diff --git a/bun.lockb b/bun.lockb
index 2bd3b63..dfe938e 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/next.config.mjs b/next.config.mjs
index 0f605e8..ffb2d84 100755
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -22,22 +22,6 @@ const nextConfig = {
},
];
},
- webpack: (config, { isServer }) => {
- if (isServer) {
- if (Array.isArray(config.resolve.alias)) {
- config.resolve.alias.push({ name: 'msw/browser', alias: false });
- } else {
- config.resolve.alias['msw/browser'] = false;
- }
- } else {
- if (Array.isArray(config.resolve.alias)) {
- config.resolve.alias.push({ name: 'msw/node', alias: false });
- } else {
- config.resolve.alias['msw/node'] = false;
- }
- }
- return config;
- },
};
const ContentSecurityPolicy = `
diff --git a/package.json b/package.json
index 74b2563..300d6c0 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,8 @@
"test:pin": "jest --watch /tests/pin/app.spec.tsx"
},
"dependencies": {
+ "@conform-to/react": "^1.1.0",
+ "@conform-to/zod": "^1.1.0",
"@mdx-js/loader": "^2.3.0",
"@mdx-js/react": "^2.3.0",
"@next/bundle-analyzer": "^13.5.4",
@@ -57,13 +59,15 @@
"sharp": "^0.32.6",
"styled-components": "^5.3.11",
"swr": "^2.2.4",
+ "tailwind-merge": "^2.2.2",
"ts-node": "^10.9.1",
"undici": "^6.10.2",
"uuid": "^9.0.1",
- "valibot": "^0.27.0",
+ "valibot": "^0.30.0",
"web-vitals": "^3.5.0",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
+ "zod": "^3.22.4",
"zustand": "^4.5.2"
},
"devDependencies": {
diff --git a/public/font/NanumSquareNeo.woff2 b/public/font/NanumSquareNeo.woff2
new file mode 100755
index 0000000..a512048
Binary files /dev/null and b/public/font/NanumSquareNeo.woff2 differ
diff --git a/src/components/NotificationList/NotificationList.tsx b/src/components/NotificationList/NotificationList.tsx
index 4c2bedc..af743ec 100644
--- a/src/components/NotificationList/NotificationList.tsx
+++ b/src/components/NotificationList/NotificationList.tsx
@@ -8,14 +8,8 @@ import NotificationItem from '../NotificationItem';
type NotificationItem = [string, Notification];
function NotificationList() {
- const [notificationList, setNotificationList] = React.useState<
- NotificationItem[]
- >([]);
- const { notifications } = useNotificationStore((state) => state);
-
- React.useEffect(() => {
- setNotificationList([...notifications.entries()]);
- }, [notifications]);
+ const notifications = useNotificationStore((state) => state.notifications);
+ console.log(notifications);
return (
- {notificationList &&
- notificationList.map(([id, notification]: NotificationItem) => (
-
+ {notifications &&
+ notifications.map(({ id, message, type }) => (
+
))}
);
diff --git a/src/components/Notifications/Notifiactions.tsx b/src/components/Notifications/Notifiactions.tsx
deleted file mode 100644
index 32d3d10..0000000
--- a/src/components/Notifications/Notifiactions.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-'use client';
-
-import React from 'react';
-import {
- NotificationContext,
- type Notification,
-} from '@/context/NotificationContext';
-import NotificationItem from '../NotificationItem';
-
-function Notifications() {
- const { notificationList } = React.useContext(NotificationContext);
-
- return (
-
- {notificationList &&
- notificationList.map((notification: Notification) => (
-
- ))}
-
- );
-}
-
-export default Notifications;
diff --git a/src/components/Notifications/index.ts b/src/components/Notifications/index.ts
deleted file mode 100644
index 2f536d0..0000000
--- a/src/components/Notifications/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './Notifiactions';
-export { default } from './Notifiactions';
diff --git a/src/components/PinNumber/PinInput.tsx b/src/components/PinNumber/PinInput.tsx
index 2709306..c8b5c8a 100644
--- a/src/components/PinNumber/PinInput.tsx
+++ b/src/components/PinNumber/PinInput.tsx
@@ -9,13 +9,15 @@ import PinSuccess from './PinSuccess';
import styled from 'styled-components';
import { motion } from 'framer-motion';
import { useNumpadStore, useSubmitNumpadStroe } from '@/context/NumpadContext';
+import { useNotificationStore } from '@/context/NotificationContext';
+import { goToUsername } from '@/utils/revalidate';
interface PinInputProps {
children: React.ReactNode;
uses: 'register' | 'confirm';
padInfo: KeypadInfo;
action: (
- decodedPinNumbers: string[],
+ formData: FormData,
padInfo: KeypadInfo,
) => Promise<{
status: string;
@@ -58,9 +60,11 @@ function PinInput({ uses, children, padInfo, action }: PinInputProps) {
errorId: '',
msg: null,
});
+
const inputRef = React.useRef(null);
const containerRef = React.useRef(null);
const isHydrated = useHydrated();
+
const { updateStatus } =
uses === 'register'
? useNumpadStore((state) => state)
@@ -101,30 +105,12 @@ function PinInput({ uses, children, padInfo, action }: PinInputProps) {
setOpen(true);
}}
action={async (formData: FormData) => {
- updateStatus('pending');
- const isReorder = formData.get('reorder') === 'on';
-
- if (isReorder) {
- reorderKeypad(isReorder);
- return;
- }
-
- let formPinNumber = formData.get('pinNumbers') as string;
- const result = v.safeParse(PinNumberSchema, formPinNumber.split(','));
+ const actionResult = await action(formData, padInfo);
- if (!result.success) {
- updateStatus('idle');
- setPinErrorStatus({
- hasError: true,
- errorId: 'pin-pattern-input',
- msg: result.issues[0].message,
- });
- return;
- }
-
- const pinNumber = result.output as string[];
- const actionResult = await action(pinNumber, padInfo);
if (actionResult.status === 'error') {
+ if (actionResult.id === 'username-not-found') {
+ return goToUsername();
+ }
updateStatus('idle');
setPinErrorStatus({
hasError: true,
@@ -133,10 +119,42 @@ function PinInput({ uses, children, padInfo, action }: PinInputProps) {
});
return;
}
-
- setOpen(true);
- setSuccess(true);
- updateStatus('idle');
+ // updateStatus('pending');
+ // const isReorder = formData.get('reorder') === 'on';
+
+ // if (isReorder) {
+ // reorderKeypad(isReorder);
+ // return;
+ // }
+
+ // let formPinNumber = formData.get('pinNumbers') as string;
+ // const result = v.safeParse(PinNumberSchema, formPinNumber.split(','));
+
+ // if (!result.success) {
+ // updateStatus('idle');
+ // setPinErrorStatus({
+ // hasError: true,
+ // errorId: 'pin-pattern-input',
+ // msg: result.issues[0].message,
+ // });
+ // return;
+ // }
+
+ // const pinNumber = result.output as string[];
+ // const actionResult = await action(pinNumber, padInfo);
+ // if (actionResult.status === 'error') {
+ // updateStatus('idle');
+ // setPinErrorStatus({
+ // hasError: true,
+ // errorId: actionResult.id,
+ // msg: actionResult.msg,
+ // });
+ // return;
+ // }
+
+ // setOpen(true);
+ // setSuccess(true);
+ // updateStatus('idle');
}}
>
{isSuccess ? (
diff --git a/src/context/NotificationContext.tsx b/src/context/NotificationContext.tsx
index 16e0c74..988a3b6 100644
--- a/src/context/NotificationContext.tsx
+++ b/src/context/NotificationContext.tsx
@@ -1,77 +1,40 @@
'use client';
import React from 'react';
-import NotificationItem from '@/components/NotificationItem';
-
-interface NotificationContextProps {
- notificationList: Notification[];
- action: {
- add: (notification: Notification) => void;
- remove: (id: string) => void;
- };
-}
-
-export interface Notification {
- id: string;
- message: string;
- type: 'default' | 'error' | 'success';
-}
-
-interface ContextValue {
- notificationList: Notification[];
- action: {
- add: (notification: Notification) => void;
- remove: (id: string) => void;
- };
-}
+import { type StoreApi, useStore } from 'zustand';
+import {
+ type NotificationStore,
+ createNotificationStore,
+} from '@/store/notification-store';
export const NotificationContext =
- React.createContext({
- notificationList: [],
- action: {
- add: () => {},
- remove: () => {},
- },
- });
+ React.createContext | null>(null);
-function NotificationContextProvider({
+export function NotificationProvider({
children,
}: {
children: React.ReactNode;
}) {
- const [notificationList, setNotification] = React.useState(
- [],
- );
-
- const contextValue = React.useMemo((): ContextValue => {
- const add = (notification: Notification) => {
- const newNotification = [...notificationList, notification];
- setNotification(newNotification);
- };
-
- const remove = (id: string) => {
- if (id.length == 0) {
- setNotification([]);
- return;
- }
-
- const newNotification = notificationList.filter((item) => item.id !== id);
- setNotification(newNotification);
- };
-
- const action = {
- add,
- remove,
- };
-
- return { notificationList, action };
- }, [notificationList, setNotification]);
+ const notificationRef = React.useRef>();
+ if (!notificationRef.current) {
+ notificationRef.current = createNotificationStore();
+ }
return (
-
+
{children}
);
}
-export default NotificationContextProvider;
+export const useNotificationStore = (
+ selector: (store: NotificationStore) => T,
+): T => {
+ const notificationContext = React.useContext(NotificationContext);
+ if (!notificationContext) {
+ throw new Error(
+ 'useNotificationStore must be used within a NotificationContextProvider',
+ );
+ }
+ return useStore(notificationContext, selector);
+};
diff --git a/src/fonts/NanumSquareNeo-Variable.woff2 b/src/fonts/NanumSquareNeo-Variable.woff2
new file mode 100644
index 0000000..62f4bae
Binary files /dev/null and b/src/fonts/NanumSquareNeo-Variable.woff2 differ
diff --git a/src/store/notification-store.ts b/src/store/notification-store.ts
index af0cf97..22e21e6 100644
--- a/src/store/notification-store.ts
+++ b/src/store/notification-store.ts
@@ -2,16 +2,17 @@ import { createStore } from 'zustand';
import { z } from 'zod';
export type Notification = {
+ id: string;
message: string;
type: 'default' | 'error' | 'success';
};
export type NotificationState = {
- notifications: Map;
+ notifications: Notification[];
};
export type NotificationAction = {
- add: (notification: Notification, id: string) => void;
+ add: (notification: Notification) => void;
remove: (id: string) => void;
};
@@ -36,7 +37,7 @@ export const NotificationStateSchema = z.map(
);
export const defaultInitState = {
- notifications: new Map(),
+ notifications: [],
} as NotificationState;
export type NotificationStore = NotificationState & NotificationAction;
@@ -46,15 +47,18 @@ export const createNotificationStore = (
) => {
return createStore((set) => ({
...initState,
- add: (notification: Notification, id: string) => {
+ add: (notification: Notification) => {
set((state) => {
- state.notifications.set(id, notification);
+ if (state.notifications.find((n) => n.id === notification.id)) {
+ return state;
+ }
+ state.notifications.push(notification);
return state;
});
},
remove: (id: string) => {
set((state) => {
- state.notifications.delete(id);
+ state.notifications = state.notifications.filter((n) => n.id !== id);
return state;
});
},
diff --git a/tailwind.config.mjs b/tailwind.config.mjs
index 13fe1de..cc4c456 100644
--- a/tailwind.config.mjs
+++ b/tailwind.config.mjs
@@ -66,6 +66,50 @@ export default {
1: '1px',
2: '2px',
},
+ colors: {
+ border: 'oklch(42.44% 0.011 17.58)',
+ input: {
+ DEFAULT: 'oklch(65.57% 0.19552898037793698 288.17775174927874)',
+ invalid: 'oklch(73.96% 0.1963 25.278467161119735)',
+ },
+ ring: {
+ DEFAULT: 'oklch(86.83% 0.06751643147886291 285.8383540015746)',
+ invalid: 'oklch(64.17% 0.221 26.06)',
+ },
+ background: 'var(--color-background)',
+ foreground: {
+ DEFAULT: 'oklch(76.7% 0.123 284.14)',
+ destructive: 'oklch(64.17% 0.221 26.06)',
+ },
+ primary: {
+ DEFAULT: 'var(--primary)',
+ foreground: 'var(--primary-foreground)',
+ },
+ secondary: {
+ DEFAULT: 'var(--secondary)',
+ foreground: 'var(--secondary-foreground)',
+ },
+ destructive: {
+ DEFAULT: 'var(--destructive)',
+ foreground: 'var(--destructive-foreground)',
+ },
+ muted: {
+ DEFAULT: 'hsl(var(--muted))',
+ foreground: 'hsl(var(--muted-foreground))',
+ },
+ accent: {
+ DEFAULT: 'var(--accent)',
+ foreground: 'var(--color-background)',
+ },
+ popover: {
+ DEFAULT: 'hsl(var(--popover))',
+ foreground: 'hsl(var(--popover-foreground))',
+ },
+ card: {
+ DEFAULT: 'hsl(var(--card))',
+ foreground: 'hsl(var(--card-foreground))',
+ },
+ },
},
},
plugins: [],