Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"presets": [
"next/babel"
],
"plugins": [
[
"styled-components",
{
"ssr": true,
"displayName": true,
"preprocess": false
}
]
]
}
64 changes: 64 additions & 0 deletions components/Header/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import Link from "next/link";
import { Avatar, AvatarContainer, AvatarImage, AvatarInfo, ButtonLogout, HeaderContainer, LogoContainer, LogoText, NavBar, ToggleMobileContainer, ToggleMobileMenu, UserInfo, UserName, UserNickName } from "./styles";
import {FaSignOutAlt, FaBars, FaTimes} from 'react-icons/fa'
import { useState } from "react";
import MobileMenu from "../MobileMenu";
import { signOut, useSession } from "next-auth/react";
import Router from "next/router";
export default function Header({ currentPage }){
const [mobileMenuIsOpen, setMobileMenuIsOpen] = useState(false)
const {data:session, status} = useSession()

if(!session || status === "unauthenticated"){
Router.push("/")
return
}

const {user} = session


function handleMobileMenu(){
setMobileMenuIsOpen( prevState => !prevState)
}


return (
<HeaderContainer>
<MobileMenu isOpen={mobileMenuIsOpen} currentPage={currentPage}/>
<NavBar>
<LogoContainer>
<Link legacyBehavior passHref href="/">
<LogoText>
DevKut
</LogoText>
</Link>
</LogoContainer>
<ToggleMobileContainer>
<ToggleMobileMenu onClick={handleMobileMenu}>
{mobileMenuIsOpen ? (
<FaTimes/>
): (
<FaBars/>
)}
</ToggleMobileMenu>
</ToggleMobileContainer>
<AvatarContainer>
<Avatar>
<Link href="/perfil" passHref legacyBehavior>
<AvatarImage src={user.image}/>
</Link>
</Avatar>
<UserInfo>
<UserName>{user.name.split(" ").slice(0,2).join(" ")}</UserName>
<UserNickName>{user.email}</UserNickName>
</UserInfo>

<ButtonLogout onClick={ () => signOut()}>
<FaSignOutAlt/>
</ButtonLogout>

</AvatarContainer>
</NavBar>
</HeaderContainer>
)
}
141 changes: 141 additions & 0 deletions components/Header/styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import styled from "styled-components";

export const HeaderContainer = styled.header`
width: 100%;
height: 100px;
display:flex;
align-items:center;
justify-content: center;
background: ${ props => props.theme.secondary};
`

export const NavBar = styled.nav`
width: 80%;
height: 70px;
display:flex;
align-items:center;
justify-content: space-between;
`

export const LogoContainer= styled.div`
width: 100%;
max-width: 300px;
display:flex;
align-items:center;
justify-content: center;
`

export const LogoText = styled.span`
font-size: 2.4rem;
color: ${props => props.theme.primary};
font-weight: 500;
cursor: pointer;
`
export const ToggleMobileContainer = styled.div`
width: 100%;
display: none;

@media (max-width: 768px) {
& {
display: flex;
justify-content: flex-end;
}
}
`
export const ToggleMobileMenu = styled.button`
width: 40px;
height: 40px;
border-radius: 50%;
outline:none;
border:none;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
background: ${props => props.theme.isDark ? props.theme.black : props.theme.lightGray};
color: ${props => props.theme.isDark ? props.theme.lightGray : props.theme.lightBlack};
`

export const AvatarContainer = styled.nav`
width: 100%;
max-width: 400px;
height: 50px;
display:flex;
align-items:center;
justify-content: flex-end;
gap: 1rem;

@media (max-width: 768px) {
& {
display:none;
}
}
`

export const Avatar = styled.nav`
width: 100%;
max-width: 55px;
height: 55px;
border-radius: 50%;
/* background: ${props => props.theme.primary}; */
display: flex;
align-items: center;
justify-content: center;

`

export const AvatarImage = styled.img`
width: 50px;
height: 50px;
border-radius: 50%;
object-fit: contain;
cursor: pointer;
transition: all 200ms ease-in-out;

&:hover{
border: 0.15rem solid ${props => props.theme.primary};
opacity: 0.8;
}
`


export const UserInfo = styled.div`
display: flex;
flex-direction: column;
`

export const UserName = styled.span`
color: ${props => props.theme.isDark ? props.theme.white : props.theme.black};
font-size: 1.2rem;
font-weight: 400;
`
export const UserNickName = styled.span`
color: ${props => props.theme.isDark ? props.theme.gray : props.theme.black};
font-size: 0.85rem;
font-weight: 200;
`


export const ButtonLogout = styled.button`
width: 100%;
max-width: 40px;
height: 40px;
border-radius: 50%;
padding: 0.2rem;
margin-left: 1rem;
display: flex;
align-items: center;
justify-content: center;
border: none;
font-size: 1.2rem;
background: ${props => props.theme.isDark ? props.theme.black : props.theme.secondary};
color: ${props => props.theme.isDark ? props.theme.white : props.theme.black};
cursor: pointer;

&:hover{
opacity: 0.8;
}

`


14 changes: 14 additions & 0 deletions components/Icon/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export default function Icon({ index, isActive = false, menuItems }){
const configIcons = {
size: 22,
color:"#cbcad2",
fill: "#cbcad2"
}

const Icon = menuItems[index].icon

configIcons.color = isActive ? '#e22b8d' : configIcons.color
configIcons.fill = isActive ? '#e22b8d' : configIcons.color

return <Icon {...configIcons} ></Icon>
}
123 changes: 123 additions & 0 deletions components/ListUsers/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import Link from "next/link";
import { Alert, Avatar, FollowButton, FollowUser, Followers, LisUsersContainer, ListUsersItem, Nickname, TextBold, Title, UserAvatar, UserDescription, UserInfo, Username } from "./styles";
import { FaUsers } from "react-icons/fa"
import React, { useContext, useEffect, useRef, useState } from "react";
import { ThemeContext } from "../../context/ThemeContext";
import api from "../../services/api";
import { useSession } from "next-auth/react";
import Loading from "../Loading";
import menuItems from "../../utils/menuItems";

const iconColor = {
dark: '#e7e7e7',
light: '#252525'
}
const PER_PAGE = 15
export default function ListUsers(){
const {theme} = useContext(ThemeContext)
const [users, setUsers] = useState([])
const [currentPage, setCurrentPage] = useState(1)
const [isLoading, setIsLoading] = useState(true)
const [showFooterLoader, setFooterLoader] = useState(false)
const refLoader = useRef()
const {data:session} = useSession()

async function getUserProfile(user){
return await api.get(`users/${user}`, {
headers: {
"Authorization": `Bearer ${session.accessToken}`,
"Accept": "application/vnd.github+json"
}
})
}


function getUsers(){
api.get(`user/followers?per_page=${PER_PAGE}&page=${currentPage}&order=DESC`, {
headers: {
"Authorization": `Bearer ${session.accessToken}`,
"Accept": "application/vnd.github+json"
}
}).then(async (res) => {
const { data } = res
if(data.length == 0){
setFooterLoader(false)
return
}

data.forEach( async (user) => {
const {data } = await getUserProfile(user.login)
setUsers( prevUsers => [...prevUsers, data])
setIsLoading(false)
setFooterLoader(true)
})
})
}


useEffect(() => {
getUsers()
}, [currentPage])


useEffect(() => {
const intersectionObserver = new IntersectionObserver(entries => {
if (entries.some(entry => entry.isIntersecting)) {
if(users.length == 0) return
setCurrentPage((currentValue) => currentValue + 1);
}
})
if(refLoader.current){
intersectionObserver.observe(refLoader.current);
}
return () => intersectionObserver.disconnect();
}, [refLoader.current]);


if(isLoading){
return <Loading/>
}

return (
<LisUsersContainer>
<Title>Seguidores</Title>
{users.length === 0 && !isLoading && (
<Alert>
<p>Nenhum resultado encontrado...</p>
</Alert>
)}
{users.map( (user, index) => (
<React.Fragment key={user.id}>
<ListUsersItem >
<UserInfo>
<UserAvatar>
<Avatar src={user.avatar_url}/>
</UserAvatar>
<UserDescription>
<div>
<Link href={user.html_url} passHref legacyBehavior>
<Username target="_blank">{user.name || user.login}</Username>
</Link>
<Nickname>{user.login}</Nickname>
</div>
<div>
<FaUsers color={iconColor[theme]} size={18}/>
<Followers><TextBold>{user.followers}</TextBold> seguidores</Followers>
<Followers><TextBold>{user.following}</TextBold> seguindo</Followers>
</div>
</UserDescription>
</UserInfo>
{/* <FollowUser>
<FollowButton>Seguir</FollowButton>
</FollowUser> */}
</ListUsersItem>
</React.Fragment>
))}

{showFooterLoader && users.length > 0 && (
<Loading ref={refLoader}/>
)}

</LisUsersContainer>
)
}
Loading