source: chapterx-frontend/src/store/authStore.ts@ 3ae4bab

main
Last change on this file since 3ae4bab was 3ae4bab, checked in by kikisrbinoska <srbinoskakristina07@…>, 3 days ago

Changes for log in

  • Property mode set to 100644
File size: 6.6 KB
Line 
1import { create } from 'zustand'
2import { persist } from 'zustand/middleware'
3import { User, UserRole } from '../types'
4import axios from 'axios'
5
6const API_BASE = 'https://localhost:7125/api'
7
8interface AuthStore {
9 currentUser: User | null
10 token: string | null
11 showMatureContent: boolean
12 allUsers: User[]
13 login: (emailOrUsername: string, password: string) => Promise<void>
14 logout: () => void
15 register: (data: { username: string; email: string; name: string; surname: string; password: string }, role: 'regular' | 'writer') => Promise<void>
16 switchUser: (userId: number) => void
17 setShowMatureContent: (show: boolean) => void
18 updateUserRole: (userId: number, role: UserRole) => void
19 updateUser: (userId: number, data: { username: string; email: string; name: string; surname: string }) => Promise<void>
20 addUser: (user: User) => void
21 fetchAllUsers: () => Promise<void>
22}
23
24export const useAuthStore = create<AuthStore>()(
25 persist(
26 (set, get) => ({
27 currentUser: null,
28 token: null,
29 showMatureContent: true,
30 allUsers: [],
31
32 login: async (emailOrUsername, password) => {
33 // Try backend first
34 try {
35 const email = emailOrUsername.includes('@')
36 ? emailOrUsername
37 : get().allUsers.find(u => u.username === emailOrUsername)?.email || emailOrUsername
38 const res = await axios.post(`${API_BASE}/auth/login`, { email, password }, { timeout: 3000 })
39 const { token, userId, username, name, surname, role } = res.data
40 const user: User = {
41 user_id: userId,
42 username,
43 email,
44 name: name ?? username,
45 surname: surname ?? '',
46 role: role ?? 'regular',
47 created_at: new Date().toISOString(),
48 follower_count: 0,
49 following_count: 0,
50 }
51 set({ currentUser: user, token })
52 return
53 } catch (err: any) {
54 // Only fall through to mock if the backend is unreachable (network/timeout)
55 // If the backend responded with an error (4xx/5xx), surface it to the user
56 if (err?.response) {
57 const message = err.response.data?.message || err.response.data || 'Incorrect email or password. Please try again.'
58 throw new Error(typeof message === 'string' ? message : 'Incorrect email or password. Please try again.')
59 }
60 // Network error / timeout — fall through to mock login
61 }
62
63 // Fallback to mock
64 const user = get().allUsers.find(
65 u => u.username === emailOrUsername || u.email === emailOrUsername
66 )
67 if (!user) throw new Error('No account found with this email. Please register first.')
68 set({ currentUser: user, token: null })
69 },
70
71 logout: () => set({ currentUser: null, token: null }),
72
73 register: async (data, role) => {
74 try {
75 await axios.post(`${API_BASE}/auth/register`, data, { timeout: 3000 })
76 // Register doesn't return a token — auto-login to get one
77 const loginRes = await axios.post(`${API_BASE}/auth/login`, { email: data.email, password: data.password }, { timeout: 3000 })
78 const { token, userId, username } = loginRes.data
79 const newUser: User = {
80 user_id: userId,
81 username,
82 email: data.email,
83 name: data.name,
84 surname: data.surname,
85 role,
86 created_at: new Date().toISOString(),
87 follower_count: 0,
88 following_count: 0,
89 }
90 set(state => ({ allUsers: [...state.allUsers, newUser], currentUser: newUser, token }))
91 return
92 } catch (err: any) {
93 if (err?.response) {
94 const message = err.response.data?.message || err.response.data || 'Registration failed.'
95 throw new Error(typeof message === 'string' ? message : 'Registration failed.')
96 }
97 // Network error / timeout — fall through to mock register
98 console.warn('Backend unreachable during register, using mock:', err?.message)
99 }
100
101 const newUser: User = {
102 user_id: Date.now(),
103 ...data,
104 role,
105 created_at: new Date().toISOString(),
106 follower_count: 0,
107 following_count: 0,
108 }
109 set(state => ({
110 allUsers: [...state.allUsers, newUser],
111 currentUser: newUser,
112 token: null,
113 }))
114 },
115
116 switchUser: (userId: number) => {
117 if (userId === 0) {
118 set({ currentUser: null, token: null })
119 return
120 }
121 const user = get().allUsers.find(u => u.user_id === userId)
122 if (user) set({ currentUser: user, token: null })
123 },
124
125 setShowMatureContent: (show: boolean) => set({ showMatureContent: show }),
126
127 updateUserRole: (userId: number, role: UserRole) =>
128 set(state => ({
129 allUsers: state.allUsers.map(u => (u.user_id === userId ? { ...u, role } : u)),
130 currentUser:
131 state.currentUser?.user_id === userId
132 ? { ...state.currentUser, role }
133 : state.currentUser,
134 })),
135
136 updateUser: async (userId, data) => {
137 const { token } = get()
138 await axios.put(`${API_BASE}/users/${userId}`, { id: userId, ...data }, {
139 headers: token ? { Authorization: `Bearer ${token}` } : {},
140 })
141 set(state => ({
142 allUsers: state.allUsers.map(u => u.user_id === userId ? { ...u, ...data } : u),
143 currentUser: state.currentUser?.user_id === userId ? { ...state.currentUser, ...data } : state.currentUser,
144 }))
145 },
146
147 addUser: (user: User) =>
148 set(state => ({ allUsers: [...state.allUsers, user] })),
149
150 fetchAllUsers: async () => {
151 try {
152 const res = await axios.get(`${API_BASE}/users`)
153 const data: any[] = res.data?.users ?? res.data ?? []
154 const existing = get().allUsers
155 const users: User[] = data.map((u: any) => ({
156 user_id: u.id,
157 username: u.username,
158 email: u.email ?? '',
159 name: u.name ?? u.username,
160 surname: u.surname ?? '',
161 role: (u.role ?? 'regular') as UserRole,
162 created_at: u.createdAt ?? new Date().toISOString(),
163 follower_count: 0,
164 following_count: 0,
165 bio: existing.find(e => e.user_id === u.id)?.bio,
166 }))
167 set({ allUsers: users })
168 } catch {
169 // keep existing
170 }
171 },
172 }),
173 {
174 name: 'chapterx-auth',
175 partialize: s => ({
176 currentUser: s.currentUser,
177 token: s.token,
178 showMatureContent: s.showMatureContent,
179 }),
180 }
181 )
182)
Note: See TracBrowser for help on using the repository browser.