diff --git a/apps/admin/package.json b/apps/admin/package.json
index 6e1a7b43c..6b84d2659 100644
--- a/apps/admin/package.json
+++ b/apps/admin/package.json
@@ -1,46 +1,53 @@
{
- "name": "admin",
- "version": "0.1.0",
- "private": true,
- "scripts": {
- "dev": "next dev",
- "build": "next build",
- "start": "next start",
- "lint": "next lint",
- "storybook": "storybook dev -p 6006",
- "build-storybook": "storybook build"
- },
- "devDependencies": {
- "@maru/eslint": "workspace:*",
- "@maru/tsconfig": "workspace:*",
- "@storybook/addon-essentials": "^7.3.1",
- "@storybook/addon-interactions": "^7.3.1",
- "@storybook/addon-links": "^7.3.1",
- "@storybook/addon-onboarding": "^1.0.8",
- "@storybook/addon-styling": "^1.3.6",
- "@storybook/blocks": "^7.3.1",
- "@storybook/nextjs": "^7.3.1",
- "@storybook/react": "^7.3.1",
- "@storybook/testing-library": "^0.2.0",
- "@types/node": "20.3.1",
- "@types/react": "18.2.13",
- "@types/react-dom": "18.2.6",
- "@types/styled-components": "^5.1.26",
- "babel-plugin-styled-components": "^2.1.4",
- "eslint-plugin-storybook": "^0.6.13",
- "storybook": "^7.3.1",
- "styled-components": "^6.0.3",
- "tsconfig-paths-webpack-plugin": "^4.1.0",
- "typescript": "5.1.6"
- },
- "dependencies": {
- "@maru/hooks": "workspace:*",
- "@maru/icon": "workspace:*",
- "@maru/theme": "workspace:*",
- "@maru/ui": "workspace:*",
- "@maru/utils": "workspace:*",
- "next": "13.4.6",
- "react": "18.2.0",
- "react-dom": "18.2.0"
- }
-}
+ "name": "admin",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "next lint",
+ "storybook": "storybook dev -p 6006",
+ "build-storybook": "storybook build"
+ },
+ "devDependencies": {
+ "@maru/eslint": "workspace:*",
+ "@maru/tsconfig": "workspace:*",
+ "@storybook/addon-essentials": "^7.3.1",
+ "@storybook/addon-interactions": "^7.3.1",
+ "@storybook/addon-links": "^7.3.1",
+ "@storybook/addon-onboarding": "^1.0.8",
+ "@storybook/addon-styling": "^1.3.6",
+ "@storybook/blocks": "^7.3.1",
+ "@storybook/nextjs": "^7.3.1",
+ "@storybook/react": "^7.3.1",
+ "@storybook/testing-library": "^0.2.0",
+ "@types/node": "20.3.1",
+ "@types/react": "18.2.13",
+ "@types/react-dom": "18.2.6",
+ "@types/styled-components": "^5.1.26",
+ "babel-plugin-styled-components": "^2.1.4",
+ "eslint-plugin-storybook": "^0.6.13",
+ "msw": "^1.2.2",
+ "storybook": "^7.3.1",
+ "styled-components": "^6.0.3",
+ "tsconfig-paths-webpack-plugin": "^4.1.0",
+ "typescript": "5.1.6"
+ },
+ "dependencies": {
+ "@maru/hooks": "workspace:*",
+ "@maru/icon": "workspace:*",
+ "@maru/theme": "workspace:*",
+ "@maru/ui": "workspace:*",
+ "@maru/utils": "workspace:*",
+ "@tanstack/react-query": "^4.32.6",
+ "@tanstack/react-query-devtools": "^4.32.6",
+ "axios": "^1.4.0",
+ "next": "13.4.6",
+ "react": "18.2.0",
+ "react-dom": "18.2.0"
+ },
+ "msw": {
+ "workerDirectory": "public"
+ }
+}
\ No newline at end of file
diff --git a/apps/admin/public/mockServiceWorker.js b/apps/admin/public/mockServiceWorker.js
new file mode 100644
index 000000000..8ee70b3e4
--- /dev/null
+++ b/apps/admin/public/mockServiceWorker.js
@@ -0,0 +1,303 @@
+/* eslint-disable */
+/* tslint:disable */
+
+/**
+ * Mock Service Worker (1.2.2).
+ * @see https://github.com/mswjs/msw
+ * - Please do NOT modify this file.
+ * - Please do NOT serve this file on production.
+ */
+
+const INTEGRITY_CHECKSUM = '3d6b9f06410d179a7f7404d4bf4c3c70'
+const activeClientIds = new Set()
+
+self.addEventListener('install', function () {
+ self.skipWaiting()
+})
+
+self.addEventListener('activate', function (event) {
+ event.waitUntil(self.clients.claim())
+})
+
+self.addEventListener('message', async function (event) {
+ const clientId = event.source.id
+
+ if (!clientId || !self.clients) {
+ return
+ }
+
+ const client = await self.clients.get(clientId)
+
+ if (!client) {
+ return
+ }
+
+ const allClients = await self.clients.matchAll({
+ type: 'window',
+ })
+
+ switch (event.data) {
+ case 'KEEPALIVE_REQUEST': {
+ sendToClient(client, {
+ type: 'KEEPALIVE_RESPONSE',
+ })
+ break
+ }
+
+ case 'INTEGRITY_CHECK_REQUEST': {
+ sendToClient(client, {
+ type: 'INTEGRITY_CHECK_RESPONSE',
+ payload: INTEGRITY_CHECKSUM,
+ })
+ break
+ }
+
+ case 'MOCK_ACTIVATE': {
+ activeClientIds.add(clientId)
+
+ sendToClient(client, {
+ type: 'MOCKING_ENABLED',
+ payload: true,
+ })
+ break
+ }
+
+ case 'MOCK_DEACTIVATE': {
+ activeClientIds.delete(clientId)
+ break
+ }
+
+ case 'CLIENT_CLOSED': {
+ activeClientIds.delete(clientId)
+
+ const remainingClients = allClients.filter((client) => {
+ return client.id !== clientId
+ })
+
+ // Unregister itself when there are no more clients
+ if (remainingClients.length === 0) {
+ self.registration.unregister()
+ }
+
+ break
+ }
+ }
+})
+
+self.addEventListener('fetch', function (event) {
+ const { request } = event
+ const accept = request.headers.get('accept') || ''
+
+ // Bypass server-sent events.
+ if (accept.includes('text/event-stream')) {
+ return
+ }
+
+ // Bypass navigation requests.
+ if (request.mode === 'navigate') {
+ return
+ }
+
+ // Opening the DevTools triggers the "only-if-cached" request
+ // that cannot be handled by the worker. Bypass such requests.
+ if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') {
+ return
+ }
+
+ // Bypass all requests when there are no active clients.
+ // Prevents the self-unregistered worked from handling requests
+ // after it's been deleted (still remains active until the next reload).
+ if (activeClientIds.size === 0) {
+ return
+ }
+
+ // Generate unique request ID.
+ const requestId = Math.random().toString(16).slice(2)
+
+ event.respondWith(
+ handleRequest(event, requestId).catch((error) => {
+ if (error.name === 'NetworkError') {
+ console.warn(
+ '[MSW] Successfully emulated a network error for the "%s %s" request.',
+ request.method,
+ request.url,
+ )
+ return
+ }
+
+ // At this point, any exception indicates an issue with the original request/response.
+ console.error(
+ `\
+[MSW] Caught an exception from the "%s %s" request (%s). This is probably not a problem with Mock Service Worker. There is likely an additional logging output above.`,
+ request.method,
+ request.url,
+ `${error.name}: ${error.message}`,
+ )
+ }),
+ )
+})
+
+async function handleRequest(event, requestId) {
+ const client = await resolveMainClient(event)
+ const response = await getResponse(event, client, requestId)
+
+ // Send back the response clone for the "response:*" life-cycle events.
+ // Ensure MSW is active and ready to handle the message, otherwise
+ // this message will pend indefinitely.
+ if (client && activeClientIds.has(client.id)) {
+ ;(async function () {
+ const clonedResponse = response.clone()
+ sendToClient(client, {
+ type: 'RESPONSE',
+ payload: {
+ requestId,
+ type: clonedResponse.type,
+ ok: clonedResponse.ok,
+ status: clonedResponse.status,
+ statusText: clonedResponse.statusText,
+ body:
+ clonedResponse.body === null ? null : await clonedResponse.text(),
+ headers: Object.fromEntries(clonedResponse.headers.entries()),
+ redirected: clonedResponse.redirected,
+ },
+ })
+ })()
+ }
+
+ return response
+}
+
+// Resolve the main client for the given event.
+// Client that issues a request doesn't necessarily equal the client
+// that registered the worker. It's with the latter the worker should
+// communicate with during the response resolving phase.
+async function resolveMainClient(event) {
+ const client = await self.clients.get(event.clientId)
+
+ if (client?.frameType === 'top-level') {
+ return client
+ }
+
+ const allClients = await self.clients.matchAll({
+ type: 'window',
+ })
+
+ return allClients
+ .filter((client) => {
+ // Get only those clients that are currently visible.
+ return client.visibilityState === 'visible'
+ })
+ .find((client) => {
+ // Find the client ID that's recorded in the
+ // set of clients that have registered the worker.
+ return activeClientIds.has(client.id)
+ })
+}
+
+async function getResponse(event, client, requestId) {
+ const { request } = event
+ const clonedRequest = request.clone()
+
+ function passthrough() {
+ // Clone the request because it might've been already used
+ // (i.e. its body has been read and sent to the client).
+ const headers = Object.fromEntries(clonedRequest.headers.entries())
+
+ // Remove MSW-specific request headers so the bypassed requests
+ // comply with the server's CORS preflight check.
+ // Operate with the headers as an object because request "Headers"
+ // are immutable.
+ delete headers['x-msw-bypass']
+
+ return fetch(clonedRequest, { headers })
+ }
+
+ // Bypass mocking when the client is not active.
+ if (!client) {
+ return passthrough()
+ }
+
+ // Bypass initial page load requests (i.e. static assets).
+ // The absence of the immediate/parent client in the map of the active clients
+ // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
+ // and is not ready to handle requests.
+ if (!activeClientIds.has(client.id)) {
+ return passthrough()
+ }
+
+ // Bypass requests with the explicit bypass header.
+ // Such requests can be issued by "ctx.fetch()".
+ if (request.headers.get('x-msw-bypass') === 'true') {
+ return passthrough()
+ }
+
+ // Notify the client that a request has been intercepted.
+ const clientMessage = await sendToClient(client, {
+ type: 'REQUEST',
+ payload: {
+ id: requestId,
+ url: request.url,
+ method: request.method,
+ headers: Object.fromEntries(request.headers.entries()),
+ cache: request.cache,
+ mode: request.mode,
+ credentials: request.credentials,
+ destination: request.destination,
+ integrity: request.integrity,
+ redirect: request.redirect,
+ referrer: request.referrer,
+ referrerPolicy: request.referrerPolicy,
+ body: await request.text(),
+ bodyUsed: request.bodyUsed,
+ keepalive: request.keepalive,
+ },
+ })
+
+ switch (clientMessage.type) {
+ case 'MOCK_RESPONSE': {
+ return respondWithMock(clientMessage.data)
+ }
+
+ case 'MOCK_NOT_FOUND': {
+ return passthrough()
+ }
+
+ case 'NETWORK_ERROR': {
+ const { name, message } = clientMessage.data
+ const networkError = new Error(message)
+ networkError.name = name
+
+ // Rejecting a "respondWith" promise emulates a network error.
+ throw networkError
+ }
+ }
+
+ return passthrough()
+}
+
+function sendToClient(client, message) {
+ return new Promise((resolve, reject) => {
+ const channel = new MessageChannel()
+
+ channel.port1.onmessage = (event) => {
+ if (event.data && event.data.error) {
+ return reject(event.data.error)
+ }
+
+ resolve(event.data)
+ }
+
+ client.postMessage(message, [channel.port2])
+ })
+}
+
+function sleep(timeMs) {
+ return new Promise((resolve) => {
+ setTimeout(resolve, timeMs)
+ })
+}
+
+async function respondWithMock(response) {
+ await sleep(response.delay)
+ return new Response(response.body, response)
+}
diff --git a/apps/admin/src/apis/instance/instance.ts b/apps/admin/src/apis/instance/instance.ts
new file mode 100644
index 000000000..0635ff118
--- /dev/null
+++ b/apps/admin/src/apis/instance/instance.ts
@@ -0,0 +1,27 @@
+import axios from 'axios';
+
+export const maru = axios.create({
+ baseURL: process.env.NEXT_PUBLIC_BASE_URL,
+ timeout: 15000,
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+});
+
+maru.interceptors.request.use(
+ (config) => {
+ return config;
+ },
+ (error) => {
+ return Promise.reject(error);
+ },
+);
+
+maru.interceptors.response.use(
+ (response) => {
+ return response;
+ },
+ async (error) => {
+ return Promise.reject(error);
+ },
+);
diff --git a/apps/admin/src/app/layout.tsx b/apps/admin/src/app/layout.tsx
index 27e5f111b..da12b1d29 100644
--- a/apps/admin/src/app/layout.tsx
+++ b/apps/admin/src/app/layout.tsx
@@ -1,4 +1,5 @@
import Provider from '@/components/Provider';
+import QueryClientProvider from '@/services/QueryClientProvider';
import { ReactNode } from 'react';
export const metadata = {
@@ -14,7 +15,9 @@ const RootLayout = ({ children }: Props) => {
return (
- {children}
+
+ {children}
+
);
diff --git a/apps/admin/src/app/notice/page.tsx b/apps/admin/src/app/notice/page.tsx
index 97e5f1459..229783027 100644
--- a/apps/admin/src/app/notice/page.tsx
+++ b/apps/admin/src/app/notice/page.tsx
@@ -34,6 +34,6 @@ const StyledNoticePage = styled.div`
${flex({ flexDirection: 'column' })}
gap: 40px;
width: 100%;
- height: 100%;
+ min-height: 100vh;
padding: 64px 75px;
`;
diff --git a/apps/admin/src/app/page.tsx b/apps/admin/src/app/page.tsx
index edeb1e7aa..c9de1ed35 100644
--- a/apps/admin/src/app/page.tsx
+++ b/apps/admin/src/app/page.tsx
@@ -1,7 +1,46 @@
'use client';
+import FormList from '@/components/main/FormList/FormList';
import AppLayout from '@/layouts/AppLayout';
+import initMockAPI from '@/mocks';
+import { Button, Column, Row, SearchInput, Text } from '@maru/ui';
+import { flex } from '@maru/utils';
+import { styled } from 'styled-components';
-export default function Home() {
- return asdf;
+if (process.env.NODE_ENV === 'development') {
+ initMockAPI();
}
+
+const Home = () => {
+ return (
+
+
+ 원서 관리
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Home;
+
+const StyledHome = styled.div`
+ ${flex({ flexDirection: 'column' })}
+ gap: 40px;
+ width: 100%;
+ height: 100%;
+ padding: 64px 75px;
+
+ overflow: auto;
+`;
diff --git a/apps/admin/src/components/common/SideBar/SideBar.tsx b/apps/admin/src/components/common/SideBar/SideBar.tsx
index a0b3e0cf9..9e1fd78f0 100644
--- a/apps/admin/src/components/common/SideBar/SideBar.tsx
+++ b/apps/admin/src/components/common/SideBar/SideBar.tsx
@@ -8,9 +8,13 @@ import { color, font } from '../../../../../../packages/maru-theme';
const NAVIGATION_DATA = [
{
- name: '홈',
+ name: '원서조회',
route: ROUTES.MAIN,
},
+ {
+ name: '원서검토',
+ route: ROUTES.REVIEW,
+ },
{
name: '공지사항',
route: ROUTES.NOTICE,
@@ -77,6 +81,7 @@ const SideNavigationBar = styled.div`
`;
const StyledLink = styled(Link)<{ $active: boolean }>`
+ ${font.H5}
position: relative;
${flex({ alignItems: 'center' })}
width: 100%;
@@ -106,7 +111,7 @@ const StyledLink = styled(Link)<{ $active: boolean }>`
`;
const LogoutButton = styled.button`
- ${font.btn1}
+ ${font.H5}
${flex({ alignItems: 'center' })}
height: 56px;
padding: 0px 36px;
diff --git a/apps/admin/src/components/common/ListHeader/ListHeader.stories.tsx b/apps/admin/src/components/common/TableHeader/TableHeader.stories.tsx
similarity index 94%
rename from apps/admin/src/components/common/ListHeader/ListHeader.stories.tsx
rename to apps/admin/src/components/common/TableHeader/TableHeader.stories.tsx
index 576847c59..7e71df1ae 100644
--- a/apps/admin/src/components/common/ListHeader/ListHeader.stories.tsx
+++ b/apps/admin/src/components/common/TableHeader/TableHeader.stories.tsx
@@ -1,6 +1,6 @@
import { Row, Text } from "@maru/ui";
import type { Meta, StoryObj } from "@storybook/react";
-import ListHeader from "./ListHeader";
+import ListHeader from "./TableHeader";
export default {
component: ListHeader,
diff --git a/apps/admin/src/components/common/ListHeader/ListHeader.tsx b/apps/admin/src/components/common/TableHeader/TableHeader.tsx
similarity index 88%
rename from apps/admin/src/components/common/ListHeader/ListHeader.tsx
rename to apps/admin/src/components/common/TableHeader/TableHeader.tsx
index 321161d53..85b7dfd84 100644
--- a/apps/admin/src/components/common/ListHeader/ListHeader.tsx
+++ b/apps/admin/src/components/common/TableHeader/TableHeader.tsx
@@ -7,11 +7,11 @@ interface Props {
children: ReactNode;
}
-const ListHeader = ({ children }: Props) => {
+const TableHeader = ({ children }: Props) => {
return {children};
};
-export default ListHeader;
+export default TableHeader;
const StyledListHeader = styled.div`
${flex({ alignItems: 'center', justifyContent: 'space-between' })}
diff --git a/apps/admin/src/components/common/ListItem/ListItem.stories.tsx b/apps/admin/src/components/common/TableItem/TableItem.stories.tsx
similarity index 95%
rename from apps/admin/src/components/common/ListItem/ListItem.stories.tsx
rename to apps/admin/src/components/common/TableItem/TableItem.stories.tsx
index b404ff61b..1dbca9939 100644
--- a/apps/admin/src/components/common/ListItem/ListItem.stories.tsx
+++ b/apps/admin/src/components/common/TableItem/TableItem.stories.tsx
@@ -1,6 +1,6 @@
import { Row, Text } from "@maru/ui";
import type { Meta, StoryObj } from "@storybook/react";
-import ListItem from "./ListItem";
+import ListItem from "./TableItem";
export default {
component: ListItem,
diff --git a/apps/admin/src/components/common/ListItem/ListItem.tsx b/apps/admin/src/components/common/TableItem/TableItem.tsx
similarity index 88%
rename from apps/admin/src/components/common/ListItem/ListItem.tsx
rename to apps/admin/src/components/common/TableItem/TableItem.tsx
index 6dcf32898..6a5b022d1 100644
--- a/apps/admin/src/components/common/ListItem/ListItem.tsx
+++ b/apps/admin/src/components/common/TableItem/TableItem.tsx
@@ -7,11 +7,11 @@ interface Props {
children: ReactNode;
}
-const ListItem = ({ children }: Props) => {
+const TableItem = ({ children }: Props) => {
return {children};
};
-export default ListItem;
+export default TableItem;
const StyledListItem = styled.div`
${flex({ alignItems: 'center', justifyContent: 'space-between' })}
diff --git a/apps/admin/src/components/faq/FaqTable/FaqTableHeader/FaqTableHeader.tsx b/apps/admin/src/components/faq/FaqTable/FaqTableHeader/FaqTableHeader.tsx
index 7cce24b74..d901e088e 100644
--- a/apps/admin/src/components/faq/FaqTable/FaqTableHeader/FaqTableHeader.tsx
+++ b/apps/admin/src/components/faq/FaqTable/FaqTableHeader/FaqTableHeader.tsx
@@ -1,9 +1,9 @@
-import ListHeader from '@/components/common/ListHeader/ListHeader';
+import TableHeader from '@/components/common/TableHeader/TableHeader';
import { Row, Text } from '@maru/ui';
const FaqTableHeader = () => {
return (
-
+
번호
@@ -20,7 +20,7 @@ const FaqTableHeader = () => {
게시일
-
+
);
};
diff --git a/apps/admin/src/components/faq/FaqTable/FaqTableItem/FaqTableItem.tsx b/apps/admin/src/components/faq/FaqTable/FaqTableItem/FaqTableItem.tsx
index 255dd5678..d87485a55 100644
--- a/apps/admin/src/components/faq/FaqTable/FaqTableItem/FaqTableItem.tsx
+++ b/apps/admin/src/components/faq/FaqTable/FaqTableItem/FaqTableItem.tsx
@@ -1,5 +1,5 @@
-import ListItem from '@/components/common/ListItem/ListItem';
-import { Text, Row } from '@maru/ui';
+import TableItem from '@/components/common/TableItem/TableItem';
+import { Row, Text } from '@maru/ui';
import { formatCreatedAt } from '@maru/utils';
interface Props {
@@ -11,7 +11,7 @@ interface Props {
const FaqTableItem = ({ id, title, category, createdAt }: Props) => {
return (
-
+
{id}
@@ -28,7 +28,7 @@ const FaqTableItem = ({ id, title, category, createdAt }: Props) => {
{formatCreatedAt(createdAt)}
-
+
);
};
diff --git a/apps/admin/src/components/main/FormList/FormList.tsx b/apps/admin/src/components/main/FormList/FormList.tsx
new file mode 100644
index 000000000..1c5220dc4
--- /dev/null
+++ b/apps/admin/src/components/main/FormList/FormList.tsx
@@ -0,0 +1,32 @@
+import { Column } from '@maru/ui';
+import { styled } from 'styled-components';
+
+import { useFormListQuery } from '@/services/form/queries';
+import FormListHeader from '../FormListHeader/FormListHeader';
+import FormListItem from '../FormListItem/FormListItem';
+
+const FormList = () => {
+ const { data: formList } = useFormListQuery();
+
+ return (
+
+
+ {formList &&
+ formList.map((item) => (
+
+ ))}
+
+ );
+};
+
+export default FormList;
+
+const StyledFormList = styled.div``;
diff --git a/apps/admin/src/components/main/FormListHeader/FormListHeader.tsx b/apps/admin/src/components/main/FormListHeader/FormListHeader.tsx
new file mode 100644
index 000000000..2516cf070
--- /dev/null
+++ b/apps/admin/src/components/main/FormListHeader/FormListHeader.tsx
@@ -0,0 +1,31 @@
+import TableHeader from '@/components/common/TableHeader/TableHeader';
+import { Row, Text } from '@maru/ui';
+
+const FormListHeader = () => {
+ return (
+
+
+
+ 접수번호
+
+
+ 이름
+
+
+ 생년월일
+
+
+ 학교
+
+
+ 전형
+
+
+
+ 상태
+
+
+ );
+};
+
+export default FormListHeader;
diff --git a/apps/admin/src/components/main/FormListItem/FormListItem.tsx b/apps/admin/src/components/main/FormListItem/FormListItem.tsx
new file mode 100644
index 000000000..6f8d067cc
--- /dev/null
+++ b/apps/admin/src/components/main/FormListItem/FormListItem.tsx
@@ -0,0 +1,43 @@
+import TableItem from '@/components/common/TableItem/TableItem';
+import { KoreanFormType } from '@/constants/main/constants';
+import { FormStatus, FormType, GraduationType } from '@/types/main/client';
+import { Row, Text } from '@maru/ui';
+
+interface Props {
+ id: number;
+ name: string;
+ birthday: string;
+ graduationType: GraduationType;
+ school: string;
+ status: FormStatus;
+ type: FormType;
+}
+
+const FormListItem = ({ id, name, birthday, graduationType, school, type, status }: Props) => {
+ return (
+
+
+
+ {id}
+
+
+ {name}
+
+
+ {birthday.replaceAll('-', '').slice(2)}
+
+
+ {graduationType === 'QUALIFICATION_EXAMINATION' ? '검정고시' : school}
+
+
+ {KoreanFormType[type as FormType]}
+
+
+
+ {status}
+
+
+ );
+};
+
+export default FormListItem;
diff --git a/apps/admin/src/components/notice/NoticeList/NoticeList.tsx b/apps/admin/src/components/notice/NoticeList/NoticeList.tsx
index 4c839e756..835c0bc58 100644
--- a/apps/admin/src/components/notice/NoticeList/NoticeList.tsx
+++ b/apps/admin/src/components/notice/NoticeList/NoticeList.tsx
@@ -1,57 +1,18 @@
-import ListHeader from '@/components/common/ListHeader/ListHeader';
-import ListItem from '@/components/common/ListItem/ListItem';
-import { Column, Row, Text } from '@maru/ui';
-import { formatPostedAt } from '@maru/utils';
-
-const NOTICE_DATA = [
- {
- id: 0,
- title: '입학전형 사용 방법에 대한 공지사항',
- date: '2022-05-07T10:35:57',
- },
- {
- id: 1,
- title: '테스트입니다',
- date: '2022-05-07T10:35:57',
- },
- {
- id: 2,
- title: '테스트입니다',
- date: '2022-05-07T10:35:57',
- },
-] as const;
+import { useNoticeListQuery } from '@/services/notice/queries';
+import { Column } from '@maru/ui';
+import NoticeListHeader from '../NoticeListHeader/NoticeListHeader';
+import NoticeListItem from '../NoticeListItem/NoticeListItem';
const NoticeList = () => {
+ const { data: noticeList } = useNoticeListQuery();
+
return (
-
-
-
- 번호
-
-
- 제목
-
-
-
- 게시일
-
-
- {NOTICE_DATA.map((item) => (
-
-
-
- {item.id}
-
-
- {item.title}
-
-
-
- {formatPostedAt(item.date)}
-
-
- ))}
+
+ {noticeList &&
+ noticeList.map(({ id, title, createdAt }) => (
+
+ ))}
);
};
diff --git a/apps/admin/src/components/notice/NoticeListHeader/NoticeListHeader.tsx b/apps/admin/src/components/notice/NoticeListHeader/NoticeListHeader.tsx
new file mode 100644
index 000000000..ec8dc8ff7
--- /dev/null
+++ b/apps/admin/src/components/notice/NoticeListHeader/NoticeListHeader.tsx
@@ -0,0 +1,22 @@
+import TableHeader from '@/components/common/TableHeader/TableHeader';
+import { Row, Text } from '@maru/ui';
+
+const NoticeListHeader = () => {
+ return (
+
+
+
+ 번호
+
+
+ 제목
+
+
+
+ 게시일
+
+
+ );
+};
+
+export default NoticeListHeader;
diff --git a/apps/admin/src/components/notice/NoticeListItem/NoticeListItem.tsx b/apps/admin/src/components/notice/NoticeListItem/NoticeListItem.tsx
new file mode 100644
index 000000000..a78e868a1
--- /dev/null
+++ b/apps/admin/src/components/notice/NoticeListItem/NoticeListItem.tsx
@@ -0,0 +1,29 @@
+import TableItem from '@/components/common/TableItem/TableItem';
+import { Row, Text } from '@maru/ui';
+import { formatPostedAt } from '@maru/utils';
+
+interface Props {
+ id: number;
+ title: string;
+ createdAt: string;
+}
+
+const NoticeListItem = ({ id, title, createdAt }: Props) => {
+ return (
+
+
+
+ {id}
+
+
+ {title}
+
+
+
+ {formatPostedAt(createdAt)}
+
+
+ );
+};
+
+export default NoticeListItem;
diff --git a/apps/admin/src/constants/common/constants.ts b/apps/admin/src/constants/common/constants.ts
index 024b80eba..d19b45f44 100644
--- a/apps/admin/src/constants/common/constants.ts
+++ b/apps/admin/src/constants/common/constants.ts
@@ -1,6 +1,12 @@
+export const KEY = {
+ NOTICE_LIST: 'useNoticeList',
+ FORM_LIST: 'useFormList',
+};
+
export const ROUTES = {
MAIN: '/',
+ REVIEW: '/review',
NOTICE: '/notice',
FAQ: '/faq',
- ANALYSIS: 'analysis',
+ ANALYSIS: '/analysis',
} as const;
diff --git a/apps/admin/src/constants/main/constants.ts b/apps/admin/src/constants/main/constants.ts
new file mode 100644
index 000000000..4e2254ba8
--- /dev/null
+++ b/apps/admin/src/constants/main/constants.ts
@@ -0,0 +1,16 @@
+import { FormType } from '@/types/main/client';
+
+export const KoreanFormType: Record = {
+ REGULAR: '일반',
+ MEISTER_TALENT: '마이스터인재',
+ NATIONAL_BASIC_LIVING: '국민기초생활수급자',
+ NEAR_POVERTY: '차상위계층',
+ NATIONAL_VETERANS: '국가보훈대상자 (국가유공자)',
+ ONE_PARENT: '한부모가정',
+ FROM_NORTH_KOREA: '북한이탈주민',
+ MULTICULTURAL: '다문화가정',
+ TEEN_HOUSEHOLDER: '소년소녀가장',
+ MULTI_CHILDREN: '다자녀가정자녀',
+ FARMING_AND_FISHING: '농어촌지역출신자',
+ SPECIAL_ADMISSION: '특례입학대상자전형',
+};
diff --git a/apps/admin/src/layouts/AppLayout.tsx b/apps/admin/src/layouts/AppLayout.tsx
index 129e9ccde..d3dacc46e 100644
--- a/apps/admin/src/layouts/AppLayout.tsx
+++ b/apps/admin/src/layouts/AppLayout.tsx
@@ -26,4 +26,6 @@ const StyledAppLayout = styled.div`
const Section = styled.section`
flex: 1;
+ min-width: fit-content;
+ overflow: auto;
`;
diff --git a/apps/admin/src/mocks/browser.ts b/apps/admin/src/mocks/browser.ts
new file mode 100644
index 000000000..74df1dbec
--- /dev/null
+++ b/apps/admin/src/mocks/browser.ts
@@ -0,0 +1,4 @@
+import { setupWorker } from "msw";
+import { handlers } from "./handlers";
+
+export const worker = setupWorker(...handlers);
diff --git a/apps/admin/src/mocks/handlers/index.ts b/apps/admin/src/mocks/handlers/index.ts
new file mode 100644
index 000000000..8535a3bd8
--- /dev/null
+++ b/apps/admin/src/mocks/handlers/index.ts
@@ -0,0 +1,4 @@
+import { mainHandlers } from './main';
+import { noticeHandlers } from './notice';
+
+export const handlers = [...noticeHandlers, ...mainHandlers];
diff --git a/apps/admin/src/mocks/handlers/main.ts b/apps/admin/src/mocks/handlers/main.ts
new file mode 100644
index 000000000..3a5094819
--- /dev/null
+++ b/apps/admin/src/mocks/handlers/main.ts
@@ -0,0 +1,38 @@
+import { Form } from '@/types/main/client';
+import { rest } from 'msw';
+
+const MAIN_FORM_DATA: Form[] = [
+ {
+ id: 0,
+ name: '김밤돌',
+ birthday: '2005-04-15',
+ graduationType: 'EXPECTED',
+ school: '비전중학교',
+ status: '최종 제출됨',
+ type: 'REGULAR',
+ },
+ {
+ id: 1,
+ name: '김밤돌',
+ birthday: '2005-04-15',
+ graduationType: 'QUALIFICATION_EXAMINATION',
+ school: '비전중학교',
+ status: '반려됨',
+ type: 'REGULAR',
+ },
+ {
+ id: 2,
+ name: '김밤돌',
+ birthday: '2005-04-15',
+ graduationType: 'EXPECTED',
+ school: '비전중학교',
+ status: '최종 제출됨',
+ type: 'MULTICULTURAL',
+ },
+];
+
+export const mainHandlers = [
+ rest.get('/form/review', (_, res, ctx) => {
+ return res(ctx.status(200), ctx.json({ dataList: MAIN_FORM_DATA }));
+ }),
+];
diff --git a/apps/admin/src/mocks/handlers/notice.ts b/apps/admin/src/mocks/handlers/notice.ts
new file mode 100644
index 000000000..68700c417
--- /dev/null
+++ b/apps/admin/src/mocks/handlers/notice.ts
@@ -0,0 +1,26 @@
+import { Notice } from '@/types/notice/client';
+import { rest } from 'msw';
+
+const NOTICE_DATA: Notice[] = [
+ {
+ id: 0,
+ title: '테스트입니다',
+ createdAt: '2022-05-07T10:35:57',
+ },
+ {
+ id: 1,
+ title: '테스트입니다',
+ createdAt: '2022-05-07T10:35:57',
+ },
+ {
+ id: 2,
+ title: '테스트입니다',
+ createdAt: '2022-05-07T10:35:57',
+ },
+];
+
+export const noticeHandlers = [
+ rest.get('/notice', (_, res, ctx) => {
+ return res(ctx.status(200), ctx.json({ dataList: NOTICE_DATA }));
+ }),
+];
diff --git a/apps/admin/src/mocks/index.ts b/apps/admin/src/mocks/index.ts
new file mode 100644
index 000000000..9b307565e
--- /dev/null
+++ b/apps/admin/src/mocks/index.ts
@@ -0,0 +1,11 @@
+const initMockAPI = async (): Promise => {
+ if (typeof window === 'undefined') {
+ const { server } = await import('@/mocks/server');
+ server.listen();
+ } else {
+ const { worker } = await import('@/mocks/browser');
+ worker.start();
+ }
+};
+
+export default initMockAPI;
diff --git a/apps/admin/src/mocks/server.ts b/apps/admin/src/mocks/server.ts
new file mode 100644
index 000000000..7b37f2acf
--- /dev/null
+++ b/apps/admin/src/mocks/server.ts
@@ -0,0 +1,4 @@
+import { setupServer } from "msw/node";
+import { handlers } from "./handlers";
+
+export const server = setupServer(...handlers);
diff --git a/apps/admin/src/services/QueryClientProvider.tsx b/apps/admin/src/services/QueryClientProvider.tsx
new file mode 100644
index 000000000..9f238d39b
--- /dev/null
+++ b/apps/admin/src/services/QueryClientProvider.tsx
@@ -0,0 +1,32 @@
+'use client';
+
+import { QueryClientProvider as MaruQueryClientProvider, QueryClient } from '@tanstack/react-query';
+import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
+import { ReactNode, useState } from 'react';
+
+interface PropsType {
+ children: ReactNode;
+}
+
+const QueryClientProvider = ({ children }: PropsType) => {
+ const [queryClient] = useState(
+ () =>
+ new QueryClient({
+ defaultOptions: {
+ queries: {
+ refetchOnWindowFocus: false,
+ suspense: true,
+ },
+ },
+ }),
+ );
+
+ return (
+
+ {children}
+
+
+ );
+};
+
+export default QueryClientProvider;
diff --git a/apps/admin/src/services/form/api.ts b/apps/admin/src/services/form/api.ts
new file mode 100644
index 000000000..e7054e18b
--- /dev/null
+++ b/apps/admin/src/services/form/api.ts
@@ -0,0 +1,8 @@
+import { maru } from '@/apis/instance/instance';
+import { GetFormReviewListRes } from '@/types/main/remote';
+
+export const getFormReviewList = async () => {
+ const { data } = await maru.get('/form/review');
+
+ return data;
+};
diff --git a/apps/admin/src/services/form/queries.ts b/apps/admin/src/services/form/queries.ts
new file mode 100644
index 000000000..0354428aa
--- /dev/null
+++ b/apps/admin/src/services/form/queries.ts
@@ -0,0 +1,13 @@
+import { KEY } from '@/constants/common/constants';
+import { useQuery } from '@tanstack/react-query';
+import { getFormReviewList } from './api';
+
+export const useFormListQuery = () => {
+ const { data, ...restQuery } = useQuery({
+ queryKey: [KEY.FORM_LIST],
+ queryFn: getFormReviewList,
+ suspense: false,
+ });
+
+ return { data: data?.dataList, ...restQuery };
+};
diff --git a/apps/admin/src/services/notice/api.ts b/apps/admin/src/services/notice/api.ts
new file mode 100644
index 000000000..c686fcd74
--- /dev/null
+++ b/apps/admin/src/services/notice/api.ts
@@ -0,0 +1,7 @@
+import { maru } from '@/apis/instance/instance';
+import { GetNoticeListRes } from '@/types/notice/remote';
+
+export const getNoticeList = async () => {
+ const { data } = await maru.get('/notice');
+ return data;
+};
diff --git a/apps/admin/src/services/notice/queries.ts b/apps/admin/src/services/notice/queries.ts
new file mode 100644
index 000000000..1af4d8c80
--- /dev/null
+++ b/apps/admin/src/services/notice/queries.ts
@@ -0,0 +1,13 @@
+import { KEY } from '@/constants/common/constants';
+import { useQuery } from '@tanstack/react-query';
+import { getNoticeList } from './api';
+
+export const useNoticeListQuery = () => {
+ const { data, ...restQuery } = useQuery({
+ queryKey: [KEY.NOTICE_LIST],
+ queryFn: getNoticeList,
+ suspense: false,
+ });
+
+ return { data: data?.dataList, ...restQuery };
+};
diff --git a/apps/admin/src/types/main/client.ts b/apps/admin/src/types/main/client.ts
new file mode 100644
index 000000000..2b6fc1850
--- /dev/null
+++ b/apps/admin/src/types/main/client.ts
@@ -0,0 +1,27 @@
+export type FormType =
+ | 'REGULAR'
+ | 'MEISTER_TALENT'
+ | 'NATIONAL_BASIC_LIVING'
+ | 'NEAR_POVERTY'
+ | 'NATIONAL_VETERANS'
+ | 'ONE_PARENT'
+ | 'FROM_NORTH_KOREA'
+ | 'MULTICULTURAL'
+ | 'TEEN_HOUSEHOLDER'
+ | 'MULTI_CHILDREN'
+ | 'FARMING_AND_FISHING'
+ | 'SPECIAL_ADMISSION';
+
+export type GraduationType = 'EXPECTED' | 'GRADUATED' | 'QUALIFICATION_EXAMINATION';
+
+export type FormStatus = '최종 제출됨' | '반려됨';
+
+export interface Form {
+ id: number;
+ name: string;
+ birthday: string;
+ graduationType: GraduationType;
+ school: string;
+ status: FormStatus;
+ type: FormType;
+}
diff --git a/apps/admin/src/types/main/remote.ts b/apps/admin/src/types/main/remote.ts
new file mode 100644
index 000000000..edc153de0
--- /dev/null
+++ b/apps/admin/src/types/main/remote.ts
@@ -0,0 +1,5 @@
+import { Form } from './client';
+
+export interface GetFormReviewListRes {
+ dataList: Form[];
+}
diff --git a/apps/admin/src/types/notice/client.ts b/apps/admin/src/types/notice/client.ts
new file mode 100644
index 000000000..26ab03a2c
--- /dev/null
+++ b/apps/admin/src/types/notice/client.ts
@@ -0,0 +1,5 @@
+export interface Notice {
+ id: number;
+ title: string;
+ createdAt: string;
+}
diff --git a/apps/admin/src/types/notice/remote.ts b/apps/admin/src/types/notice/remote.ts
new file mode 100644
index 000000000..8b575d968
--- /dev/null
+++ b/apps/admin/src/types/notice/remote.ts
@@ -0,0 +1,5 @@
+import { Notice } from './client';
+
+export interface GetNoticeListRes {
+ dataList: Notice[];
+}
diff --git a/apps/admin/tsconfig.json b/apps/admin/tsconfig.json
index 0c7555fa7..9557b813f 100644
--- a/apps/admin/tsconfig.json
+++ b/apps/admin/tsconfig.json
@@ -1,28 +1,28 @@
{
- "compilerOptions": {
- "target": "es5",
- "lib": ["dom", "dom.iterable", "esnext"],
- "allowJs": true,
- "skipLibCheck": true,
- "strict": true,
- "forceConsistentCasingInFileNames": true,
- "noEmit": true,
- "esModuleInterop": true,
- "module": "esnext",
- "moduleResolution": "node",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "jsx": "preserve",
- "incremental": true,
- "plugins": [
- {
- "name": "next"
- }
- ],
- "paths": {
- "@/*": ["./src/*"]
- }
- },
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
- "exclude": ["node_modules"]
+ "compilerOptions": {
+ "target": "es5",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "incremental": true,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+ "exclude": ["node_modules"]
}
diff --git a/apps/user/src/app/error.tsx b/apps/user/src/app/error.tsx
index e7f94c9cf..7c61b5251 100644
--- a/apps/user/src/app/error.tsx
+++ b/apps/user/src/app/error.tsx
@@ -13,7 +13,7 @@ const Error = () => {
return (
-
+
@@ -38,14 +38,14 @@ const Error = () => {
새로고침하기
-
+
);
};
export default Error;
-const StyledError = styled.div`
+const StyledErrorPage = styled.div`
${flex({ flexDirection: 'column', alignItems: 'center' })};
gap: 56px;
margin: 82px auto 0;
diff --git a/apps/user/src/app/faq/page.tsx b/apps/user/src/app/faq/page.tsx
index d7cac7f8f..e100b6924 100644
--- a/apps/user/src/app/faq/page.tsx
+++ b/apps/user/src/app/faq/page.tsx
@@ -12,7 +12,7 @@ const FaqPage = () => {
const [category, setCategory] = useState('TOP_QUESTION');
return (
-
+
자주 묻는 질문
@@ -31,6 +31,8 @@ export default FaqPage;
const StyledFaqPage = styled.div`
position: relative;
width: 100%;
+ max-width: 1240px;
height: 100%;
- padding-bottom: 227px;
+ margin: 0 auto;
+ padding: 82px 204px 240px;
`;
diff --git "a/apps/user/src/app/form/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264.hooks.ts" "b/apps/user/src/app/form/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264.hooks.ts"
index 0043834c8..6996e3cfe 100644
--- "a/apps/user/src/app/form/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264.hooks.ts"
+++ "b/apps/user/src/app/form/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264.hooks.ts"
@@ -1,6 +1,6 @@
-import { ChangeEventHandler } from 'react';
import { useSaveFormMutation } from '@/services/form/mutations';
-import { useSetFormStore, useSetFormStepStore, useFormValueStore } from '@/store';
+import { useFormValueStore, useSetFormStepStore, useSetFormStore } from '@/store';
+import { ChangeEventHandler } from 'react';
export const useCTAButton = () => {
const form = useFormValueStore();
@@ -24,6 +24,7 @@ export const useInput = () => {
const handle보호자정보DataChange: ChangeEventHandler = (e) => {
const { name, value } = e.target;
+
setForm((prev) => ({ ...prev, parent: { ...prev.parent, [name]: value } }));
};
diff --git "a/apps/user/src/app/form/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264.tsx" "b/apps/user/src/app/form/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264.tsx"
index 0467bb74e..b733432fb 100644
--- "a/apps/user/src/app/form/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264.tsx"
+++ "b/apps/user/src/app/form/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264/\353\263\264\355\230\270\354\236\220\354\240\225\353\263\264.tsx"
@@ -1,7 +1,7 @@
import { FindAddressModal, FormController } from '@/components/form';
import { FormLayout } from '@/layouts';
import { useFormValueStore } from '@/store';
-import { ButtonInput, Column, Input, RadioGroup, Row } from '@maru/ui';
+import { ButtonInput, Column, Input, Row } from '@maru/ui';
import { useOverlay } from '@toss/use-overlay';
import styled from 'styled-components';
import { useCTAButton, useInput } from './보호자정보.hooks';
@@ -53,32 +53,14 @@ const 보호자정보 = () => {
isError={form.parent.address.length > 100}
errorMessage="100자 이하여야 합니다."
/>
-
-
-
- {form.parent.relation !== '아빠' && form.parent.relation !== '엄마' && (
-
- )}
+
{
- const [fieldStep, setFieldStep] = useState('성적 입력');
+ const [scoreStep, setScoreStep] = useState('성적 입력');
const { handleNextButtonClick, handlePreviousButtonClick } = useCTAButton();
return (
@@ -37,16 +37,16 @@ const 성적입력 = () => {
{FIELD_DATA.map((item, index) => (
- setFieldStep(item)}>
+ setScoreStep(item)}>
{item}
-
+
))}
,
출결상황: ,
diff --git "a/apps/user/src/app/form/\354\265\234\354\242\205\354\240\234\354\266\234/\354\265\234\354\242\205\354\240\234\354\266\234.tsx" "b/apps/user/src/app/form/\354\265\234\354\242\205\354\240\234\354\266\234/\354\265\234\354\242\205\354\240\234\354\266\234.tsx"
index f7eb57a92..3708eaa4c 100644
--- "a/apps/user/src/app/form/\354\265\234\354\242\205\354\240\234\354\266\234/\354\265\234\354\242\205\354\240\234\354\266\234.tsx"
+++ "b/apps/user/src/app/form/\354\265\234\354\242\205\354\240\234\354\266\234/\354\265\234\354\242\205\354\240\234\354\266\234.tsx"
@@ -35,7 +35,7 @@ const 최종제출 = () => {
};
return (
-
+
@@ -111,6 +111,7 @@ const Styled최종제출 = styled.div`
${flex({ alignItems: 'center', justifyContent: 'space-between' })}
width: 100%;
height: 100%;
+ padding: 58px 96px 0px;
`;
const ContentBox = styled.div`
diff --git "a/apps/user/src/app/form/\354\266\234\354\213\240\355\225\231\352\265\220\353\260\217\355\225\231\353\240\245/\354\266\234\354\213\240\355\225\231\352\265\220\353\260\217\355\225\231\353\240\245.tsx" "b/apps/user/src/app/form/\354\266\234\354\213\240\355\225\231\352\265\220\353\260\217\355\225\231\353\240\245/\354\266\234\354\213\240\355\225\231\352\265\220\353\260\217\355\225\231\353\240\245.tsx"
index d12757851..ab87eae29 100644
--- "a/apps/user/src/app/form/\354\266\234\354\213\240\355\225\231\352\265\220\353\260\217\355\225\231\353\240\245/\354\266\234\354\213\240\355\225\231\352\265\220\353\260\217\355\225\231\353\240\245.tsx"
+++ "b/apps/user/src/app/form/\354\266\234\354\213\240\355\225\231\352\265\220\353\260\217\355\225\231\353\240\245/\354\266\234\354\213\240\355\225\231\352\265\220\353\260\217\355\225\231\353\240\245.tsx"
@@ -1,7 +1,8 @@
import { FindSchoolModal, FormController } from '@/components/form';
import { FormLayout } from '@/layouts';
import { useFormValueStore } from '@/store';
-import { ButtonInput, Input, RadioGroup } from '@maru/ui';
+import { ButtonInput, Input, RadioGroup, Row } from '@maru/ui';
+import { flex } from '@maru/utils';
import { useOverlay } from '@toss/use-overlay';
import styled from 'styled-components';
import { useCTAButton, useInput } from './출신학교및학력.hooks';
@@ -30,7 +31,6 @@ const 출신학교및학력 = () => {
value={form.education.graduationType}
onChange={handle출신학교및학력DataChange}
/>
-
{
isError={form.education.schoolName.length > 20}
errorMessage="20자 이하여야 합니다."
/>
-
-
- 20}
- errorMessage="20자여야 합니다."
- width="100%"
- value={form.education.schoolLocation}
- onChange={handle출신학교및학력DataChange}
- />
-
- 11}
- errorMessage="11자 이하여야 합니다."
- />
- 20}
- errorMessage="20자 이하여야 합니다."
- />
- 11}
- errorMessage="11자 이하여야 합니다."
- />
+
+
+ 20}
+ errorMessage="20자여야 합니다."
+ width="100%"
+ value={form.education.schoolLocation}
+ onChange={handle출신학교및학력DataChange}
+ />
+
+
+
+ 11}
+ errorMessage="11자 이하여야 합니다."
+ />
+
+
+ 20}
+ errorMessage="20자 이하여야 합니다."
+ />
+ 11}
+ errorMessage="11자 이하여야 합니다."
+ />
+
{
export default 출신학교및학력;
const Styled출신학교및학력 = styled.div`
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 30px 48px;
+ ${flex({ flexDirection: 'column' })}
+ gap:30px;
+ width: 100%;
+ height: 100%;
`;
diff --git a/apps/user/src/app/login/login.hooks.ts b/apps/user/src/app/login/login.hooks.ts
index 98e529008..a680c726c 100644
--- a/apps/user/src/app/login/login.hooks.ts
+++ b/apps/user/src/app/login/login.hooks.ts
@@ -31,12 +31,8 @@ export const useInput = () => {
export const useCTAButton = () => {
const router = useRouter();
- const handleGoSingUpPageButtonClick = () => {
- router.push(ROUTES.SIGNUP);
- };
-
const handleGoMainPageButtonClick = () => {
router.push(ROUTES.MAIN);
};
- return { handleGoSingUpPageButtonClick, handleGoMainPageButtonClick };
+ return { handleGoMainPageButtonClick };
};
diff --git a/apps/user/src/app/login/page.tsx b/apps/user/src/app/login/page.tsx
index 5fc85d4f6..60a55a9d0 100644
--- a/apps/user/src/app/login/page.tsx
+++ b/apps/user/src/app/login/page.tsx
@@ -1,16 +1,18 @@
'use client';
+import { ROUTES } from '@/constants/common/constant';
import { AppLayout } from '@/layouts';
import { IconArrowRight } from '@maru/icon';
import { color, font } from '@maru/theme';
import { Button, Column, Input, PreviewInput } from '@maru/ui';
import { flex } from '@maru/utils';
import Image from 'next/image';
+import Link from 'next/link';
import styled from 'styled-components';
import { useCTAButton, useInput, useLoginAction } from './login.hooks';
const LoginPage = () => {
- const { handleGoSingUpPageButtonClick, handleGoMainPageButtonClick } = useCTAButton();
+ const { handleGoMainPageButtonClick } = useCTAButton();
const { loginUserData, handleLoginUserDataChange } = useInput();
const { handleLoginButtonClick } = useLoginAction(loginUserData);
@@ -18,7 +20,12 @@ const LoginPage = () => {
-
+
{
height={70}
alt="logo"
/>
-
-
+
+
{
onChange={handleLoginUserDataChange}
/>
-
+
-
+
비밀번호 찾기
-
+
-
+
회원이 아니신가요?
-
- 회원가입
-
-
-
+ 회원가입
+
+
@@ -68,7 +73,7 @@ const LoginPage = () => {
export default LoginPage;
const StyledLoginPage = styled.div`
- ${flex({ justifyContent: 'center' })}
+ ${flex({ justifyContent: 'center', alignItems: 'center' })};
width: 100%;
height: 100vh;
`;
@@ -81,16 +86,9 @@ const LoginBox = styled.div`
background-color: ${color.white};
`;
-const LoginBoxWrap = styled.div`
- ${flex({ flexDirection: 'column', alignItems: 'center' })}
- gap: 56px;
- width: 446px;
-`;
-
-const GoFindPasswordPageButton = styled.a`
+const FindPasswordLink = styled(Link)`
${font.p2}
color: ${color.gray500};
- cursor: pointer;
${flex({ alignItems: 'center' })}
&:hover {
text-decoration-line: underline;
@@ -98,17 +96,16 @@ const GoFindPasswordPageButton = styled.a`
}
`;
-const GoSignUpPageButtonBox = styled.div`
+const SignUpLinkBox = styled.div`
${font.p2}
color: ${color.gray500};
${flex({ alignItems: 'center' })}
gap: 8px;
`;
-const GoSignUpPageButton = styled.a`
+const SignUpLink = styled(Link)`
${font.p2}
color: ${color.gray500};
text-decoration-line: underline;
text-decoration-color: ${color.gray500};
- cursor: pointer;
`;
diff --git a/apps/user/src/app/mobile/page.tsx b/apps/user/src/app/mobile/page.tsx
index f24d6af58..ec721e67a 100644
--- a/apps/user/src/app/mobile/page.tsx
+++ b/apps/user/src/app/mobile/page.tsx
@@ -37,6 +37,5 @@ const StyledMobilPage = styled.div`
${flex({ flexDirection: 'column', alignItems: 'center' })};
padding-top: 200px;
gap: 36px;
- width: 100%;
height: 100%;
`;
diff --git a/apps/user/src/app/notice/[id]/page.tsx b/apps/user/src/app/notice/[id]/page.tsx
index dafae8e5c..aab8db769 100644
--- a/apps/user/src/app/notice/[id]/page.tsx
+++ b/apps/user/src/app/notice/[id]/page.tsx
@@ -6,9 +6,9 @@ import { ROUTES } from '@/constants/common/constant';
import { AppLayout } from '@/layouts';
import { IconArrowLeft } from '@maru/icon';
import { color } from '@maru/theme';
-import { Link, Text } from '@maru/ui';
+import { Text } from '@maru/ui';
import { flex } from '@maru/utils';
-import { useRouter } from 'next/navigation';
+import Link from 'next/link';
import { Suspense } from 'react';
import styled from 'styled-components';
@@ -17,17 +17,15 @@ interface Props {
}
const NoticeDetailPage = ({ params: { id } }: Props) => {
- const router = useRouter();
-
return (
-
+
- router.push(ROUTES.NOTICE)} gap="2px">
+
공지사항
-
+
}>
@@ -43,5 +41,13 @@ const StyledNoticeDetailPage = styled.div`
${flex({ flexDirection: 'column' })}
gap: 36px;
width: 100%;
+ max-width: 1240px;
height: 100%;
+ margin: 0 auto;
+ padding: 52px 204px 240px;
+`;
+
+const BackLink = styled(Link)`
+ ${flex({ alignItems: 'center' })};
+ gap: 8px;
`;
diff --git a/apps/user/src/app/notice/page.tsx b/apps/user/src/app/notice/page.tsx
index c273d50e8..50a003eb7 100644
--- a/apps/user/src/app/notice/page.tsx
+++ b/apps/user/src/app/notice/page.tsx
@@ -11,7 +11,7 @@ import styled from 'styled-components';
const NoticePage = () => {
return (
-
+
공지사항
@@ -31,5 +31,8 @@ const StyledNoticePage = styled.div`
${flex({ flexDirection: 'column' })}
gap: 48px;
width: 100%;
+ max-width: 1240px;
height: 100%;
+ margin: 0 auto;
+ padding: 82px 204px 240px;
`;
diff --git a/apps/user/src/app/page.tsx b/apps/user/src/app/page.tsx
index ba34c778b..0805c3089 100644
--- a/apps/user/src/app/page.tsx
+++ b/apps/user/src/app/page.tsx
@@ -1,6 +1,14 @@
'use client';
-import { Dday, Faq, Notice, Schedule } from '@/components/main';
+import {
+ ApplicationBox,
+ Dday,
+ Faq,
+ GuidelineBox,
+ Notice,
+ Schedule,
+ SimulatorBox,
+} from '@/components/main';
import { AppLayout } from '@/layouts';
import { Row } from '@maru/ui';
import { flex } from '@maru/utils';
@@ -12,12 +20,17 @@ if (process.env.NODE_ENV === 'development') {
const MainPage = () => {
return (
-
+
+
+
+
+
+
@@ -31,8 +44,6 @@ export default MainPage;
const StyledMainPage = styled.div`
${flex({ flexDirection: 'column', alignItems: 'center' })};
- padding-bottom: 227px;
- gap: 60px;
- width: 100%;
- height: 100%;
+ padding: 52px 96px 240px;
+ gap: 80px;
`;
diff --git a/apps/user/src/app/result/final/page.tsx b/apps/user/src/app/result/final/page.tsx
index c59eba0d6..36f9bdd92 100644
--- a/apps/user/src/app/result/final/page.tsx
+++ b/apps/user/src/app/result/final/page.tsx
@@ -1,14 +1,14 @@
'use client';
+import { FinalResultTable, ResultMain } from '@/components/result';
import { AppLayout } from '@/layouts';
+import { ResultStep } from '@/types/result/client';
import { color } from '@maru/theme';
import { Column, Text } from '@maru/ui';
import { flex } from '@maru/utils';
import { SwitchCase } from '@toss/react';
-import { ResultStep } from '@/types/result/client';
-import styled from 'styled-components';
import { useState } from 'react';
-import { ResultMain, FinalResultTable } from '@/components/result';
+import styled from 'styled-components';
const FinalResultPage = () => {
const [ResultStep, setResultStep] = useState('MAIN');
diff --git a/apps/user/src/app/result/first/page.tsx b/apps/user/src/app/result/first/page.tsx
index e2b3ed016..0f75b8601 100644
--- a/apps/user/src/app/result/first/page.tsx
+++ b/apps/user/src/app/result/first/page.tsx
@@ -1,14 +1,14 @@
'use client';
+import { FirstResultTable, ResultMain } from '@/components/result';
import { AppLayout } from '@/layouts';
+import { ResultStep } from '@/types/result/client';
import { color } from '@maru/theme';
import { Column, Text } from '@maru/ui';
import { flex } from '@maru/utils';
import { SwitchCase } from '@toss/react';
-import { ResultStep } from '@/types/result/client';
-import styled from 'styled-components';
import { useState } from 'react';
-import { ResultMain, FirstResultTable } from '@/components/result';
+import styled from 'styled-components';
const FirstResultPage = () => {
const [ResultStep, setResultStep] = useState('MAIN');
diff --git a/apps/user/src/app/grade-simulation/page.tsx b/apps/user/src/app/score-simulation/page.tsx
similarity index 87%
rename from apps/user/src/app/grade-simulation/page.tsx
rename to apps/user/src/app/score-simulation/page.tsx
index 22ee2e899..d05f4fb92 100644
--- a/apps/user/src/app/grade-simulation/page.tsx
+++ b/apps/user/src/app/score-simulation/page.tsx
@@ -10,18 +10,18 @@ import {
import { FIELD_DATA } from '@/constants/form/data';
import { AppLayout } from '@/layouts';
import { color } from '@maru/theme';
-import { Column, Text, UnderLineButton } from '@maru/ui';
+import { Column, Text, UnderlineButton } from '@maru/ui';
import { flex } from '@maru/utils';
import { SwitchCase } from '@toss/react';
import { useState } from 'react';
import styled from 'styled-components';
-const GradeSimulation = () => {
+const ScoreSimulation = () => {
const [fieldStep, setFieldStep] = useState('성적 입력');
return (
-
+
성적 모의 계산
@@ -42,12 +42,12 @@ const GradeSimulation = () => {
{FIELD_DATA.map((item, index) => (
- setFieldStep(item)}>
{item}
-
+
))}
{
defaultComponent={}
/>
-
+
);
};
-export default GradeSimulation;
+export default ScoreSimulation;
-const GradeSimulationPage = styled.div`
+const ScoreSimulationPage = styled.div`
${flex({ flexDirection: 'column' })};
gap: 48px;
width: 816px;
- margin: 82px auto 93px;
+ padding: 82px 0 172px;
+ margin: 0 auto;
`;
const NavigationBar = styled.div`
diff --git a/apps/user/src/app/signup/page.tsx b/apps/user/src/app/signup/page.tsx
index b2419728a..24899cb6a 100644
--- a/apps/user/src/app/signup/page.tsx
+++ b/apps/user/src/app/signup/page.tsx
@@ -14,8 +14,13 @@ const SignUpPage = () => {
const [termsAgree, setTermsAgree] = useState(false);
const { startTimer, timerTime, setTimerTime } = useTimer();
const { joinUserData, handleJoinUserDataChange } = useInput();
- const { handleVerificationButtonClick, isButtonDisabled, isVerification } =
- useVerificationAction(joinUserData.phoneNumber);
+ const {
+ handleRequestVerificationButtonClick,
+ handleVerificationButtonClick,
+ isRequestVerificationDisabled,
+ isVerificationDisabled,
+ isVerification,
+ } = useVerificationAction(joinUserData);
const { handleJoinButtonClick } = useJoinAction(joinUserData, termsAgree);
return (
@@ -45,10 +50,10 @@ const SignUpPage = () => {
label="전화번호 인증"
buttonText={isVerification ? '재전송' : '인증'}
onClick={() => {
- handleVerificationButtonClick();
+ handleRequestVerificationButtonClick();
startTimer();
}}
- enabled={isButtonDisabled}
+ enabled={isRequestVerificationDisabled}
type="phoneNumber"
placeholder="- 없이 입력해주세요"
width="100%"
@@ -63,9 +68,12 @@ const SignUpPage = () => {
maxLength={6}
name="code"
onChange={handleJoinUserDataChange}
- timerTime={timerTime}
+ onClick={handleVerificationButtonClick}
+ timerTime={isVerificationDisabled ? 0 : timerTime}
setTimerTime={setTimerTime}
isError={joinUserData.code.length < 6}
+ buttonText="인증번호 확인"
+ enabled={isVerificationDisabled}
errorMessage="발송된 전화번호의 인증번호를 입력해주세요."
/>
)}
@@ -101,7 +109,7 @@ export default SignUpPage;
const StyledSignUpPage = styled.div`
${flex({ justifyContent: 'space-between', alignItems: 'center' })}
width: 100%;
- height: 100%;
+ height: 100vh;
background-color: ${color.gray100};
`;
@@ -118,5 +126,6 @@ const SignUpBox = styled.div`
${flex({ flexDirection: 'column' })};
gap: 36px;
width: 446px;
+ height: fit-content;
margin: 120px 0;
`;
diff --git a/apps/user/src/app/signup/signup.hooks.ts b/apps/user/src/app/signup/signup.hooks.ts
index 4e5ec4dd9..240bf11b8 100644
--- a/apps/user/src/app/signup/signup.hooks.ts
+++ b/apps/user/src/app/signup/signup.hooks.ts
@@ -1,9 +1,13 @@
-import { useJoinUserMutation, useVerificationMutation } from '@/services/auth/mutations';
-import { PostJoinAuthReq } from '@/types/auth/remote';
+import {
+ useJoinUserMutation,
+ useRequestVerificationMutation,
+ useVerificationMutation,
+} from '@/services/auth/mutations';
+import { Join } from '@/types/auth/client';
import { useBooleanState } from '@maru/hooks';
import { ChangeEventHandler, useState } from 'react';
-export const useJoinAction = (joinUserData: PostJoinAuthReq, termsAgree: boolean) => {
+export const useJoinAction = (joinUserData: Join, termsAgree: boolean) => {
const { joinUserMutate } = useJoinUserMutation(joinUserData);
const handleJoinButtonClick = () => {
@@ -26,25 +30,42 @@ export const useJoinAction = (joinUserData: PostJoinAuthReq, termsAgree: boolean
return { handleJoinButtonClick };
};
-export const useVerificationAction = (phoneNumber: string) => {
+export const useVerificationAction = (joinUserData: Join) => {
// 전화번호 요청을 보냈는가?
const { value: isVerification, setValue: setIsVerification } = useBooleanState(false);
// 전화번호 전송 활성화 비활성화
- const { value: isButtonDisabled, setValue: setIsButtonDisabled } = useBooleanState(false);
- const { requestVerificationMutate } = useVerificationMutation(phoneNumber);
+ const { value: isRequestVerificationDisabled, setValue: setIsRequestVerificationDisabled } =
+ useBooleanState(false);
+ // 전화번호 인증 확인 여부
+ const { value: isVerificationDisabled, setValue: setIsVerificationDisabled } =
+ useBooleanState(false);
- const handleVerificationButtonClick = () => {
+ const { verificationMutate } = useVerificationMutation(setIsVerificationDisabled);
+ const { requestVerificationMutate } = useRequestVerificationMutation(joinUserData.phoneNumber);
+
+ const handleRequestVerificationButtonClick = () => {
requestVerificationMutate();
- setIsButtonDisabled(true);
+ setIsRequestVerificationDisabled(true);
setIsVerification(true);
+ setIsVerificationDisabled(false);
// 5초뒤 비활성화를 풀어줌
setTimeout(() => {
- setIsButtonDisabled(false);
+ setIsRequestVerificationDisabled(false);
}, 7000);
};
- return { handleVerificationButtonClick, isButtonDisabled, isVerification };
+ const handleVerificationButtonClick = () => {
+ verificationMutate(joinUserData);
+ };
+
+ return {
+ handleRequestVerificationButtonClick,
+ handleVerificationButtonClick,
+ isRequestVerificationDisabled,
+ isVerificationDisabled,
+ isVerification,
+ };
};
export const useTimer = () => {
@@ -58,7 +79,7 @@ export const useTimer = () => {
};
export const useInput = () => {
- const [joinUserData, setJoinUserData] = useState({
+ const [joinUserData, setJoinUserData] = useState({
phoneNumber: '',
code: '',
name: '',
diff --git a/apps/user/src/components/common/Footer/Footer.tsx b/apps/user/src/components/common/Footer/Footer.tsx
index a1c75b9e2..a3588e881 100644
--- a/apps/user/src/components/common/Footer/Footer.tsx
+++ b/apps/user/src/components/common/Footer/Footer.tsx
@@ -1,83 +1,81 @@
import { ROUTES } from '@/constants/common/constant';
import { color, font } from '@maru/theme';
-import { Column, Link, Row, Text } from '@maru/ui';
+import { Column, Row, Text } from '@maru/ui';
import { flex } from '@maru/utils';
import Image from 'next/image';
-import { useRouter } from 'next/navigation';
+import Link from 'next/link';
import styled from 'styled-components';
const Footer = () => {
- const router = useRouter();
-
return (
-
-
-
-
-
- 주소: 부산광역시 강서구 가락대로 1393 봉림동 15 (46708)
-
-
- 교무실(입학처): 051-971-2153, Fax: 051-971-2061
+
+
+
+
+
+
+ 주소: 부산광역시 강서구 가락대로 1393 봉림동 15 (46708)
+
+
+ 교무실(입학처): 051-971-2153, Fax: 051-971-2061
+
+
+ 행정실:051-971-2152, Fax: 051-971-6325
+
+
+
+ Copyright © 밤돌이로 all rights reserved.
-
- 행정실:051-971-2152, Fax: 051-971-6325
-
-
-
- Copyright © 밤돌이로 all rights reserved.
-
-
-
-
-
-
-
- router.push(ROUTES.FORM)}>원서접수
- router.push(ROUTES.NOTICE)}>공지사항
- router.push(ROUTES.FAQ)}>자주묻는질문
- console.log('학교 소개 페이지')}>학교소개
-
-
- console.log('test')}>이용약관
- console.log('test')}>개인정보처리방침
- console.log('test')}>학교 홈페이지
-
-
-
-
+
+
+
+
+ 원서접수
+ 공지사항
+ 자주묻는질문
+ 학교소개
+
+
+ 이용약관
+ 개인정보처리방침
+ 학교 홈페이지
+
+
+
+
+
+
-
+
);
};
export default Footer;
-const StyledFooter = styled.div`
- ${flex({ justifyContent: 'space-between', alignItems: 'center' })}
+const StyledFooter = styled.footer`
background-color: ${color.gray100};
- height: 350px;
- width: 100%;
- padding: 40px 100px;
+ padding: 40px 96px 82px;
`;
-const InfoBox = styled.div`
- ${flex({ flexDirection: 'column' })}
- gap: 40px;
- width: 489px;
+const FooterBox = styled.div`
+ ${flex({ justifyContent: 'space-between', alignItems: 'center' })}
+ height: 350px;
+ max-width: 1248px;
+ width: 100%;
+ margin: 0 auto;
`;
const ContentBox = styled.div`
@@ -87,10 +85,7 @@ const ContentBox = styled.div`
padding-bottom: 20px;
`;
-const NavigationBox = styled.div`
- // @TODO Link 리팩토링하면서
+const DirectLink = styled(Link)`
${font.p3}
color: ${color.gray600};
- display: flex;
- gap: 132px;
`;
diff --git a/apps/user/src/components/common/Header/Header.tsx b/apps/user/src/components/common/Header/Header.tsx
index ee825dc0b..962e85f8e 100644
--- a/apps/user/src/components/common/Header/Header.tsx
+++ b/apps/user/src/components/common/Header/Header.tsx
@@ -1,8 +1,7 @@
import { ROUTES } from '@/constants/common/constant';
import { useUser } from '@/hooks';
import { color } from '@maru/theme';
-import { Button, Row, UnderLineButton } from '@maru/ui';
-import { flex } from '@maru/utils';
+import { Button, Row, UnderlineButton } from '@maru/ui';
import Image from 'next/image';
import { usePathname, useRouter } from 'next/navigation';
import styled from 'styled-components';
@@ -14,7 +13,7 @@ const NAVIGATION_DATA = [
},
{
name: '성적 모의 계산',
- route: ROUTES.GRADE_SIMULATION,
+ route: ROUTES.SCORE_SIMULATION,
},
{
name: '원서작성',
@@ -37,46 +36,52 @@ const Header = () => {
return (
-
-
+ router.push(ROUTES.MAIN)}
- alt="logo"
- />
- {isLoggedIn ? (
-
- ) : (
-
-
-
-
- )}
-
-
- {NAVIGATION_DATA.map(({ route, name }, index) => {
- return (
- router.push(route)}>
- {name}
-
- );
- })}
-
+ alignItems="center"
+ justifyContent="space-between">
+ router.push(ROUTES.MAIN)}
+ alt="logo"
+ />
+ {isLoggedIn ? (
+
+ ) : (
+
+
+
+
+ )}
+
+
+ {NAVIGATION_DATA.map(({ route, name }, index) => {
+ return (
+ router.push(route)}>
+ {name}
+
+ );
+ })}
+
+
);
};
@@ -84,22 +89,14 @@ const Header = () => {
export default Header;
const StyledHeader = styled.div`
- max-width: 1448px;
- height: 118px;
- background-color: ${color.white};
- margin: 0 auto;
- padding: 0px 100px;
- border-bottom: 1px solid ${color.gray200};
-`;
-
-const HeaderBar = styled.div`
- ${flex({ alignItems: 'center', justifyContent: 'space-between' })}
width: 100%;
+ height: 118px;
+ box-shadow: 0 1px 0 0 ${color.gray200};
`;
-const NavigationBar = styled.div`
- ${flex({ alignItems: 'center' })}
- width: 100%;
- height: 54px;
+const HeaderBox = styled.div`
+ max-width: 1448px;
+ height: 100%;
background-color: ${color.white};
+ margin: 0 auto;
`;
diff --git a/apps/user/src/components/common/Header/Profile/Profile.tsx b/apps/user/src/components/common/Header/Profile/Profile.tsx
index 52b0cf8f2..8b31d609e 100644
--- a/apps/user/src/components/common/Header/Profile/Profile.tsx
+++ b/apps/user/src/components/common/Header/Profile/Profile.tsx
@@ -36,7 +36,7 @@ const Profile = () => {
{userData.name}
- @{userData.phoneNumber.split('@')[0]}
+ @{userData.name}
-
- {noticeDetailData.content}
-
+
) : null;
};
@@ -45,3 +43,7 @@ const NoticeHeader = styled.div`
border-bottom: 1px solid ${color.gray300};
margin-bottom: 8px;
`;
+const Content = styled.div`
+ ${font.p2};
+ color: ${color.gray900};
+`;
diff --git a/apps/user/src/constants/common/constant.ts b/apps/user/src/constants/common/constant.ts
index 1746b4e84..2066efa4d 100644
--- a/apps/user/src/constants/common/constant.ts
+++ b/apps/user/src/constants/common/constant.ts
@@ -21,7 +21,7 @@ export const ROUTES = {
SIGNUP: '/signup',
FIRST_RESULT: '/result/first',
FINAL_RESULT: '/result/first',
- GRADE_SIMULATION: '/grade-simulation',
+ SCORE_SIMULATION: '/score-simulation',
} as const;
export const TOKEN = {
diff --git a/apps/user/src/layouts/AppLayout.tsx b/apps/user/src/layouts/AppLayout.tsx
index b63014b75..1bf84df21 100644
--- a/apps/user/src/layouts/AppLayout.tsx
+++ b/apps/user/src/layouts/AppLayout.tsx
@@ -8,21 +8,19 @@ interface Props {
header?: boolean;
footer?: boolean;
children: ReactNode;
- backgroundColor?: string;
- style?: CSSProperties;
+ backgroundColor?: CSSProperties['backgroundColor'];
}
const AppLayout = ({
children,
backgroundColor = color.white,
- style,
header = false,
footer = false,
}: Props) => {
return (
<>
{header && }
- {children}
+ {children}
{footer && }
>
);
@@ -32,6 +30,5 @@ export default AppLayout;
const StyledAppLayout = styled.section`
width: 100%;
- height: 100%;
- min-height: 100vh;
+ min-height: calc(100vh - 118px);
`;
diff --git a/apps/user/src/layouts/FormLayout.tsx b/apps/user/src/layouts/FormLayout.tsx
index 3a17674d3..95812ae72 100644
--- a/apps/user/src/layouts/FormLayout.tsx
+++ b/apps/user/src/layouts/FormLayout.tsx
@@ -1,5 +1,5 @@
import { Header } from '@/components/common/';
-import { ProgressBar } from '@/components/form';
+import { ProgressSteps } from '@/components/form';
import { color } from '@maru/theme';
import { Text } from '@maru/ui';
import { ReactNode } from 'react';
@@ -15,7 +15,7 @@ const FormLayout = ({ children, title }: Props) => {
<>
-
+
{title}
@@ -31,8 +31,6 @@ export default FormLayout;
const StyledFormLayout = styled.section`
width: 100%;
- height: 100%;
- min-height: 100vh;
margin-bottom: 240px;
background-color: ${color.white};
`;
diff --git a/apps/user/src/services/auth/api.ts b/apps/user/src/services/auth/api.ts
index 207a4e6ae..514d890c4 100644
--- a/apps/user/src/services/auth/api.ts
+++ b/apps/user/src/services/auth/api.ts
@@ -1,22 +1,27 @@
import { maru } from '@/apis/instance/instance';
import { authorization } from '@/apis/token';
-import { PostJoinAuthReq, PostLoginAuthReq } from '@/types/auth/remote';
+import { PatchVerificationReq, PostJoinAuthReq, PostLoginAuthReq } from '@/types/auth/remote';
export const postLoginUser = async ({ phoneNumber, password }: PostLoginAuthReq) => {
const { data } = await maru.post('/auth', { phoneNumber, password });
return data;
};
-export const postJoinUser = async ({ phoneNumber, name, code, password }: PostJoinAuthReq) => {
- const { data } = await maru.post('/user', { phoneNumber, name, code, password });
+export const postJoinUser = async ({ phoneNumber, name, password }: PostJoinAuthReq) => {
+ const { data } = await maru.post('/user', { phoneNumber, name, password });
return data;
};
-export const postVerification = async (phoneNumber: string) => {
+export const postRequestVerification = async (phoneNumber: string) => {
const { data } = await maru.post('/user/verification', { phoneNumber });
return data;
};
+export const patchVerification = async ({ code, phoneNumber }: PatchVerificationReq) => {
+ const { data } = await maru.patch('/user/verification', { code, phoneNumber });
+ return data;
+};
+
export const deleteLogoutUser = async () => {
await maru.delete('/auth', authorization());
};
diff --git a/apps/user/src/services/auth/mutations.ts b/apps/user/src/services/auth/mutations.ts
index 5246f9017..6cda6367e 100644
--- a/apps/user/src/services/auth/mutations.ts
+++ b/apps/user/src/services/auth/mutations.ts
@@ -1,11 +1,18 @@
import { Storage } from '@/apis/storage/storage';
import { ROUTES, TOKEN } from '@/constants/common/constant';
import { useApiError } from '@/hooks';
-import { PostJoinAuthReq, PostLoginAuthReq } from '@/types/auth/remote';
+import { PatchVerificationReq, PostJoinAuthReq, PostLoginAuthReq } from '@/types/auth/remote';
import { useMutation } from '@tanstack/react-query';
import { AxiosResponse } from 'axios';
import { useRouter } from 'next/navigation';
-import { deleteLogoutUser, postJoinUser, postLoginUser, postVerification } from './api';
+import { Dispatch, SetStateAction } from 'react';
+import {
+ deleteLogoutUser,
+ patchVerification,
+ postJoinUser,
+ postLoginUser,
+ postRequestVerification,
+} from './api';
export const useLoginUserMutation = ({ phoneNumber, password }: PostLoginAuthReq) => {
const router = useRouter();
@@ -25,12 +32,12 @@ export const useLoginUserMutation = ({ phoneNumber, password }: PostLoginAuthReq
return { loginUserMutate, ...restMutation };
};
-export const useJoinUserMutation = ({ phoneNumber, name, code, password }: PostJoinAuthReq) => {
+export const useJoinUserMutation = ({ phoneNumber, name, password }: PostJoinAuthReq) => {
const router = useRouter();
const { handleError } = useApiError();
const { mutate: joinUserMutate, ...restMutation } = useMutation({
- mutationFn: () => postJoinUser({ phoneNumber, name, code, password }),
+ mutationFn: () => postJoinUser({ phoneNumber, name, password }),
onSuccess: () => {
alert('회원가입 성공');
router.push(ROUTES.LOGIN);
@@ -41,17 +48,34 @@ export const useJoinUserMutation = ({ phoneNumber, name, code, password }: PostJ
return { joinUserMutate, ...restMutation };
};
-export const useVerificationMutation = (phoneNumber: string) => {
+export const useRequestVerificationMutation = (phoneNumber: string) => {
const { handleError } = useApiError();
const { mutate: requestVerificationMutate, ...restMutation } = useMutation({
- mutationFn: () => postVerification(phoneNumber),
+ mutationFn: () => postRequestVerification(phoneNumber),
onError: handleError,
});
return { requestVerificationMutate, ...restMutation };
};
+export const useVerificationMutation = (
+ setIsVerificationDisabled: Dispatch>,
+) => {
+ const { handleError } = useApiError();
+
+ const { mutate: verificationMutate, ...restMutation } = useMutation({
+ mutationFn: ({ code, phoneNumber }: PatchVerificationReq) =>
+ patchVerification({ code, phoneNumber }),
+ onSuccess: () => {
+ setIsVerificationDisabled(true);
+ },
+ onError: handleError,
+ });
+
+ return { verificationMutate, ...restMutation };
+};
+
export const useLogoutUserMutation = () => {
const { mutate: logoutUserMutate, ...restMutation } = useMutation({
mutationFn: deleteLogoutUser,
diff --git a/apps/user/src/types/auth/client.ts b/apps/user/src/types/auth/client.ts
new file mode 100644
index 000000000..2177eb097
--- /dev/null
+++ b/apps/user/src/types/auth/client.ts
@@ -0,0 +1,7 @@
+export interface Join {
+ phoneNumber: string;
+ code: string;
+ name: string;
+ password: string;
+ password_confirm?: string;
+}
diff --git a/apps/user/src/types/auth/remote.ts b/apps/user/src/types/auth/remote.ts
index 3b7d64d5b..27bd5a730 100644
--- a/apps/user/src/types/auth/remote.ts
+++ b/apps/user/src/types/auth/remote.ts
@@ -5,8 +5,11 @@ export interface PostLoginAuthReq {
export interface PostJoinAuthReq {
phoneNumber: string;
- code: string;
name: string;
password: string;
- password_confirm?: string;
+}
+
+export interface PatchVerificationReq {
+ code: string;
+ phoneNumber: string;
}
diff --git a/apps/user/src/types/form/client.ts b/apps/user/src/types/form/client.ts
index 879b7f946..51b96ecf0 100644
--- a/apps/user/src/types/form/client.ts
+++ b/apps/user/src/types/form/client.ts
@@ -123,3 +123,9 @@ export interface FormStatus {
status: 'APPROVED' | 'REJECTED' | 'RECEIVED' | 'SUBMITTED' | 'FINAL_SUBMITTED';
type: FormType;
}
+
+export interface School {
+ name: string;
+ location: string;
+ code: string;
+}
diff --git a/docs/README.md b/docs/README.md
deleted file mode 100644
index 6c2350537..000000000
--- a/docs/README.md
+++ /dev/null
@@ -1 +0,0 @@
-## 프로젝트에 대한 설명, 컨벤션을 한번 더 정리해놓습니다.
diff --git a/packages/maru-icon/index.ts b/packages/maru-icon/index.ts
index 8ade07fbb..b7611368b 100644
--- a/packages/maru-icon/index.ts
+++ b/packages/maru-icon/index.ts
@@ -3,15 +3,17 @@ export { default as IconAnswer } from './src/IconAnswer';
export { default as IconArrowBottom } from './src/IconArrowBottom';
export { default as IconArrowDropdown } from './src/IconArrowDropdown';
export { default as IconArrowLeft } from './src/IconArrowLeft';
+export { default as IconArrowOutward } from './src/IconArrowOutward';
export { default as IconArrowRight } from './src/IconArrowRight';
export { default as IconArrowTop } from './src/IconArrowTop';
export { default as IconCancelCircle } from './src/IconCancelCircle';
export { default as IconCheck } from './src/IconCheck';
export { default as IconCheckCircle } from './src/IconCheckCircle';
export { default as IconClose } from './src/IconClose';
+export { default as IconError } from './src/IconError';
export { default as IconFaq } from './src/IconFaq';
+export { default as IconFunction } from './src/IconFunction';
export { default as IconInvisibleEye } from './src/IconInvisibleEye';
export { default as IconSearch } from './src/IconSearch';
export { default as IconShortcuts } from './src/IconShortcuts';
export { default as IconVisibleEye } from './src/IconVisibleEye';
-export { default as IconError } from './src/IconError';
diff --git a/packages/maru-icon/src/IconArrowOutward.tsx b/packages/maru-icon/src/IconArrowOutward.tsx
new file mode 100644
index 000000000..54658275e
--- /dev/null
+++ b/packages/maru-icon/src/IconArrowOutward.tsx
@@ -0,0 +1,15 @@
+import type { SVGProps } from 'react';
+import React from 'react';
+
+const IconArrowOutward = (props: SVGProps) => {
+ return (
+
+ );
+};
+
+export default IconArrowOutward;
diff --git a/packages/maru-icon/src/IconFunction.tsx b/packages/maru-icon/src/IconFunction.tsx
new file mode 100644
index 000000000..ec89dc661
--- /dev/null
+++ b/packages/maru-icon/src/IconFunction.tsx
@@ -0,0 +1,15 @@
+import type { SVGProps } from 'react';
+import React from 'react';
+
+const IconFunction = (props: SVGProps) => {
+ return (
+
+ );
+};
+
+export default IconFunction;
diff --git a/packages/maru-theme/src/font.ts b/packages/maru-theme/src/font.ts
index a4548c482..984fb6576 100644
--- a/packages/maru-theme/src/font.ts
+++ b/packages/maru-theme/src/font.ts
@@ -22,7 +22,7 @@ const font = {
H2: fontGenerator(700, 1.75, 140, 0),
H3: fontGenerator(600, 1.5, 140, 0.15),
H4: fontGenerator(600, 1.25, 140, 0.15),
- H5: fontGenerator(600, 1.125, 140, 0.15),
+ H5: fontGenerator(500, 1.125, 140, 0.15),
p1: fontGenerator(400, 1.125, 140, -0.15),
p2: fontGenerator(400, 1, 160, 0),
@@ -34,12 +34,7 @@ const font = {
caption: fontGenerator(400, 0.75, 140, 0),
context: fontGenerator(500, 1, 130, 0),
- code: css`
- font-family: 'IBM Plex Mono';
- font-weight: 400;
- font-size: 1rem;
- line-height: 130%;
- `,
+ code: fontGenerator(400, 1, 130, 0),
};
export default font;
diff --git a/packages/maru-theme/src/global.ts b/packages/maru-theme/src/global.ts
index 5d7625a2c..638fb1ef8 100644
--- a/packages/maru-theme/src/global.ts
+++ b/packages/maru-theme/src/global.ts
@@ -1,5 +1,6 @@
import { createGlobalStyle } from 'styled-components';
import { reset } from 'styled-reset';
+import color from './color';
const GlobalStyle = createGlobalStyle`
${reset}
@@ -51,6 +52,11 @@ button {
padding: 0;
cursor: pointer;
}
+
+.link {
+ color: ${color.maruDefault};
+ text-decoration: underline;
+}
`;
export default GlobalStyle;
diff --git a/packages/maru-ui/index.ts b/packages/maru-ui/index.ts
index e762bb334..4e32f23ad 100644
--- a/packages/maru-ui/index.ts
+++ b/packages/maru-ui/index.ts
@@ -1,4 +1,8 @@
export { default as Button } from './src/Button/Button';
+export type { ButtonOption } from './src/Button/Button.type';
+export { default as UnderlineButton } from './src/Button/UnderlineButton';
+export { default as CheckBox } from './src/CheckBox/CheckBox';
+export { default as Confirm } from './src/Confirm/Confirm';
export { default as Dropdown } from './src/Dropdown/Dropdown';
export { default as Column } from './src/Flex/Column';
export { default as Row } from './src/Flex/Row';
@@ -8,17 +12,10 @@ export { default as NumberInput } from './src/Input/NumberInput';
export { default as PreviewInput } from './src/Input/PreviewInput';
export { default as SearchInput } from './src/Input/SearchInput';
export { default as TimeLimitInput } from './src/Input/TimeLimitInput';
-export { default as Link } from './src/Link/Link';
+export { default as Modal } from './src/Modal/Modal';
export { default as Radio } from './src/Radio/Radio';
export { default as RadioGroup } from './src/RadioGroup/RadioGroup';
export { default as Td } from './src/Table/Td';
export { default as Th } from './src/Table/Th';
-export { default as Textarea } from './src/Textarea/Textarea';
-export { default as CheckBox } from './src/CheckBox/CheckBox';
-export { default as UnderLineButton } from './src/Button/UnderLineButton';
-export { default as Confirm } from './src/Confirm/Confirm';
-export { default as Modal } from './src/Modal/Modal';
export { default as Text } from './src/Text/Text';
-
-// type
-export type { ButtonOption } from './src/Button/Button.type';
+export { default as Textarea } from './src/Textarea/Textarea';
diff --git a/packages/maru-ui/src/Button/UnderLineButton.tsx b/packages/maru-ui/src/Button/UnderlineButton.tsx
similarity index 80%
rename from packages/maru-ui/src/Button/UnderLineButton.tsx
rename to packages/maru-ui/src/Button/UnderlineButton.tsx
index a17b7b86d..2e08ee6a9 100644
--- a/packages/maru-ui/src/Button/UnderLineButton.tsx
+++ b/packages/maru-ui/src/Button/UnderlineButton.tsx
@@ -7,15 +7,15 @@ interface Props extends ButtonHTMLAttributes {
active: boolean;
}
-const UnderLineButton = ({ children, onClick, active }: Props) => {
+const UnderlineButton = ({ children, onClick, active }: Props) => {
return (
-
+
{children}
-
+
);
};
-export default UnderLineButton;
+export default UnderlineButton;
const HoverStateBox = styled.div`
${font.btn1}
@@ -23,7 +23,7 @@ const HoverStateBox = styled.div`
border-radius: 6px;
`;
-const StyledUnderLineButton = styled.button<{ $active: boolean }>`
+const StyledUnderlineButton = styled.button<{ $active: boolean }>`
padding: 0px 4px;
height: 54px;
position: relative;
diff --git a/packages/maru-ui/src/Input/Input.tsx b/packages/maru-ui/src/Input/Input.tsx
index c8aca2586..d890d8186 100644
--- a/packages/maru-ui/src/Input/Input.tsx
+++ b/packages/maru-ui/src/Input/Input.tsx
@@ -5,7 +5,7 @@ import ConditionalMessage from './ConditionalMessage';
import { InputProps } from './Input.type';
const Input = ({
- width = '320px',
+ width = 320,
label,
placeholder,
type = 'text',
diff --git a/packages/maru-ui/src/Input/Input.type.ts b/packages/maru-ui/src/Input/Input.type.ts
index ae418d9c9..4cc800c2f 100644
--- a/packages/maru-ui/src/Input/Input.type.ts
+++ b/packages/maru-ui/src/Input/Input.type.ts
@@ -1,7 +1,7 @@
import { CSSProperties, InputHTMLAttributes } from 'react';
export interface InputProps extends InputHTMLAttributes {
- width?: string;
+ width?: CSSProperties['width'];
label?: string;
errorMessage?: string;
message?: string;
diff --git a/packages/maru-ui/src/Input/NumberInput.tsx b/packages/maru-ui/src/Input/NumberInput.tsx
index 2dac61250..acb9c65cd 100644
--- a/packages/maru-ui/src/Input/NumberInput.tsx
+++ b/packages/maru-ui/src/Input/NumberInput.tsx
@@ -1,21 +1,32 @@
import { color, font } from '@maru/theme';
+import { useRef } from 'react';
import { css, styled } from 'styled-components';
import { InputProps } from './Input.type';
const NumberInput = ({
name,
- width = '80px',
+ width = 80,
textAlign = 'center',
onChange,
placeholder,
value = 0,
isError = false,
}: InputProps) => {
+ const numberInputRef = useRef(null);
+
+ const handleSelectAllClick = () => {
+ if (numberInputRef.current) {
+ numberInputRef.current.select();
+ }
+ };
+
return (
>;
+ buttonText: string;
+ enabled?: boolean;
+ onClick: () => void;
}
const TimeLimitInput = ({
- width = '320px',
+ width = 320,
name,
label,
message,
@@ -23,6 +27,9 @@ const TimeLimitInput = ({
setTimerTime,
isError = false,
errorMessage,
+ onClick,
+ buttonText,
+ enabled = false,
}: TimeLimitInputProps) => {
useInterval(() => {
setTimerTime((prev) => prev - 1);
@@ -34,14 +41,17 @@ const TimeLimitInput = ({
return (
{label &&
}
-
+
{formatTime(timerTime)}
-
+
+
);
@@ -53,6 +63,7 @@ const StyledTimeLimitInput = styled.div<{ $isError: boolean }>`
${flex({ alignItems: 'center', justifyContent: 'center' })}
gap: 10px;
height: 48px;
+ width: 100%;
padding: 10px 16px;
background-color: ${color.white};
border: 1px solid ${color.gray400};
@@ -90,6 +101,23 @@ const Input = styled.input`
}
`;
+export const Button = styled.button<{ enabled: boolean }>`
+ ${font.btn2};
+ color: ${color.white};
+ background-color: ${(props) => (props.enabled ? color.gray400 : color.maruDefault)};
+ pointer-events: ${(props) => props.enabled && 'none'};
+ ${flex({ alignItems: 'center', justifyContent: 'center' })}
+ border-radius: 6px;
+ height: 48px;
+ padding: 10px 20px;
+ flex-shrink: 0;
+
+ &:hover {
+ background-color: ${(props) => (props.enabled ? color.gray400 : color.maruHoverd)};
+ cursor: ${(props) => (props.enabled ? 'default' : 'pointer')};
+ }
+`;
+
const Label = styled.p`
${font.context}
color: ${color.gray700};
diff --git a/packages/maru-ui/src/Link/Link.tsx b/packages/maru-ui/src/Link/Link.tsx
deleted file mode 100644
index 24a6d5db5..000000000
--- a/packages/maru-ui/src/Link/Link.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { flex } from '@maru/utils';
-import { CSSProperties, ReactNode } from 'react';
-import styled from 'styled-components';
-
-interface Props {
- children: ReactNode;
- onClick: () => void;
- gap?: CSSProperties['gap'];
-}
-
-const Link = ({ children, gap, onClick }: Props) => {
- return (
-
- {children}
-
- );
-};
-
-export default Link;
-
-const StyledLink = styled.a`
- ${flex({ alignItems: 'center' })}
- cursor: pointer;
-`;
diff --git a/packages/maru-ui/src/RadioGroup/RadioGroup.tsx b/packages/maru-ui/src/RadioGroup/RadioGroup.tsx
index 52080e68a..ef9e5597f 100644
--- a/packages/maru-ui/src/RadioGroup/RadioGroup.tsx
+++ b/packages/maru-ui/src/RadioGroup/RadioGroup.tsx
@@ -4,9 +4,14 @@ import styled from 'styled-components';
import Row from '../Flex/Row';
import Radio from '../Radio/Radio';
+interface Radio {
+ value: string;
+ label: string;
+}
+
interface Props {
label: string;
- list: { value?: string; label: string; checked?: boolean }[] | string[];
+ list: Radio[] | string[];
name: string;
value: string;
onChange: ChangeEventHandler;
@@ -14,41 +19,37 @@ interface Props {
const RadioGroup = ({ label, list, name, value, onChange }: Props) => {
return (
-
+
-
+
{list.map((item, index) => {
+ const isString = typeof item === 'string';
+ const radioLabel = isString ? item : item.label;
+ const radioValue = isString ? item : item.value;
+ const isChecked = isString ? item === value : value === item.value;
+
return (
-
+
+
+ {radioLabel}
+
);
})}
-
-
+
+
);
};
export default RadioGroup;
-const RadioListBox = styled.div`
- display: flex;
+const StyledRadioGroup = styled.div`
+ width: 100%;
+ height: 100%;
`;
const Label = styled.p`
@@ -61,5 +62,4 @@ const RadioLabel = styled.p`
${font.p2};
color: ${color.gray900};
margin-right: 40px;
- height: 26px;
`;
diff --git a/packages/maru-ui/src/Text/Text.tsx b/packages/maru-ui/src/Text/Text.tsx
index fe4055b4a..da19b07b5 100644
--- a/packages/maru-ui/src/Text/Text.tsx
+++ b/packages/maru-ui/src/Text/Text.tsx
@@ -6,7 +6,7 @@ type Font = keyof typeof font;
interface Props extends HTMLAttributes {
children: ReactNode;
- color?: string;
+ color?: CSSProperties['color'];
fontType: Font;
width?: CSSProperties['width'];
textAlign?: CSSProperties['textAlign'];
diff --git a/packages/maru-utils/functions/convertLink.ts b/packages/maru-utils/functions/convertLink.ts
new file mode 100644
index 000000000..d8d0af14a
--- /dev/null
+++ b/packages/maru-utils/functions/convertLink.ts
@@ -0,0 +1,7 @@
+const convertLink = (content: string): string => {
+ const pattern = /(https?:\/\/\S+)/g;
+
+ return content.replace(pattern, '$1').replace(/\n/g, '
');
+};
+
+export default convertLink;
diff --git a/packages/maru-utils/index.ts b/packages/maru-utils/index.ts
index 7357a6177..2d121c06b 100644
--- a/packages/maru-utils/index.ts
+++ b/packages/maru-utils/index.ts
@@ -1,7 +1,7 @@
// function
+export { default as convertLink } from './functions/convertLink';
export { default as formatCreatedAt } from './functions/formatCreatedAt';
export { default as formatPostedAt } from './functions/formatPostedAt';
export { default as formatTime } from './functions/formatTime';
-
// style
export { default as flex } from './styles/flex';
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 40d925420..92639a669 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -22,7 +22,7 @@ importers:
version: 2.5.1
turbo:
specifier: latest
- version: 1.10.7
+ version: 1.10.12
apps/admin:
dependencies:
@@ -41,6 +41,15 @@ importers:
'@maru/utils':
specifier: workspace:*
version: link:../../packages/maru-utils
+ '@tanstack/react-query':
+ specifier: ^4.32.6
+ version: 4.32.6(react-dom@18.2.0)(react@18.2.0)
+ '@tanstack/react-query-devtools':
+ specifier: ^4.32.6
+ version: 4.32.6(@tanstack/react-query@4.32.6)(react-dom@18.2.0)(react@18.2.0)
+ axios:
+ specifier: ^1.4.0
+ version: 1.4.0
next:
specifier: 13.4.6
version: 13.4.6(@babel/core@7.22.10)(react-dom@18.2.0)(react@18.2.0)
@@ -102,6 +111,9 @@ importers:
eslint-plugin-storybook:
specifier: ^0.6.13
version: 0.6.13(eslint@7.32.0)(typescript@5.1.6)
+ msw:
+ specifier: ^1.2.2
+ version: 1.2.2(typescript@5.1.6)
storybook:
specifier: ^7.3.1
version: 7.3.1
@@ -6873,7 +6885,6 @@ packages:
/asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
- dev: true
/available-typed-arrays@1.0.5:
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
@@ -6892,7 +6903,6 @@ packages:
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
- dev: true
/axobject-query@3.2.1:
resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==}
@@ -7521,7 +7531,6 @@ packages:
engines: {node: '>= 0.8'}
dependencies:
delayed-stream: 1.0.0
- dev: true
/commander@10.0.1:
resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
@@ -7960,7 +7969,6 @@ packages:
/delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
- dev: true
/depd@2.0.0:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
@@ -9052,7 +9060,6 @@ packages:
peerDependenciesMeta:
debug:
optional: true
- dev: true
/for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
@@ -9137,7 +9144,6 @@ packages:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
- dev: true
/forwarded@0.2.0:
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
@@ -10568,14 +10574,12 @@ packages:
/mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
- dev: true
/mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
dependencies:
mime-db: 1.52.0
- dev: true
/mime@1.6.0:
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
@@ -10730,6 +10734,42 @@ packages:
- supports-color
dev: true
+ /msw@1.2.2(typescript@5.1.6):
+ resolution: {integrity: sha512-GsW3PE/Es/a1tYThXcM8YHOZ1S1MtivcS3He/LQbbTCx3rbWJYCtWD5XXyJ53KlNPT7O1VI9sCW3xMtgFe8XpQ==}
+ engines: {node: '>=14'}
+ hasBin: true
+ requiresBuild: true
+ peerDependencies:
+ typescript: '>= 4.4.x <= 5.1.x'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@mswjs/cookies': 0.2.2
+ '@mswjs/interceptors': 0.17.9
+ '@open-draft/until': 1.0.3
+ '@types/cookie': 0.4.1
+ '@types/js-levenshtein': 1.1.1
+ chalk: 4.1.1
+ chokidar: 3.5.3
+ cookie: 0.4.2
+ graphql: 16.7.1
+ headers-polyfill: 3.1.2
+ inquirer: 8.2.5
+ is-node-process: 1.2.0
+ js-levenshtein: 1.1.6
+ node-fetch: 2.6.12
+ outvariant: 1.4.0
+ path-to-regexp: 6.2.1
+ strict-event-emitter: 0.4.6
+ type-fest: 2.19.0
+ typescript: 5.1.6
+ yargs: 17.7.2
+ transitivePeerDependencies:
+ - encoding
+ - supports-color
+ dev: true
+
/mute-stream@0.0.8:
resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
dev: true
@@ -11544,7 +11584,6 @@ packages:
/proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
- dev: true
/prr@1.0.1:
resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}
@@ -13131,65 +13170,65 @@ packages:
resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==}
dev: true
- /turbo-darwin-64@1.10.7:
- resolution: {integrity: sha512-N2MNuhwrl6g7vGuz4y3fFG2aR1oCs0UZ5HKl8KSTn/VC2y2YIuLGedQ3OVbo0TfEvygAlF3QGAAKKtOCmGPNKA==}
+ /turbo-darwin-64@1.10.12:
+ resolution: {integrity: sha512-vmDfGVPl5/aFenAbOj3eOx3ePNcWVUyZwYr7taRl0ZBbmv2TzjRiFotO4vrKCiTVnbqjQqAFQWY2ugbqCI1kOQ==}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
- /turbo-darwin-arm64@1.10.7:
- resolution: {integrity: sha512-WbJkvjU+6qkngp7K4EsswOriO3xrNQag7YEGRtfLoDdMTk4O4QTeU6sfg2dKfDsBpTidTvEDwgIYJhYVGzrz9Q==}
+ /turbo-darwin-arm64@1.10.12:
+ resolution: {integrity: sha512-3JliEESLNX2s7g54SOBqqkqJ7UhcOGkS0ywMr5SNuvF6kWVTbuUq7uBU/sVbGq8RwvK1ONlhPvJne5MUqBCTCQ==}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
- /turbo-linux-64@1.10.7:
- resolution: {integrity: sha512-x1CF2CDP1pDz/J8/B2T0hnmmOQI2+y11JGIzNP0KtwxDM7rmeg3DDTtDM/9PwGqfPotN9iVGgMiMvBuMFbsLhg==}
+ /turbo-linux-64@1.10.12:
+ resolution: {integrity: sha512-siYhgeX0DidIfHSgCR95b8xPee9enKSOjCzx7EjTLmPqPaCiVebRYvbOIYdQWRqiaKh9yfhUtFmtMOMScUf1gg==}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
- /turbo-linux-arm64@1.10.7:
- resolution: {integrity: sha512-JtnBmaBSYbs7peJPkXzXxsRGSGBmBEIb6/kC8RRmyvPAMyqF8wIex0pttsI+9plghREiGPtRWv/lfQEPRlXnNQ==}
+ /turbo-linux-arm64@1.10.12:
+ resolution: {integrity: sha512-K/ZhvD9l4SslclaMkTiIrnfcACgos79YcAo4kwc8bnMQaKuUeRpM15sxLpZp3xDjDg8EY93vsKyjaOhdFG2UbA==}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
- /turbo-windows-64@1.10.7:
- resolution: {integrity: sha512-7A/4CByoHdolWS8dg3DPm99owfu1aY/W0V0+KxFd0o2JQMTQtoBgIMSvZesXaWM57z3OLsietFivDLQPuzE75w==}
+ /turbo-windows-64@1.10.12:
+ resolution: {integrity: sha512-7FSgSwvktWDNOqV65l9AbZwcoueAILeE4L7JvjauNASAjjbuzXGCEq5uN8AQU3U5BOFj4TdXrVmO2dX+lLu8Zg==}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
- /turbo-windows-arm64@1.10.7:
- resolution: {integrity: sha512-D36K/3b6+hqm9IBAymnuVgyePktwQ+F0lSXr2B9JfAdFPBktSqGmp50JNC7pahxhnuCLj0Vdpe9RqfnJw5zATA==}
+ /turbo-windows-arm64@1.10.12:
+ resolution: {integrity: sha512-gCNXF52dwom1HLY9ry/cneBPOKTBHhzpqhMylcyvJP0vp9zeMQQkt6yjYv+6QdnmELC92CtKNp2FsNZo+z0pyw==}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
- /turbo@1.10.7:
- resolution: {integrity: sha512-xm0MPM28TWx1e6TNC3wokfE5eaDqlfi0G24kmeHupDUZt5Wd0OzHFENEHMPqEaNKJ0I+AMObL6nbSZonZBV2HA==}
+ /turbo@1.10.12:
+ resolution: {integrity: sha512-WM3+jTfQWnB9W208pmP4oeehZcC6JQNlydb/ZHMRrhmQa+htGhWLCzd6Q9rLe0MwZLPpSPFV2/bN5egCLyoKjQ==}
hasBin: true
requiresBuild: true
optionalDependencies:
- turbo-darwin-64: 1.10.7
- turbo-darwin-arm64: 1.10.7
- turbo-linux-64: 1.10.7
- turbo-linux-arm64: 1.10.7
- turbo-windows-64: 1.10.7
- turbo-windows-arm64: 1.10.7
+ turbo-darwin-64: 1.10.12
+ turbo-darwin-arm64: 1.10.12
+ turbo-linux-64: 1.10.12
+ turbo-linux-arm64: 1.10.12
+ turbo-windows-64: 1.10.12
+ turbo-windows-arm64: 1.10.12
dev: true
/tween-functions@1.2.0: