Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion front/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/node_modules
/.pnp
.pnp.js

.env
# testing
/coverage

Expand Down
1 change: 1 addition & 0 deletions front/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@types/react-dom": "^18.3.1",
"axios": "^1.7.8",
"class-variance-authority": "^0.7.0",
"dotenv": "^16.4.5",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^7.0.1",
Expand Down
47 changes: 47 additions & 0 deletions front/src/Controller/fetch.signup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import supabaseInstance from '../Model/fetch.supabase.instance';

interface SignUpParams {
email: string;
password: string;
admin: boolean;
job?: string; // Optional: name은 필수가 아닐 수 있음
nickname?: string;
}

const fetchSignUp = async ({ email, password, admin, job, nickname }: SignUpParams) => {
try {
const { data, error } = await supabaseInstance.auth.signUp({
email,
password,
options: {
data: {
// 사용자 정의 메타데이터로 전달
admin,
job,
nickname,
},
},
});

// 구조할당으로 responseMessage를 보내는 이유는 이 구조로 호출하는 쪽에서 명확하게 responseMessage와 data를 구분해서 사용할 수 있게 하기 위함이다. 즉, 반환 값은 객체이기 때문이다.
// 추가적으로 fetchSignup은 promise를 반환했다.

if (error) {
// error
console.error('SignUp Error:', error);
const errorMessage = error.message || 'Signup failed. Please try again.';
return { responseMessage: errorMessage, data: undefined };
}
// 성공적인 경우
const successMessage = 'Signup successful! Check your email for confirmation.';
return { responseMessage: successMessage, data };

// 예외가 발생할 경우
} catch (error: any) {
console.error('SignUp Error:', error);
const catchMessage = error.message || 'An unexpected error occurred. Please try again.';
return { responseMessage: catchMessage, data: undefined };
}
};

export default fetchSignUp;
12 changes: 12 additions & 0 deletions front/src/Model/fetch.instance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import axios from 'axios';

const axiosInstance = axios.create({
baseURL: 'https://fsrotjrwllkimiidizgk.supabase.co', // Supabase 프로젝트 URL
headers: {
apikey:
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImZzcm90anJ3bGxraW1paWRpemdrIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzMwMjgzMTQsImV4cCI6MjA0ODYwNDMxNH0.uiFog4O3BbOZhBC1z0LRFTtEE4p4z3PK5VQ5wKrRHzg', // Supabase API Key
'Content-Type': 'application/json',
},
});

export default axiosInstance;
8 changes: 8 additions & 0 deletions front/src/Model/fetch.supabase.instance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { createClient } from '@supabase/supabase-js';

const supabaseInstance = createClient(
'https://bsrffkqymaqhwwqziqee.supabase.co',
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJzcmZma3F5bWFxaHd3cXppcWVlIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzMxMTc5NzMsImV4cCI6MjA0ODY5Mzk3M30.1UKuqvG0Ls3WxLvNkAHRASWyv8Y8coIJKe0M9tZ8flA',
);

export default supabaseInstance;
87 changes: 42 additions & 45 deletions front/src/Page/Signup.tsx
Original file line number Diff line number Diff line change
@@ -1,80 +1,77 @@
import React, { useState } from 'react';
import { createClient } from '@supabase/supabase-js';
import fetchSignUp from '../Controller/fetch.signup';

const supabase = createClient(
'https://fsrotjrwllkimiidizgk.supabase.co',
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImZzcm90anJ3bGxraW1paWRpemdrIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzMwMjgzMTQsImV4cCI6MjA0ODYwNDMxNH0.uiFog4O3BbOZhBC1z0LRFTtEE4p4z3PK5VQ5wKrRHzg',
);

const Signup: React.FC = () => {
const Login = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [name, setName] = useState('');
const [admin, setAdmin] = useState(false);
const [job, setJob] = useState('');
const [nickname, setNickName] = useState('');
const [responseMessage, setResponseMessage] = useState('');

const handleSignUp = async () => {
try {
const { data, error } = await supabase.auth.signUp({
email,
password,
options: {
data: {
name, // 사용자 정의 메타데이터로 전달
},
},
});

if (error) {
throw error;
}

setResponseMessage('Signup successful! Check your email for confirmation.');
} catch (error: any) {
setResponseMessage(error.message || 'Signup failed. Please try again.');
}
const { responseMessage } = await fetchSignUp({
email,
password,
admin,
job,
nickname,
});
setResponseMessage(responseMessage);
};

return (
<div style={{ maxWidth: '400px', margin: 'auto', padding: '20px' }}>
<h1>Sign Up</h1>
<div className='max-w-md p-5 mx-auto'>
<h1 className='mb-5 text-2xl font-bold'>Sign Up</h1>
{/* Nickname */}
<input
type='text'
placeholder='Name'
value={name}
onChange={(e) => setName(e.target.value)}
style={{ display: 'block', width: '100%', marginBottom: '10px', padding: '8px' }}
placeholder='nickname'
value={nickname}
onChange={(e) => setNickName(e.target.value)}
className='block w-full p-2 mb-3 border border-gray-300 rounded'
/>
{/* Job */}
<select
value={job}
onChange={(e) => setJob(e.target.value)}
className='block w-full p-2 mb-3 border border-gray-300 rounded'
>
<option value=''>Select your job</option>
<option value='Front-Developer'>프론트 개발자</option>
<option value='Back-Developer'>백엔드 개발자</option>
<option value='Full-Developer'>풀스택 개발자</option>
<option value='Designer'>디자이너</option>
<option value='Manager'>기획자</option>
<option value='Student'>학생</option>
</select>
{/* Email */}
<input
type='email'
placeholder='Email'
value={email}
onChange={(e) => setEmail(e.target.value)}
style={{ display: 'block', width: '100%', marginBottom: '10px', padding: '8px' }}
className='block w-full p-2 mb-3 border border-gray-300 rounded'
/>
{/* Password */}
<input
type='password'
placeholder='Password'
value={password}
onChange={(e) => setPassword(e.target.value)}
style={{ display: 'block', width: '100%', marginBottom: '10px', padding: '8px' }}
className='block w-full p-2 mb-3 border border-gray-300 rounded'
/>
{/* Sign Up Button */}
<button
onClick={handleSignUp}
type='button'
style={{
width: '100%',
padding: '10px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '5px',
}}
className='w-full p-3 font-bold text-white bg-blue-500 rounded hover:bg-blue-600'
>
Sign Up
</button>
{responseMessage && <p style={{ marginTop: '20px', color: 'red' }}>{responseMessage}</p>}
{responseMessage && <p className='mt-5 text-red-500'>{responseMessage}</p>}
</div>
);
};

export default Signup;
export default Login;
Loading