Skip to content

Commit

Permalink
Merge pull request #26 from SkyLightQP/refactor/nextjs-app
Browse files Browse the repository at this point in the history
refactor: refactor nextjs to app router (app directory)
  • Loading branch information
SkyLightQP authored Nov 12, 2024
2 parents 25c79aa + eddf05d commit 3a738d1
Show file tree
Hide file tree
Showing 38 changed files with 1,617 additions and 1,892 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = {
plugins: ['react', 'react-hooks', 'prettier', '@typescript-eslint'],
plugins: ['react', 'prettier', '@typescript-eslint'],
extends: ['next', 'airbnb', 'prettier', 'plugin:@typescript-eslint/recommended'],
parser: '@typescript-eslint/parser',
globals: {
Expand All @@ -21,6 +21,7 @@ module.exports = {
'react/function-component-definition': 'off',
'react/jsx-no-useless-fragment': 'off',
'react/require-default-props': 'off',
'react/react-in-jsx-scope': 'off',

'import/extensions': 'off',
'import/no-unresolved': 'off',
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:20-alpine AS base
FROM node:22-alpine AS base

FROM base AS builder

Expand Down
2 changes: 1 addition & 1 deletion next-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
29 changes: 13 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,34 @@
},
"license": "MIT",
"dependencies": {
"@chakra-ui/react": "^2.2.1",
"@emotion/css": "^11.11.2",
"@emotion/react": "^11.1.1",
"@emotion/styled": "^11.0.0",
"@remixicon/react": "^4.2.0",
"@supabase/auth-helpers-nextjs": "^0.9.0",
"@supabase/auth-helpers-react": "^0.4.2",
"@supabase/supabase-js": "^2.39.7",
"@chakra-ui/react": "^2.10.3",
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@emotion/css": "^11.13.4",
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@remixicon/react": "^4.5.0",
"@supabase/ssr": "^0.5.1",
"@supabase/supabase-js": "^2.46.1",
"framer-motion": "^6.3.12",
"next": "^14.2.10",
"next-seo": "^6.6.0",
"next": "^15.0.2",
"react": "^18.2.0",
"react-beautiful-dnd": "^13.1.0",
"react-dom": "^18.2.0",
"react-gesture-responder": "^2.1.0",
"react-grid-dnd": "^2.1.2",
"react-hook-form": "^7.33.1",
"react-hotkeys-hook": "^3.4.6",
"react-markdown": "^8.0.5",
"sharp": "^0.33.5"
},
"devDependencies": {
"@types/node": "^20.11.24",
"@types/node": "^22.9.0",
"@types/react": "~18.0.28",
"@types/react-beautiful-dnd": "^13.1.2",
"@types/react-dom": "^18.2.19",
"@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^7.1.0",
"eslint": "^8.57.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-next": "^14.1.0",
"eslint-config-next": "^15.0.2",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
Expand Down
23 changes: 23 additions & 0 deletions src/acitons/section-data.action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use server';

import { SchemaType } from '../types/type-util';
import { createSupabaseClient } from '../utils/supabase/server';

export type SectionType = Array<
SchemaType<'sections'> & {
contents: Array<SchemaType<'contents'> & { links: SchemaType<'links'>[]; images: SchemaType<'images'>[] }>;
}
>;

export const getSectionData = async () => {
const supabase = await createSupabaseClient();
const { data, error } = await supabase
.from('sections')
.select('*, contents(*, links(*), images(*))')
.eq('contents.isHidden', false)
.order('id', { ascending: true });
return {
sections: data as SectionType,
error
};
};
55 changes: 29 additions & 26 deletions src/pages/admin/content.tsx → src/app/admin/content/page.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
/** @jsxImportSource @emotion/react */

'use client';

import styled from '@emotion/styled';
import React, { useCallback, useEffect, useState } from 'react';
import { Button, Checkbox, Input, Select, Td, Textarea, useDisclosure, useToast } from '@chakra-ui/react';
import { css } from '@emotion/react';
import { DropResult } from 'react-beautiful-dnd';
import { SubmitHandler, useForm } from 'react-hook-form';
import useUserVerify from '../../hooks/useUserVerify';
import { HugeTitle } from '../../components/Typography';
import DraggableTable from '../../components/DraggableTable';
import DeleteModal from '../../components/Dialogs/DeleteModal';
import UpdateModal from '../../components/Dialogs/UpdateModal';
import AdminLayout from '../../layouts/AdminLayout';
import LinkModal from '../../components/Dialogs/LinkModal';
import { useSupabase } from '../../utils/supabase';
import { SchemaType } from '../../types/type-util';
import { Space } from '../../components/Space';
import ImageModal from '../../components/Dialogs/ImageModal';
import { arrayMove } from '@dnd-kit/sortable';
import { DragEndEvent } from '@dnd-kit/core';
import { HugeTitle } from '../../../components/Typography';
import DraggableTable from '../../../components/DraggableTable';
import DeleteModal from '../../../components/Dialogs/DeleteModal';
import UpdateModal from '../../../components/Dialogs/UpdateModal';
import AdminLayout from '../../../layouts/AdminLayout';
import LinkModal from '../../../components/Dialogs/LinkModal';
import { SchemaType } from '../../../types/type-util';
import { Space } from '../../../components/Space';
import ImageModal from '../../../components/Dialogs/ImageModal';
import { createSupabaseClient } from '../../../utils/supabase/client';

const Header = styled.div`
display: grid;
Expand Down Expand Up @@ -48,8 +51,7 @@ const DEFAULT_VALUE: AddForm = {
isHidden: false
};

const AdminContent: React.FC = () => {
useUserVerify();
const Page: React.FC = () => {
const [data, setData] = useState<Array<SchemaType<'contents'> & { sections: SchemaType<'sections'> }>>([]);
const [section, setSection] = useState<Array<SchemaType<'sections'>>>([]);
const [isChange, setBeChange] = useState(false);
Expand All @@ -59,13 +61,13 @@ const AdminContent: React.FC = () => {
const updateDialog = useDisclosure();
const linkDialog = useDisclosure();
const imageDialog = useDisclosure();
const supabase = useSupabase();
const supabase = createSupabaseClient();
const toast = useToast({
isClosable: true,
position: 'top-left'
});

const fetchData = async () => {
const fetchData = useCallback(async () => {
const { data: response, error } = await supabase.from('contents').select('*, sections(*)');
if (error !== null) {
toast({
Expand All @@ -77,14 +79,15 @@ const AdminContent: React.FC = () => {
}
const contents = response as Array<SchemaType<'contents'> & { sections: SchemaType<'sections'> }>;
setData(contents.sort((a, b) => a.order - b.order).sort((a, b) => a.sections.order - b.sections.order));
};
}, [supabase]);

const onChangeData = (result: DropResult) => {
if (!result.destination) return;
const items = [...data];
const [reorderedItem] = items.splice(result.source.index, 1);
items.splice(result.destination.index, 0, reorderedItem);
setData(items);
const onChangeData = ({ active, over }: DragEndEvent) => {
if (!over || active.id === over.id) return;

const oldIndex = data.findIndex((item) => item.id === Number(active.id));
const newIndex = data.findIndex((item) => item.id === Number(over.id));

setData((prev) => arrayMove(prev, oldIndex, newIndex));
setBeChange(true);
};

Expand Down Expand Up @@ -123,7 +126,7 @@ const AdminContent: React.FC = () => {
.then(({ data: sections }) => {
if (sections !== null) setSection(sections);
});
}, [supabase]);
}, [fetchData, supabase]);

const SectionOptions = useCallback(
() => (
Expand Down Expand Up @@ -153,7 +156,7 @@ const AdminContent: React.FC = () => {
{...register('title', { required: true })}
/>
<Input
placeholder="부제목 (2022 / 프론트엔드)"
placeholder="부제목 (풀스택, 2024)"
background="white"
css={css`
grid-column: 4 / 6;
Expand Down Expand Up @@ -331,4 +334,4 @@ const AdminContent: React.FC = () => {
);
};

export default AdminContent;
export default Page;
18 changes: 10 additions & 8 deletions src/pages/admin/login.tsx → src/app/admin/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
'use client';

import React, { useState } from 'react';
import styled from '@emotion/styled';
import { useRouter } from 'next/router';
import { useToast } from '@chakra-ui/react';
import { SectionTitle } from '../../components/Typography';
import Colors from '../../styles/Colors';
import { useSupabase } from '../../utils/supabase';
import { Space } from '../../components/Space';
import { useRouter } from 'next/navigation';
import { SectionTitle } from '../../../components/Typography';
import Colors from '../../../styles/Colors';
import { Space } from '../../../components/Space';
import { createSupabaseClient } from '../../../utils/supabase/client';

const Container = styled.div`
min-height: 100vh;
Expand Down Expand Up @@ -45,9 +47,9 @@ const LoginButton = styled.button`
}
`;

const Login: React.FC = () => {
const Page: React.FC = () => {
const router = useRouter();
const supabase = useSupabase();
const supabase = createSupabaseClient();
const [input, setInput] = useState<{ email: string; password: string }>({
email: '',
password: ''
Expand Down Expand Up @@ -108,4 +110,4 @@ const Login: React.FC = () => {
);
};

export default Login;
export default Page;
40 changes: 21 additions & 19 deletions src/pages/admin/index.tsx → src/app/admin/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import React, { useEffect, useState } from 'react';
'use client';

import React, { useCallback, useEffect, useState } from 'react';
import styled from '@emotion/styled';
import { Button, Input, useDisclosure, useToast } from '@chakra-ui/react';
import { DropResult } from 'react-beautiful-dnd';
import { SubmitHandler, useForm } from 'react-hook-form';
import useUserVerify from '../../hooks/useUserVerify';
import { DragEndEvent } from '@dnd-kit/core';
import { arrayMove } from '@dnd-kit/sortable';
import { HugeTitle } from '../../components/Typography';
import DraggableTable from '../../components/DraggableTable';
import DeleteModal from '../../components/Dialogs/DeleteModal';
import UpdateModal from '../../components/Dialogs/UpdateModal';
import AdminLayout from '../../layouts/AdminLayout';
import { useSupabase } from '../../utils/supabase';
import { SchemaType } from '../../types/type-util';
import { Space } from '../../components/Space';
import { createSupabaseClient } from '../../utils/supabase/client';

const Header = styled.div`
display: grid;
Expand All @@ -24,21 +26,20 @@ const Footer = styled.div`
justify-content: flex-end;
`;

const Admin: React.FC = () => {
useUserVerify();
const Page: React.FC = () => {
const [data, setData] = useState<Array<SchemaType<'sections'>>>([]);
const [isChange, setBeChange] = useState(false);
const [modalData, setModalData] = useState<{ id: number; title: string }>({ id: -1, title: '' });
const { register, handleSubmit, reset } = useForm<{ title: string }>();
const deleteDialog = useDisclosure();
const updateDialog = useDisclosure();
const supabase = useSupabase();
const supabase = createSupabaseClient();
const toast = useToast({
isClosable: true,
position: 'top-left'
});

const fetchData = async () => {
const fetchData = useCallback(async () => {
const { data: sections, error } = await supabase.from('sections').select('*');
if (sections === null || error !== null) {
toast({
Expand All @@ -49,11 +50,11 @@ const Admin: React.FC = () => {
return;
}
setData(sections.sort((a, b) => a.order - b.order));
};
}, [supabase]);

useEffect(() => {
fetchData().then();
}, []);
}, [fetchData]);

const onAddClick: SubmitHandler<{ title: string }> = async (values) => {
if (values.title.trim() === '') return;
Expand All @@ -62,12 +63,13 @@ const Admin: React.FC = () => {
reset({ title: '' });
};

const onChangeData = (result: DropResult) => {
if (!result.destination) return;
const items = [...data];
const [reorderedItem] = items.splice(result.source.index, 1);
items.splice(result.destination.index, 0, reorderedItem);
setData(items);
const onChangeData = ({ active, over }: DragEndEvent) => {
if (!over || active.id === over.id) return;

const oldIndex = data.findIndex((item) => item.id === Number(active.id));
const newIndex = data.findIndex((item) => item.id === Number(over.id));

setData((prev) => arrayMove(prev, oldIndex, newIndex));
setBeChange(true);
};

Expand All @@ -94,10 +96,10 @@ const Admin: React.FC = () => {
<Input
placeholder="섹션 이름"
background="white"
{...register('title', { required: true })}
onKeyPress={(e) => {
onKeyDown={(e) => {
if (e.key === 'Enter') handleSubmit(onAddClick)();
}}
{...register('title', { required: true })}
/>
<Button colorScheme="blue" fontWeight="normal" onClick={handleSubmit(onAddClick)}>
섹션 추가
Expand Down Expand Up @@ -164,4 +166,4 @@ const Admin: React.FC = () => {
);
};

export default Admin;
export default Page;
Loading

0 comments on commit 3a738d1

Please sign in to comment.