Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/app/(user-access)/components/modal/Modal.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.modalContainer {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1000;
}

.modal {
width: 308px;
height: 152px;
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enter πŸ˜‡

.message {
margin-top: 20px;
font-size: 18px;
font-weight: 500;
text-align: center;
}

.button {
margin-top: 30px;
height: 40px;
}
35 changes: 35 additions & 0 deletions src/app/(user-access)/components/modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import useModalStore from '../../modalStore/modalStore';
import Button from '@/components/Button';
import styles from './Modal.module.css';
import { useRouter } from 'next/navigation';

interface AlertModalProps {
message: string;
}

const AlertModal = ({ message }: AlertModalProps) => {
const { closeModal, messageType } = useModalStore();
const router = useRouter();

const handleConfirm = () => {
closeModal();
if (messageType === 'success') {
router.push('/login');
}
};

return (
<div className={styles.modal}>
<div className={styles.messageContainer}>
<p className={styles.message}>{message}</p>
</div>
<div className={styles.buttonContainer}>
<Button onClick={handleConfirm} className={styles.button}>
확인
</Button>
</div>
</div>
);
};

export default AlertModal;
17 changes: 17 additions & 0 deletions src/app/(user-access)/components/modal/ModalContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import useModalStore from '../../modalStore/modalStore';
import styles from './Modal.module.css';
import AlertModal from './Modal';

const ModalContainer = () => {
const { isOpen, message } = useModalStore();

if (!isOpen) return null;

return (
<div className={styles.modalContainer}>
<AlertModal message={message} />
</div>
);
};

export default ModalContainer;
8 changes: 2 additions & 6 deletions src/app/(user-access)/layout.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,29 @@
align-items: center;
min-height: 100vh;
width: 100%;
background-color: var(--white);
background-color: var(--gray-100);
}

.authContent {
width: 100%;
max-width: 400px;
box-sizing: border-box;
display: flex;
justify-content: center;
background-color: var(--white);
background-color: var(--gray-100);
border-radius: 8px;
padding: 20px;
}

.logoContainer {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin: 16px 0;
}

.logo {
width: 100%;
height: auto;
}

@media screen and (min-width: 768px) {
.authContent {
max-width: 351px;
Expand Down
File renamed without changes.
File renamed without changes.
143 changes: 74 additions & 69 deletions src/app/(user-access)/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
'use client';

import React from 'react';
import axios from 'axios';
import { useForm, FieldValues, UseFormReturn } from 'react-hook-form';
import { useRouter } from 'next/navigation';
import useAuthStore from '@/store/authStore';
import Button from '@/components/Button';
import { ERROR_MESSAGES } from '@/constants/message';
import type { User } from '@/types/user';
import styles from './loginPage.module.css';
import ModalContainer from '../components/modal/ModalContainer';
import useModalStore from '../modalStore/modalStore';
import axios, { AxiosError, isAxiosError } from 'axios';

type LoginFormInputs = {
email: string;
Expand All @@ -33,6 +35,7 @@ export default function LoginPage() {

const router = useRouter();
const { setUser } = useAuthStore();
const { openModal } = useModalStore();

const onSubmit = async (data: LoginFormInputs) => {
try {
Expand All @@ -43,78 +46,80 @@ export default function LoginPage() {

router.replace('/mydashboard');
} catch (error) {
console.error('둜그인 μ‹€νŒ¨:', error);
alert('λΉ„λ°€λ²ˆν˜Έκ°€ μΌμΉ˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.');
openModal('λΉ„λ°€λ²ˆν˜Έκ°€ μΌμΉ˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.', 'error');
}
};

return (
<form onSubmit={handleSubmit(onSubmit)} className={styles.form}>
<div className={styles.inputWrapper}>
<p className={styles.greeting}>μ˜€λŠ˜λ„ λ§Œλ‚˜μ„œ λ°˜κ°€μ›Œμš”!</p>
<label htmlFor="email" className={styles.label}>
이메일
</label>
<input
id="email"
type="email"
className={`${styles.input} ${errors.email ? styles.inputError : ''}`}
{...register('email', {
required: ERROR_MESSAGES.REQUIRED_EMAIL,
pattern: {
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
message: ERROR_MESSAGES.INVALID_EMAIL,
},
})}
/>
{errors.email && (
<span className={styles.errorMessage}>{errors.email.message}</span>
)}
</div>
<div className={styles.loginContainer}>
<ModalContainer />
<form onSubmit={handleSubmit(onSubmit)} className={styles.form}>
<div className={styles.inputWrapper}>
<p className={styles.greeting}>μ˜€λŠ˜λ„ λ§Œλ‚˜μ„œ λ°˜κ°€μ›Œμš”!</p>
<label htmlFor="email" className={styles.label}>
이메일
</label>
<input
id="email"
type="email"
className={`${styles.input} ${errors.email ? styles.inputError : ''}`}
{...register('email', {
required: ERROR_MESSAGES.REQUIRED_EMAIL,
pattern: {
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
message: ERROR_MESSAGES.INVALID_EMAIL,
},
})}
/>
{errors.email && (
<span className={styles.errorMessage}>{errors.email.message}</span>
)}
</div>

<div className={styles.inputWrapper}>
<label htmlFor="password" className={styles.label}>
λΉ„λ°€λ²ˆν˜Έ
</label>
<input
id="password"
type="password"
className={`${styles.input} ${errors.password ? styles.inputError : ''}`}
{...register('password', {
required: ERROR_MESSAGES.PASSWORD_REQUIRE,
minLength: {
value: 8,
message: ERROR_MESSAGES.PASSWORD_TOO_SHORT,
},
})}
/>
{errors.password && (
<p className={styles.errorMessage}>{errors.password.message}</p>
)}
</div>
<Button
type="submit"
disabled={!isValid}
className={!isValid ? styles.disabled : ''}
style={{ height: '40px' }}
>
둜그인
</Button>
<div style={{ display: 'flex', justifyContent: 'center' }}>
<p>
νšŒμ›μ΄ μ•„λ‹ˆμ‹ κ°€μš”?{' '}
<span
style={{
color: 'var(--violet)',
textDecoration: 'underline',
cursor: 'pointer',
}}
onClick={() => router.push('/signup')}
>
νšŒμ›κ°€μž…ν•˜κΈ°
</span>{' '}
</p>
</div>
</form>
<div className={styles.inputWrapper}>
<label htmlFor="password" className={styles.label}>
λΉ„λ°€λ²ˆν˜Έ
</label>
<input
id="password"
type="password"
className={`${styles.input} ${errors.password ? styles.inputError : ''}`}
{...register('password', {
required: ERROR_MESSAGES.PASSWORD_REQUIRE,
minLength: {
value: 8,
message: ERROR_MESSAGES.PASSWORD_TOO_SHORT,
},
})}
/>
{errors.password && (
<p className={styles.errorMessage}>{errors.password.message}</p>
)}
</div>
<Button
type="submit"
disabled={!isValid}
className={!isValid ? styles.disabled : ''}
style={{ height: '40px' }}
>
둜그인
</Button>
<div style={{ display: 'flex', justifyContent: 'center' }}>
<p>
νšŒμ›μ΄ μ•„λ‹ˆμ‹ κ°€μš”?{' '}
<span
style={{
color: 'var(--violet)',
textDecoration: 'underline',
cursor: 'pointer',
}}
onClick={() => router.push('/signup')}
Copy link
Owner

@najitwo najitwo Nov 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

인라인 μŠ€νƒ€μΌμ΄ λ§Žλ„€μš”~
κΌ­ ν•„μš”ν•˜μ§€ μ•ŠμœΌλ©΄ 인라인 μŠ€νƒ€μΌμ€ μ§€μ–‘ν•΄μ£Όμ„Έμš”~

>
νšŒμ›κ°€μž…ν•˜κΈ°
</span>{' '}
</p>
</div>
</form>
</div>
);
}
20 changes: 20 additions & 0 deletions src/app/(user-access)/modalStore/modalStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { create } from 'zustand';

interface ModalState {
isOpen: boolean;
message: string;
messageType: string;
openModal: (message: string, messageType: string) => void;
closeModal: () => void;
}

const useModalStore = create<ModalState>((set) => ({
isOpen: false,
message: '',
messageType: '',
openModal: (message, messageType) =>
set({ isOpen: true, message, messageType }),
closeModal: () => set({ isOpen: false, message: '', messageType: '' }),
}));

export default useModalStore;
Loading