Skip to content

Commit

Permalink
feat(user): add tabs to user page
Browse files Browse the repository at this point in the history
  • Loading branch information
ErickCReis committed Dec 21, 2023
1 parent 41c940e commit 22d6adb
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 148 deletions.
Original file line number Diff line number Diff line change
@@ -1,24 +1,41 @@
import { useRouter } from 'next/router';
import { getStaticPropsRevalidate } from 'next-swr';

import { ContentList, DefaultLayout } from '@/TabNewsUI';
import { ContentList, DefaultLayout, UserHeader } from '@/TabNewsUI';
import { FaUser } from '@/TabNewsUI/icons';
import { NotFoundError } from 'errors';
import authorization from 'models/authorization.js';
import content from 'models/content.js';
import removeMarkdown from 'models/remove-markdown.js';
import user from 'models/user.js';
import validator from 'models/validator.js';
import { useUser } from 'pages/interface';

export default function Home({ contentListFound, pagination, username }) {
const { push } = useRouter();
const { user, isLoading } = useUser();
const isAuthenticatedUser = user && user.username === username;

return (
<>
<DefaultLayout metadata={{ title: `Página ${pagination.currentPage} · ${username}` }}>
<ContentList
contentList={contentListFound}
pagination={pagination}
paginationBasePath={`/${username}/pagina`}
/>
</DefaultLayout>
</>
<DefaultLayout metadata={{ title: `Publicações · Página ${pagination.currentPage} · ${username}` }}>
<UserHeader username={username} conteudosCount={pagination.totalRows} />

<ContentList
contentList={contentListFound}
pagination={pagination}
paginationBasePath={`/${username}/conteudos`}
emptyStateProps={{
isLoading: isLoading,
title: 'Nenhuma publicação encontrada',
description: `${isAuthenticatedUser ? 'Você' : username} ainda não fez nenhuma publicação.`,
icon: FaUser,
action: isAuthenticatedUser && {
text: 'Publicar conteúdo',
onClick: () => push('/publicar'),
},
}}
/>
</DefaultLayout>
);
}

Expand Down Expand Up @@ -55,6 +72,7 @@ export const getStaticProps = getStaticPropsRevalidate(async (context) => {
results = await content.findWithStrategy({
strategy: 'new',
where: {
parent_id: null,
owner_id: secureUserFound.id,
status: 'published',
},
Expand Down
204 changes: 66 additions & 138 deletions pages/[username]/index.public.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,44 @@
import { useRouter } from 'next/router';
import { getStaticPropsRevalidate } from 'next-swr';
import { useState } from 'react';
import useSWR from 'swr';

import {
ActionList,
ActionMenu,
Box,
ContentList,
Button,
DefaultLayout,
Flash,
IconButton,
Label,
LabelGroup,
NavItem,
NavList,
Pagehead,
Link,
PastTime,
TabCashCount,
TabCoinCount,
Text,
useConfirm,
UserHeader,
Viewer,
} from '@/TabNewsUI';
import { CircleSlashIcon, FaUser, GearIcon, KebabHorizontalIcon } from '@/TabNewsUI/icons';
import { CircleSlashIcon, GearIcon } from '@/TabNewsUI/icons';
import { NotFoundError } from 'errors';
import authorization from 'models/authorization.js';
import content from 'models/content.js';
import removeMarkdown from 'models/remove-markdown.js';
import user from 'models/user.js';
import validator from 'models/validator.js';
import { useUser } from 'pages/interface';

export default function Home({ contentListFound, pagination, userFound: userFoundFallback }) {
export default function Home({ userFound: userFoundFallback }) {
const { data: userFound, mutate: userFoundMutate } = useSWR(`/api/v1/users/${userFoundFallback.username}`, {
fallbackData: userFoundFallback,
revalidateOnMount: false,
});

const { user, isLoading } = useUser();
const { push } = useRouter();
const { user } = useUser();
const confirm = useConfirm();
const [globalErrorMessage, setGlobalErrorMessage] = useState(false);

const isAuthenticatedUser = user && user.username === userFound.username;
const canNuke =
!isAuthenticatedUser && user?.features?.includes('ban:user') && !userFound?.features?.includes('nuked');
const canUpdate = isAuthenticatedUser && user?.features?.includes('update:user');

async function handleClickNuke() {
setGlobalErrorMessage(null);
Expand Down Expand Up @@ -90,115 +85,73 @@ export default function Home({ contentListFound, pagination, userFound: userFoun
return;
}

function OptionsMenu() {
const canNuke =
!isAuthenticatedUser && user?.features?.includes('ban:user') && !userFound?.features?.includes('nuked');
const canUpdate = isAuthenticatedUser && user?.features?.includes('update:user');
if (!canNuke && !canUpdate) {
return null;
}

return (
<ActionMenu>
<ActionMenu.Anchor>
<IconButton
sx={{ ml: 'auto', px: 1, alignSelf: 'center' }}
size="small"
icon={KebabHorizontalIcon}
aria-label="Editar usuário"
/>
</ActionMenu.Anchor>
<ActionMenu.Overlay>
<ActionList>
{canUpdate && (
<NavItem href="/perfil">
<NavList.LeadingVisual>
<GearIcon />
</NavList.LeadingVisual>
Editar perfil
</NavItem>
)}
{canNuke && (
<ActionList.Item variant="danger" onClick={handleClickNuke}>
<ActionList.LeadingVisual>
<CircleSlashIcon />
</ActionList.LeadingVisual>
Nuke
</ActionList.Item>
)}
</ActionList>
</ActionMenu.Overlay>
</ActionMenu>
);
}

function UserFeatures() {
if (!userFound?.features?.length) return null;

return (
<LabelGroup sx={{ display: 'flex', alignSelf: 'center', mt: 1, mr: 2 }}>
<LabelGroup sx={{ display: 'flex' }}>
{userFound.features.includes('nuked') && <Label variant="danger">nuked</Label>}
</LabelGroup>
);
}

return (
<>
<DefaultLayout metadata={{ title: `${userFound.username}` }}>
{globalErrorMessage && (
<Flash variant="danger" sx={{ width: '100%', mb: 4 }}>
{globalErrorMessage}
</Flash>
)}

<Pagehead sx={{ width: '100%', display: 'flex', mt: 0, pt: 0, pb: 3, mb: 3 }}>
<Box sx={{ display: 'flex', alignItems: 'baseline', wordBreak: 'break-word', flexWrap: 'wrap' }}>
<Text sx={{ margin: 0, pr: 2 }} as="h1">
{userFound.username}
</Text>
<UserFeatures />
<Box sx={{ display: 'flex' }}>
<TabCoinCount amount={userFound.tabcoins} direction="n" sx={{ pr: 1 }} />
<TabCashCount amount={userFound.tabcash} direction="n" sx={{ pr: 2 }} />
{' · '}
<PastTime date={userFound.created_at} formatText={(date) => `Membro há ${date}.`} sx={{ pl: 2 }} />
</Box>
</Box>
{OptionsMenu()}
</Pagehead>

{userFound.description && (
<Box
sx={{
borderWidth: 1,
borderStyle: 'solid',
borderColor: 'border.default',
borderRadius: '6px',
width: '100%',
p: 3,
mb: 3,
}}>
<Viewer value={userFound.description} />
</Box>
)}

<ContentList
contentList={contentListFound}
pagination={pagination}
paginationBasePath={`/${userFound.username}/pagina`}
emptyStateProps={{
isLoading: isLoading,
title: 'Nenhum conteúdo encontrado',
description: `${isAuthenticatedUser ? 'Você' : userFound.username} ainda não fez nenhuma publicação.`,
icon: FaUser,
action: isAuthenticatedUser && {
text: 'Publicar conteúdo',
onClick: () => push('/publicar'),
},
}}
/>
</DefaultLayout>
</>
<DefaultLayout metadata={{ title: `${userFound.username}` }}>
{globalErrorMessage && (
<Flash variant="danger" sx={{ width: '100%', mb: 4 }}>
{globalErrorMessage}
</Flash>
)}

<UserHeader username={userFound.username} />

<Box
sx={{
width: '100%',
display: 'flex',
alignItems: 'center',
wordBreak: 'break-word',
flexWrap: 'wrap',
gap: 2,
mb: 3,
}}>
<Box sx={{ flex: 1, display: 'flex', justifyContent: 'start' }}>
<TabCoinCount amount={userFound.tabcoins} direction="n" sx={{ pr: 1 }} />
<TabCashCount amount={userFound.tabcash} direction="n" sx={{ pr: 2 }} />
{' · '}
<PastTime date={userFound.created_at} formatText={(date) => `Membro há ${date}`} sx={{ pl: 2 }} />
</Box>

<Box sx={{ flexGrow: 0, display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 2 }}>
<UserFeatures />
{canUpdate && (
<Button leadingIcon={GearIcon} href="/perfil" as={Link}>
Editar
</Button>
)}
{canNuke && (
<Button variant="danger" leadingIcon={CircleSlashIcon} onClick={handleClickNuke}>
Nuke
</Button>
)}
</Box>
</Box>

{userFound.description && (
<Box
sx={{
borderWidth: 1,
borderStyle: 'solid',
borderColor: 'border.default',
borderRadius: '6px',
width: '100%',
p: 3,
mb: 3,
}}>
<Viewer value={userFound.description} />
</Box>
)}
</DefaultLayout>
);
}

Expand Down Expand Up @@ -245,23 +198,12 @@ export const getStaticProps = getStaticPropsRevalidate(async (context) => {
};
}

let results;
let secureUserFound;

try {
const userFound = await user.findOneByUsername(context.params.username, { withBalance: true });

secureUserFound = authorization.filterOutput(userTryingToGet, 'read:user', userFound);

results = await content.findWithStrategy({
strategy: 'new',
where: {
owner_id: secureUserFound.id,
status: 'published',
},
page: context.params.page,
per_page: context.params.per_page,
});
} catch (error) {
// `user` model will throw a `NotFoundError` if the user is not found.
if (error instanceof NotFoundError) {
Expand All @@ -274,22 +216,8 @@ export const getStaticProps = getStaticPropsRevalidate(async (context) => {
throw error;
}

const contentListFound = results.rows;

const secureContentListFound = authorization.filterOutput(userTryingToGet, 'read:content:list', contentListFound);

for (const content of secureContentListFound) {
if (content.parent_id) {
content.body = removeMarkdown(content.body, { maxLength: 255 });
} else {
delete content.body;
}
}

return {
props: {
contentListFound: JSON.parse(JSON.stringify(secureContentListFound)),
pagination: results.pagination,
userFound: JSON.parse(JSON.stringify(secureUserFound)),
},

Expand Down
Loading

0 comments on commit 22d6adb

Please sign in to comment.