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

main
Last change on this file since acf690c was acf690c, checked in by kikisrbinoska <srbinoskakristina07@…>, 4 months ago

Added fixes for the login,stories management and reading lists

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