Skip to content

Commit 622dc76

Browse files
committed
feat: register done
1 parent 83dc51c commit 622dc76

File tree

6 files changed

+182
-54
lines changed

6 files changed

+182
-54
lines changed

src/api/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import axios from 'axios'
22

33
import { listSamples } from './sounds/list-samples'
4-
import { login } from './users'
4+
import { login, me, register } from './users'
55

66
export const userApiClient = axios.create({
77
baseURL: import.meta.env.VITE_DEV_TUNEMA_API_USER,
@@ -23,5 +23,7 @@ export default {
2323
userApiClient,
2424
soundApiClient,
2525
login,
26+
register,
27+
me,
2628
listSamples,
2729
}

src/api/users/index.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { userApiClient } from '..'
22

3-
type LoginResponse = {
3+
export type LoginResponse = {
44
message: string
55
access_token: string
66
user: {
@@ -19,7 +19,33 @@ export async function login(email: string, password: string) {
1919
return response
2020
}
2121

22-
type MeResponse = {
22+
export type RegisterRequest = {
23+
username: string
24+
email: string
25+
password: string
26+
profile_img_url: string
27+
}
28+
29+
export type RegisterResponse = {
30+
message: string
31+
access_token: string
32+
user: {
33+
id: number
34+
username: string
35+
email: string
36+
profile_img_url: string
37+
}
38+
}
39+
40+
export async function register(params: RegisterRequest) {
41+
const response = await userApiClient.post<RegisterResponse>(
42+
'/users/register',
43+
params,
44+
)
45+
return response
46+
}
47+
48+
export type MeResponse = {
2349
id: number
2450
username: string
2551
email: string

src/components/Navbar/navbar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ const Navbar = () => {
135135
href="/artist-dashboard"
136136
className="duration-200 px-4 py-2 font-bold hover:bg-light-green hover:rounded-lg text-center"
137137
>
138-
{'Account'}
138+
{auth.user.username}
139139
</a>
140140
<div className="duration-200 border-b border-gray-3"></div>
141141
<a

src/pages/login/login.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ const LoginWithEmail = () => {
3838

3939
const navigate = useNavigate()
4040

41-
const { login, isAuthenticated } = useAuthStore()
41+
const [login, isAuthenticated] = useAuthStore((state) => [
42+
state.login,
43+
state.isAuthenticated,
44+
])
4245

4346
const onSubmit = handleSubmit(async (data) => {
4447
await login(data.email, data.password)

src/pages/register/register.tsx

Lines changed: 108 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,43 @@
1-
import Navbar from '../../components/Navbar/navbar'
1+
import { useForm } from 'react-hook-form'
2+
import { useNavigate } from 'react-router-dom'
23
import Button from '../../components/button'
3-
import styled from 'styled-components'
44
import Container from '../../components/container'
5-
import IconSoundcloud from '../../components/icons/icon-soundcloud'
65
import IconGoogle from '../../components/icons/icon-google'
7-
// import { Input } from '@material-tailwind/react'
6+
import IconSoundcloud from '../../components/icons/icon-soundcloud'
7+
import Navbar from '../../components/Navbar/navbar'
8+
import { useAuthStore } from '../../store/useAuthStore'
9+
10+
type RegisterFormData = {
11+
username: string
12+
email: string
13+
password: string
14+
confirmPassword: string
15+
}
816

917
function Register() {
18+
const {
19+
register: registerInput,
20+
handleSubmit,
21+
formState: { errors },
22+
watch,
23+
} = useForm<RegisterFormData>()
24+
25+
const navigate = useNavigate()
26+
27+
const [register, isAuthenticated, registrationError] = useAuthStore(
28+
(state) => [state.register, state.isAuthenticated, state.error],
29+
)
30+
const onSubmit = handleSubmit(async (data) => {
31+
await register({
32+
username: data.username,
33+
email: data.email,
34+
password: data.password,
35+
profile_img_url: 'https://i.pravatar.cc/300',
36+
})
37+
38+
return isAuthenticated ? navigate('/home') : null
39+
})
40+
1041
return (
1142
<>
1243
<Navbar />
@@ -28,13 +59,13 @@ function Register() {
2859
<div className="pt-10 flex justify-center text-center">
2960
<button className="p-5 flex justify-center gap-2 w-full h-8 shadow-md rounded-md font-medium content-center items-center text-small text-center hover:bg-primary-green">
3061
<IconGoogle className="mb-0.5 inline" />
31-
<b> Sign Up with Google</b>
62+
<b>Sign Up with Google</b>
3263
</button>
3364
</div>
3465
<div className="pt-5 flex justify-center text-center">
3566
<button className="p-5 flex gap-2 w-full h-8 shadow-md rounded-md font-medium content-center items-center justify-center text-small text-center hover:bg-primary-green">
3667
<IconSoundcloud className="mb-1 inline" />
37-
<b> Sign Up with Soundcloud</b>
68+
<b>Sign Up with Soundcloud</b>
3869
</button>
3970
</div>
4071
<div className="inline-flex items-center justify-center w-full">
@@ -43,49 +74,77 @@ function Register() {
4374
Or
4475
</span>
4576
</div>
46-
<div className="flex flex-col w-full justify-center items-center font-medium text-small">
47-
<label className="flex text-gray-3 text-small self-start font-medium mb-2">
48-
Username
49-
</label>
50-
<input
51-
className="flex bg-gray-2 rounded w-full h-9 pl-3"
52-
type="text"
53-
placeholder=""
54-
/>
55-
</div>
56-
<div className="flex flex-col w-full justify-center items-center font-medium text-small">
57-
<label className="flex text-gray-3 text-small self-start font-medium mt-5 mb-2">
58-
E-mail
59-
</label>
60-
<input
61-
className="flex bg-gray-2 rounded w-full h-9 pl-3"
62-
type="email"
63-
placeholder=""
64-
/>
65-
</div>
66-
<div className="flex flex-col w-full justify-center font-medium text-small">
67-
<label className="flex text-gray-3 text-small font-medium mt-5 mb-2">
68-
Password
69-
</label>
70-
<input
71-
className="flex bg-gray-2 rounded w-auto h-9 pl-3"
72-
type="password"
73-
placeholder=""
74-
/>
75-
</div>
76-
<div className="flex flex-col w-full justify-center font-medium text-small">
77-
<label className="flex text-gray-3 text-small font-medium mt-5 mb-2">
78-
Re-enter Password
79-
</label>
80-
<input
81-
className="flex bg-gray-2 rounded w-auto h-9 pl-3 mb-5"
82-
type="password"
83-
placeholder=""
84-
/>
85-
</div>
86-
<div className="flex flex-col pt-5 w-full">
87-
<Button type="primary">Register</Button>
88-
</div>
77+
<form onSubmit={onSubmit}>
78+
<div className="flex flex-col w-full justify-center items-center font-medium text-small">
79+
<label className="flex text-gray-3 text-small self-start font-medium mb-2">
80+
Username
81+
</label>
82+
<input
83+
className="flex bg-gray-2 rounded w-full h-9 pl-3"
84+
type="text"
85+
placeholder=""
86+
{...registerInput('username', {
87+
required: true,
88+
validate(val: string) {
89+
if (val.length > 50)
90+
return 'Username must be less than 50 characters'
91+
return true
92+
},
93+
})}
94+
/>
95+
</div>
96+
<span className="flex text-red-500 text-small">
97+
{errors.username?.message}
98+
</span>
99+
<div className="flex flex-col w-full justify-center items-center font-medium text-small">
100+
<label className="flex text-gray-3 text-small self-start font-medium mt-5 mb-2">
101+
E-mail
102+
</label>
103+
<input
104+
className="flex bg-gray-2 rounded w-full h-9 pl-3"
105+
type="email"
106+
placeholder=""
107+
{...registerInput('email', { required: true })}
108+
/>
109+
</div>
110+
<div className="flex flex-col w-full justify-center font-medium text-small">
111+
<label className="flex text-gray-3 text-small font-medium mt-5 mb-2">
112+
Password
113+
</label>
114+
<input
115+
className="flex bg-gray-2 rounded w-auto h-9 pl-3"
116+
type="password"
117+
placeholder=""
118+
{...registerInput('password', { required: true })}
119+
/>
120+
</div>
121+
<div className="flex flex-col w-full justify-center font-medium text-small">
122+
<label className="flex text-gray-3 text-small font-medium mt-5 mb-2">
123+
Re-enter Password
124+
</label>
125+
<input
126+
className="flex bg-gray-2 rounded w-auto h-9 pl-3 mb-5"
127+
type="password"
128+
placeholder=""
129+
{...registerInput('confirmPassword', {
130+
required: true,
131+
validate(val: string) {
132+
if (watch('password') === val) return true
133+
return 'Password does not match'
134+
},
135+
})}
136+
/>
137+
<span className="flex text-red-500 text-small">
138+
{errors.confirmPassword?.message}
139+
</span>
140+
</div>
141+
<span className="flex text-red-500 text-small capitalize">
142+
{registrationError}
143+
</span>
144+
<div className="flex flex-col pt-5 w-full">
145+
<Button type="primary">Register</Button>
146+
</div>
147+
</form>
89148
<div className="flex flex-row w-full justify-center pt-5 pb-10 font-medium text-small text-gray-3">
90149
Already have an account?
91150
<u className="indent-1 text-dark-green hover:text-primary-green bg-white">

src/store/useAuthStore.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import { AxiosError } from 'axios'
12
import { create } from 'zustand'
23
import { persist } from 'zustand/middleware'
34
import api from '../api'
45
import { User } from '../api/models'
6+
import { RegisterRequest } from '../api/users'
57

68
export type AuthState = {
79
isAuthenticated: boolean
@@ -12,6 +14,7 @@ export type AuthState = {
1214

1315
export type AuthAction = {
1416
login(email: string, password: string): Promise<void>
17+
register(params: RegisterRequest): Promise<void>
1518
logout(): void
1619
}
1720

@@ -45,8 +48,43 @@ export const useAuthStore = create<AuthState & AuthAction>()(
4548
email: data['user']['email'],
4649
profileImageUrl: data['user']['profile_img_url'],
4750
},
51+
error: '',
4852
}))
4953
},
54+
async register(params: RegisterRequest) {
55+
try {
56+
const { data, status } = await api.register(params)
57+
58+
if (status !== 201) {
59+
set((state) => ({
60+
...state,
61+
error: data['message'],
62+
}))
63+
return
64+
}
65+
66+
set((state) => ({
67+
...state,
68+
isAuthenticated: true,
69+
accessToken: data['access_token'],
70+
user: {
71+
id: data['user']['id'],
72+
username: data['user']['username'],
73+
email: data['user']['email'],
74+
profileImageUrl: data['user']['profile_img_url'],
75+
},
76+
error: '',
77+
}))
78+
} catch (error) {
79+
if (error instanceof AxiosError) {
80+
const errMessage = error.response?.data['message']
81+
set((state) => ({
82+
...state,
83+
error: errMessage,
84+
}))
85+
}
86+
}
87+
},
5088
logout() {
5189
set((state) => ({
5290
...state,

0 commit comments

Comments
 (0)