diff --git a/nextjs-13/src/app/app.tsx b/nextjs-13/src/app/app.tsx index ba0d86cc..671d2527 100644 --- a/nextjs-13/src/app/app.tsx +++ b/nextjs-13/src/app/app.tsx @@ -6,6 +6,7 @@ import { usePathname } from 'next/navigation'; import { ApiMeResponse } from './api/v1/me/route'; import AppLayout from '../components/AppLayout'; import AuthLayout from '../components/AuthLayout'; +import PublicLayout from '../components/PublicLayout'; import '../stylesheets/application.scss'; import { UserState, @@ -45,6 +46,10 @@ export default function RootLayout({ return {children}; } + if (pathname.includes('/newsletter')) { + return {children}; + } + return ( {children} diff --git a/nextjs-13/src/app/newsletter/[id]/page.test.tsx b/nextjs-13/src/app/newsletter/[id]/page.test.tsx new file mode 100644 index 00000000..0d6eaa47 --- /dev/null +++ b/nextjs-13/src/app/newsletter/[id]/page.test.tsx @@ -0,0 +1,67 @@ +import React from 'react'; + +import { render, screen, waitFor } from '@testing-library/react'; +import { useParams } from 'next/navigation'; + +import requestManager from 'lib/request/manager'; + +import ViewNewsletter from './page'; + +jest.mock('next-auth/react'); +jest.mock('next/navigation'); +jest.mock('lib/request/manager'); + +jest.mock('react-spinners', () => ({ + ClipLoader: () =>
Loading...
, +})); + +describe('ViewNewsletter', () => { + beforeEach(() => { + requestManager.mockResolvedValue({ record: {} }); + useParams.mockReturnValue({ id: 1 }); + }); + + it('renders component', async () => { + render(); + + await waitFor(() => { + expect(screen.getByTestId('view-newsletter')).toBeInTheDocument(); + }); + }); + + describe('given fetching data', () => { + beforeEach(() => { + requestManager.mockImplementation(() => new Promise(() => [])); + }); + + it('renders ClipLoader', async () => { + render(); + + expect(screen.getByTestId('clip-loader')).toBeInTheDocument(); + }); + + it('does NOT render NewsletterDetail', async () => { + render(); + + expect(screen.queryByTestId('newsletter')).not.toBeInTheDocument(); + }); + }); + + describe('given NOT fetching data', () => { + it('does NOT render ClipLoader', async () => { + render(); + + await waitFor(() => { + expect(screen.queryByTestId('clip-loader')).not.toBeInTheDocument(); + }); + }); + + it('renders ListNewsletter', async () => { + render(); + + await waitFor(() => { + expect(screen.getByTestId('newsletter')).toBeInTheDocument(); + }); + }); + }); +}); diff --git a/nextjs-13/src/app/newsletter/[id]/page.tsx b/nextjs-13/src/app/newsletter/[id]/page.tsx new file mode 100644 index 00000000..73fc4f75 --- /dev/null +++ b/nextjs-13/src/app/newsletter/[id]/page.tsx @@ -0,0 +1,53 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { ClipLoader } from 'react-spinners'; + +import { useParams, redirect } from 'next/navigation'; + +import NewsletterDetail from '@components/NewsletterDetail'; +import requestManager from 'lib/request/manager'; + +const ViewNewsletter = () => { + const [record, setRecord] = useState([]); + const [hasError, setHasError] = useState(false); + const [isLoading, setIsLoading] = useState(false); + + const params = useParams(); + const id = params.id; + + const getNewletter = async () => { + setIsLoading(true); + + try { + const response = await requestManager('GET', `v1/newsletter/${id}`); + + setIsLoading(false); + setRecord(response.record); + } catch (error) { + setHasError(true); + setIsLoading(false); + } + }; + + useEffect(() => { + getNewletter(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + if (hasError) redirect('/auth/sign-in'); + }, [hasError]); + + return ( +
+ {isLoading ? ( + + ) : ( + + )} +
+ ); +}; + +export default ViewNewsletter; diff --git a/nextjs-13/src/app/send/page.tsx b/nextjs-13/src/app/send/page.tsx index 64d1288d..39156a78 100644 --- a/nextjs-13/src/app/send/page.tsx +++ b/nextjs-13/src/app/send/page.tsx @@ -68,7 +68,7 @@ const SendNewsletter = () => {

Your Newsletters

{isLoading ? ( - + ) : (