diff --git a/src/components/navbar/index.tsx b/src/components/navbar/index.tsx index 6732345..2f29079 100644 --- a/src/components/navbar/index.tsx +++ b/src/components/navbar/index.tsx @@ -6,7 +6,7 @@ import Overlay from 'react-bootstrap/Overlay'; import Tooltip from 'react-bootstrap/Tooltip'; import profile from "../image/107161_circle_github_icon.png"; import '../../styles/sass/main.scss' -import { useNavigate } from "react-router-dom"; +import { useNavigate,Link } from "react-router-dom"; export const Navbar = () => { const {userData} = useSelector((state) => state.user) @@ -36,13 +36,13 @@ export const Navbar = () => { {(props) => ( -
Your Profile
+
)}
diff --git a/src/containers/profile/index.tsx b/src/containers/profile/index.tsx new file mode 100644 index 0000000..9ac137f --- /dev/null +++ b/src/containers/profile/index.tsx @@ -0,0 +1,161 @@ +import './style.scss'; +import Container from 'react-bootstrap/Container'; +import 'bootstrap/dist/css/bootstrap.css'; +import Row from 'react-bootstrap/Row'; +import Col from 'react-bootstrap/Col'; +import 'bootstrap/dist/css/bootstrap.css'; +import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; +import ReactPaginate from 'react-paginate'; +import profile from "..//../component/image/PngItem_1280311.png"; +import { useSelector, useDispatch } from '../../store/index'; +import { useEffect, useState } from 'react'; +import Popover from 'react-bootstrap/Popover' +import Button from 'react-bootstrap/Button'; +import { useParams, Link } from 'react-router-dom'; +import axios from 'axios'; +import '../../styles/sass/main.scss' + +export const ProfilePage = () => { + const {token, userData} = useSelector((state) => state.user) + const [userInfo,setUserInfo] = useState(); + const [followersInfo,setFollowersInfo] = useState([]); + const [followingInfo,setFollowingInfo] = useState([]); + const { profileId } = useParams(); + const [currentPageForFollowers, setCurrentPageForFollowers] = useState(0); + const [currentPageForFollowing, setCurrentPageForFollowing] = useState(0); + const [loading, setLoading] = useState(false); + const [isFollowing, setIsFollowing] = useState(true); + const [ownProfile, setOwnProfile] = useState(false); + const PER_PAGE = 4; + + const fetchUserInfo = async() =>{ + setLoading(true); + if(userData?.login!==profileId) { + setOwnProfile(false); + isFollowingUser(); + } + else { + setOwnProfile(true); + } + const response = await axios.get('https://api.github.com/users/'+profileId); + setUserInfo(response.data); + console.log(response.data); + } + + useEffect(() =>{ + fetchUserInfo(); + },[profileId]); + + const fetchFollowersInfo = async() =>{ + const response = await axios.get('https://api.github.com/users/'+profileId+"/followers?page="+(currentPageForFollowers+1)+"&per_page="+PER_PAGE); + setFollowersInfo(response.data); + } + + const fetchFollowingInfo = async() =>{ + const response = await axios.get('https://api.github.com/users/'+profileId+"/following?page="+(currentPageForFollowing+1)+"&per_page="+PER_PAGE); + setFollowingInfo(response.data); + } + + useEffect(() =>{ + fetchFollowersInfo(); + },[profileId,currentPageForFollowers]); + + useEffect(() =>{ + fetchFollowingInfo(); + },[profileId,currentPageForFollowing]); + + function handlePageClickForFollowers({selected} : {selected:number}) { + setCurrentPageForFollowers(selected) + } + + function handlePageClickForFollowing({selected} : {selected:number}) { + setCurrentPageForFollowing(selected) + } + + const isFollowingUser = async() =>{ + try { + await axios({ + method: 'get', + url: 'https://api.github.com/user/following/'+profileId, + headers: { + Authorization: 'Bearer ' + token + } + }) + setIsFollowing(true); + } catch(error:any) { + setIsFollowing(false); + } + } + const followUser = async() =>{ + await axios({ + method: 'put', + url: 'https://api.github.com/user/following/'+profileId, + headers: { + Authorization: 'Bearer ' + token + } + }) + setIsFollowing(true); + } + + return( +
+ {loading===false? +
+
+
: +
+
+ +

{{userInfo}.userInfo?.name}

+

{profileId}

+ {!ownProfile&&
+ {isFollowing===true? + : + () + } +
} +

{{userInfo}.userInfo?.followers} Followers

+

{{userInfo}.userInfo?.following} Following

+
+
+

Followers

+
+ {followersInfo.slice(0, PER_PAGE).map((res, index) => <>

{res?.login}

)} +
+
+ "} + pageCount = {Math.ceil({userInfo}.userInfo?.followers / PER_PAGE)} + onPageChange = {handlePageClickForFollowers} + containerClassName = {"pagination"} + previousLinkClassName = {"pagination__link"} + nextClassName = {"pagination__link"} + disabledClassName = {"pagination__link--disabled"} + activeClassName = {"pagination__link--active"} + /> +
+

Following

+
+ {followingInfo.slice(0,PER_PAGE).map((res, index) => <>

{res?.login}

)} +
+
+ "} + pageCount = {Math.ceil({userInfo}.userInfo?.following / PER_PAGE)} + onPageChange = {handlePageClickForFollowing} + containerClassName = {"pagination"} + previousLinkClassName = {"pagination__link"} + nextClassName = {"pagination__link"} + disabledClassName = {"pagination__link--disabled"} + activeClassName = {"pagination__link--active"} + /> +
+
+
} +
+ ) +} diff --git a/src/containers/search/index.tsx b/src/containers/search/index.tsx index a3b7694..285eb9a 100644 --- a/src/containers/search/index.tsx +++ b/src/containers/search/index.tsx @@ -1,16 +1,17 @@ -import { useParams } from 'react-router-dom'; +import { useParams, Link } from 'react-router-dom'; import { useEffect, useState } from 'react'; import ReactPaginate from 'react-paginate'; import React, { Component } from 'react'; +import '../../styles/sass/main.scss' import axios from 'axios'; -import './style.scss'; + export const SearchPage = () => { const [users,setUsers] = useState(); const { searchId } = useParams(); const [currentPage, setCurrentPage] = useState(0); - let pageCount; + const PER_PAGE = 10; const fetchData = async() =>{ const response = await axios.get('https://api.github.com/search/users?per_page=10&page='+(currentPage+1)+'&q='+searchId) setUsers(response.data); @@ -21,24 +22,20 @@ export const SearchPage = () => { function handlePageClick({selected} : {selected:number}) { setCurrentPage(selected) - setUsers(undefined) - } - if (users!=undefined){ - pageCount = users.total_count; } - + const pageCount = Math.ceil(users?.total_count/PER_PAGE); return(
{users?.items?.map((res:any, index:any) => - <>
+ <>

{res.login}

)}
"} - pageCount = {pageCount} + pageCount = {pageCount===undefined?0:pageCount} onPageChange = {handlePageClick} containerClassName = {"pagination"} previousLinkClassName = {"pagination__link"} diff --git a/src/routes/routesConfig.tsx b/src/routes/routesConfig.tsx index 61a3d8f..a53467d 100644 --- a/src/routes/routesConfig.tsx +++ b/src/routes/routesConfig.tsx @@ -1,8 +1,7 @@ import { LoginPage } from '../containers/login' import { HomePage } from '../containers/home' import { SearchPage } from '../containers/search' -import React, { Component } from 'react'; - +import { ProfilePage } from '../containers/profile' const routesConfig: RouteConfig[] = [ { path: '/', @@ -14,6 +13,11 @@ const routesConfig: RouteConfig[] = [ component: , private: true, }, + { + path: '/profile/:profileId', + component: , + private: true, + }, { path: '/login', component: , diff --git a/src/styles/sass/components/_navbar.scss b/src/styles/sass/components/_navbar.scss index 271b8f3..5b65465 100644 --- a/src/styles/sass/components/_navbar.scss +++ b/src/styles/sass/components/_navbar.scss @@ -40,4 +40,8 @@ nav { box-shadow: none; } } - \ No newline at end of file +.your-profile { + background-color: #003865; + border: none; + color: white; +} \ No newline at end of file diff --git a/src/styles/sass/main.scss b/src/styles/sass/main.scss index 475da9e..6775ac2 100644 --- a/src/styles/sass/main.scss +++ b/src/styles/sass/main.scss @@ -3,3 +3,4 @@ @import 'pages/login'; @import 'components/navbar'; @import 'pages/search'; +@import 'pages/profile'; diff --git a/src/styles/sass/pages/_profile.scss b/src/styles/sass/pages/_profile.scss new file mode 100644 index 0000000..c41a717 --- /dev/null +++ b/src/styles/sass/pages/_profile.scss @@ -0,0 +1,61 @@ +.profile-section-pic { + border-radius: 50%; + height: 300px; + margin-top: 40px; + margin-left: 40px; +} +.profile-section { + display: flex; +} + +.profile-section-bio { + width: 30%; +} + +.profile-section-bio h3{ + margin-left: 80px; + margin-top: 10px; +} + +.profile-section-name { + margin-left: 80px; + margin-top: -10px; + color: grey; +} +.profile-section-follows { + margin-left: 80px; + margin-top: 10px; +} +.profile-section button { + display: block; + width: 250px; + height: 36px; + margin-left: 80px; + color: white; + background-color: #003865; +} + +.location{ + margin-left: 42px; +} + +.profile-section-followers h3 { + margin-left: 42px; +} + +@keyframes spinner { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} +.loading-spinner { + width: 50px; + height: 50px; + border: 10px solid #f3f3f3; + border-top: 10px solid #383636; + border-radius: 50%; + animation: spinner 1.5s linear infinite; +} diff --git a/src/styles/sass/pages/_search.scss b/src/styles/sass/pages/_search.scss index 9e8285c..4e1d910 100644 --- a/src/styles/sass/pages/_search.scss +++ b/src/styles/sass/pages/_search.scss @@ -37,5 +37,4 @@ background-color: transparent; border: 1px solid transparent; margin-right: 10px; - margin-bottom: 1px; }