Skip to content

Commit 00d7b16

Browse files
committed
add public page with ssr
1 parent ddb3afa commit 00d7b16

File tree

25 files changed

+216
-98
lines changed

25 files changed

+216
-98
lines changed

apps/nextjs-pages/.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,6 @@ yarn-error.log*
3838
# local
3939
mocked-db.json
4040

41-
/.next
41+
/.next
42+
43+
tsconfig.tsbuildinfo

apps/nextjs-pages/src/application/pages/app/discussions/__tests__/discussion.test.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,25 @@ import {
88
createDiscussion,
99
createUser,
1010
within,
11+
waitForLoadingToFinish,
1112
} from '@/testing/test-utils';
1213

13-
import { Discussion } from '../discussion';
14+
import { DiscussionPage } from '../discussion';
1415

1516
const renderDiscussion = async () => {
1617
const fakeUser = await createUser();
1718
const fakeDiscussion = await createDiscussion({ teamId: fakeUser.teamId });
1819

1920
mockRouter.query = { discussionId: fakeDiscussion.id };
2021

21-
const utils = await renderApp(<Discussion />, {
22+
const utils = await renderApp(<DiscussionPage />, {
2223
user: fakeUser,
2324
path: `/app/discussions/:discussionId`,
2425
url: `/app/discussions/${fakeDiscussion.id}`,
2526
});
2627

28+
await waitForLoadingToFinish();
29+
2730
await screen.findByText(fakeDiscussion.title);
2831

2932
return {

apps/nextjs-pages/src/application/pages/app/discussions/__tests__/discussions.test.tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
screen,
77
userEvent,
88
waitFor,
9+
waitForLoadingToFinish,
910
within,
1011
} from '@/testing/test-utils';
1112
import { formatDate } from '@/utils/format';
@@ -24,14 +25,9 @@ test(
2425
'should create, render and delete discussions',
2526
{ timeout: 10000 },
2627
async () => {
27-
await renderApp(
28-
<DiscussionsPage
29-
dehydratedState={{
30-
mutations: [],
31-
queries: [],
32-
}}
33-
/>,
34-
);
28+
await renderApp(<DiscussionsPage />);
29+
30+
await waitForLoadingToFinish();
3531

3632
const newDiscussion = createDiscussion();
3733

apps/nextjs-pages/src/application/pages/app/discussions/discussion.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export const getServerSideProps = (async ({ query, req }) => {
4141
};
4242
}) satisfies GetServerSideProps<DiscussionPageProps>;
4343

44-
export const Discussion = () => {
44+
export const DiscussionPage = () => {
4545
const router = useRouter();
4646
const discussionId = router.query.discussionId as string;
4747

@@ -77,18 +77,18 @@ export const Discussion = () => {
7777
);
7878
};
7979

80-
const DiscussionPage = ({
80+
DiscussionPage.getLayout = (page: ReactElement) => {
81+
return <DashboardLayout>{page}</DashboardLayout>;
82+
};
83+
84+
export default DiscussionPage;
85+
86+
export const PublicDiscussionPage = ({
8187
dehydratedState,
8288
}: InferGetServerSidePropsType<typeof getServerSideProps>) => {
8389
return (
8490
<HydrationBoundary state={dehydratedState}>
85-
<Discussion />
91+
<DiscussionPage />
8692
</HydrationBoundary>
8793
);
8894
};
89-
90-
DiscussionPage.getLayout = (page: ReactElement) => {
91-
return <DashboardLayout>{page}</DashboardLayout>;
92-
};
93-
94-
export default DiscussionPage;

apps/nextjs-pages/src/application/pages/app/discussions/discussions.tsx

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,16 @@
1-
import {
2-
HydrationBoundary,
3-
QueryClient,
4-
useQueryClient,
5-
dehydrate,
6-
} from '@tanstack/react-query';
7-
import type { InferGetServerSidePropsType, GetServerSideProps } from 'next';
1+
import { useQueryClient } from '@tanstack/react-query';
82
import { ReactElement } from 'react';
93

104
import { ContentLayout, DashboardLayout } from '@/components/layouts';
115
import { getInfiniteCommentsQueryOptions } from '@/features/comments/api/get-comments';
12-
import { getDiscussionsQueryOptions } from '@/features/discussions/api/get-discussions';
136
import { CreateDiscussion } from '@/features/discussions/components/create-discussion';
147
import { DiscussionsList } from '@/features/discussions/components/discussions-list';
158

16-
type DiscussionsPageProps = {
17-
dehydratedState?: unknown;
18-
};
19-
20-
export const getServerSideProps = (async ({ query, req }) => {
21-
const queryClient = new QueryClient();
22-
const page = Number(query.page || 1);
23-
const cookie = req.headers.cookie;
24-
25-
await queryClient.prefetchQuery(getDiscussionsQueryOptions({ page, cookie }));
26-
27-
return {
28-
props: {
29-
dehydratedState: dehydrate(queryClient),
30-
},
31-
};
32-
}) satisfies GetServerSideProps<DiscussionsPageProps>;
33-
34-
const DiscussionsPage = ({
35-
dehydratedState,
36-
}: InferGetServerSidePropsType<typeof getServerSideProps>) => {
9+
const DiscussionsPage = () => {
3710
const queryClient = useQueryClient();
3811

3912
return (
40-
<HydrationBoundary state={dehydratedState}>
13+
<>
4114
<div className="flex justify-end">
4215
<CreateDiscussion />
4316
</div>
@@ -51,7 +24,7 @@ const DiscussionsPage = ({
5124
}}
5225
/>
5326
</div>
54-
</HydrationBoundary>
27+
</>
5528
);
5629
};
5730

apps/nextjs-pages/src/components/layouts/dashboard-layout.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { ErrorBoundary } from 'react-error-boundary';
77
import { Button } from '@/components/ui/button';
88
import { Drawer, DrawerContent, DrawerTrigger } from '@/components/ui/drawer';
99
import { Spinner } from '@/components/ui/spinner';
10-
import { useLogout } from '@/lib/auth';
10+
import { AuthLoader, useLogout } from '@/lib/auth';
1111
import { ROLES, useAuthorization } from '@/lib/authorization';
1212
import { cn } from '@/utils/cn';
1313

@@ -235,7 +235,15 @@ export const DashboardLayout = ({
235235
key={router.pathname}
236236
fallback={<div>Something went wrong!</div>}
237237
>
238-
{children}
238+
<AuthLoader
239+
renderLoading={() => (
240+
<div className="flex size-full items-center justify-center">
241+
<Spinner size="xl" />
242+
</div>
243+
)}
244+
>
245+
{children}
246+
</AuthLoader>
239247
</ErrorBoundary>
240248
</Suspense>
241249
</Layout>

apps/nextjs-pages/src/components/ui/link/link.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { cn } from '@/utils/cn';
55
export type LinkProps = {
66
className?: string;
77
children: React.ReactNode;
8+
target?: string;
89
} & NextLinkProps;
910

1011
export const Link = ({ className, children, href, ...props }: LinkProps) => {

apps/nextjs-pages/src/features/comments/components/comments-list.tsx

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ArchiveX } from 'lucide-react';
2+
import { usePathname } from 'next/navigation';
23

34
import { Button } from '@/components/ui/button';
45
import { MDPreview } from '@/components/ui/md-preview';
@@ -19,6 +20,8 @@ type CommentsListProps = {
1920
export const CommentsList = ({ discussionId }: CommentsListProps) => {
2021
const user = useUser();
2122
const commentsQuery = useInfiniteComments({ discussionId });
23+
const pathname = usePathname();
24+
const isPublicView = pathname?.startsWith?.('/public/');
2225

2326
if (commentsQuery.isLoading) {
2427
return (
@@ -51,28 +54,29 @@ export const CommentsList = ({ discussionId }: CommentsListProps) => {
5154
key={comment.id || index}
5255
className="w-full bg-white p-4 shadow-sm"
5356
>
54-
<Authorization
55-
policyCheck={POLICIES['comment:delete'](
56-
user.data as User,
57-
comment,
58-
)}
59-
>
60-
<div className="flex justify-between">
61-
<div>
62-
<span className="text-xs font-semibold">
63-
{formatDate(comment.createdAt)}
57+
<div className="flex justify-between">
58+
<div>
59+
<span className="text-xs font-semibold">
60+
{formatDate(comment.createdAt)}
61+
</span>
62+
{comment.author && (
63+
<span className="text-xs font-bold">
64+
{' '}
65+
by {comment.author.firstName} {comment.author.lastName}
6466
</span>
65-
{comment.author && (
66-
<span className="text-xs font-bold">
67-
{' '}
68-
by {comment.author.firstName} {comment.author.lastName}
69-
</span>
70-
)}
71-
</div>
72-
<DeleteComment discussionId={discussionId} id={comment.id} />
67+
)}
7368
</div>
74-
</Authorization>
75-
69+
{!isPublicView && (
70+
<Authorization
71+
policyCheck={POLICIES['comment:delete'](
72+
user.data as User,
73+
comment,
74+
)}
75+
>
76+
<DeleteComment discussionId={discussionId} id={comment.id} />
77+
</Authorization>
78+
)}
79+
</div>
7680
<MDPreview value={comment.body} />
7781
</li>
7882
))}

apps/nextjs-pages/src/features/comments/components/comments.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { usePathname } from 'next/navigation';
2+
13
import { CommentsList } from './comments-list';
24
import { CreateComment } from './create-comment';
35

@@ -6,11 +8,13 @@ type CommentsProps = {
68
};
79

810
export const Comments = ({ discussionId }: CommentsProps) => {
11+
const pathname = usePathname();
12+
const isPublicView = pathname?.startsWith?.('/public/');
913
return (
1014
<div>
1115
<div className="mb-4 flex items-center justify-between">
1216
<h3 className="text-xl font-bold">Comments:</h3>
13-
<CreateComment discussionId={discussionId} />
17+
{!isPublicView && <CreateComment discussionId={discussionId} />}
1418
</div>
1519
<CommentsList discussionId={discussionId} />
1620
</div>

apps/nextjs-pages/src/features/discussions/api/create-discussion.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { getDiscussionsQueryOptions } from './get-discussions';
1010
export const createDiscussionInputSchema = z.object({
1111
title: z.string().min(1, 'Required'),
1212
body: z.string().min(1, 'Required'),
13+
public: z.boolean(),
1314
});
1415

1516
export type CreateDiscussionInput = z.infer<typeof createDiscussionInputSchema>;

0 commit comments

Comments
 (0)