Initial commit: Helpdesk application setup
- Backend: Node.js/TypeScript with Prisma ORM - Frontend: Vite + TypeScript - Project configuration and documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
80
frontend/src/store/authStore.ts
Normal file
80
frontend/src/store/authStore.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import type { User } from '@/types';
|
||||
import { authApi, type LoginCredentials } from '@/services/auth.api';
|
||||
|
||||
interface AuthState {
|
||||
user: User | null;
|
||||
isAuthenticated: boolean;
|
||||
isLoading: boolean;
|
||||
error: string | null;
|
||||
|
||||
login: (credentials: LoginCredentials) => Promise<void>;
|
||||
logout: () => Promise<void>;
|
||||
fetchProfile: () => Promise<void>;
|
||||
clearError: () => void;
|
||||
}
|
||||
|
||||
export const useAuthStore = create<AuthState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
user: null,
|
||||
isAuthenticated: false,
|
||||
isLoading: false,
|
||||
error: null,
|
||||
|
||||
login: async (credentials) => {
|
||||
set({ isLoading: true, error: null });
|
||||
try {
|
||||
const response = await authApi.login(credentials);
|
||||
const { user, accessToken, refreshToken } = response.data;
|
||||
|
||||
localStorage.setItem('accessToken', accessToken);
|
||||
localStorage.setItem('refreshToken', refreshToken);
|
||||
|
||||
set({ user, isAuthenticated: true, isLoading: false });
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : 'Prihlásenie zlyhalo';
|
||||
set({ error: message, isLoading: false });
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
logout: async () => {
|
||||
try {
|
||||
await authApi.logout();
|
||||
} catch {
|
||||
// Ignore logout errors
|
||||
} finally {
|
||||
localStorage.removeItem('accessToken');
|
||||
localStorage.removeItem('refreshToken');
|
||||
set({ user: null, isAuthenticated: false });
|
||||
}
|
||||
},
|
||||
|
||||
fetchProfile: async () => {
|
||||
const token = localStorage.getItem('accessToken');
|
||||
if (!token) {
|
||||
set({ user: null, isAuthenticated: false });
|
||||
return;
|
||||
}
|
||||
|
||||
set({ isLoading: true });
|
||||
try {
|
||||
const response = await authApi.getProfile();
|
||||
set({ user: response.data, isAuthenticated: true, isLoading: false });
|
||||
} catch {
|
||||
localStorage.removeItem('accessToken');
|
||||
localStorage.removeItem('refreshToken');
|
||||
set({ user: null, isAuthenticated: false, isLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
clearError: () => set({ error: null }),
|
||||
}),
|
||||
{
|
||||
name: 'auth-storage',
|
||||
partialize: (state) => ({ user: state.user, isAuthenticated: state.isAuthenticated }),
|
||||
}
|
||||
)
|
||||
);
|
||||
91
frontend/src/store/configStore.ts
Normal file
91
frontend/src/store/configStore.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { create } from 'zustand';
|
||||
import type {
|
||||
TaskStatus,
|
||||
Priority,
|
||||
EquipmentType,
|
||||
RevisionType,
|
||||
RMAStatus,
|
||||
RMASolution,
|
||||
UserRole,
|
||||
} from '@/types';
|
||||
import { settingsApi } from '@/services/settings.api';
|
||||
|
||||
interface ConfigState {
|
||||
taskStatuses: TaskStatus[];
|
||||
priorities: Priority[];
|
||||
equipmentTypes: EquipmentType[];
|
||||
revisionTypes: RevisionType[];
|
||||
rmaStatuses: RMAStatus[];
|
||||
rmaSolutions: RMASolution[];
|
||||
userRoles: UserRole[];
|
||||
isLoading: boolean;
|
||||
isLoaded: boolean;
|
||||
|
||||
fetchConfig: () => Promise<void>;
|
||||
getTaskStatusById: (id: string) => TaskStatus | undefined;
|
||||
getPriorityById: (id: string) => Priority | undefined;
|
||||
getEquipmentTypeById: (id: string) => EquipmentType | undefined;
|
||||
getRevisionTypeById: (id: string) => RevisionType | undefined;
|
||||
getRMAStatusById: (id: string) => RMAStatus | undefined;
|
||||
getRMASolutionById: (id: string) => RMASolution | undefined;
|
||||
getUserRoleById: (id: string) => UserRole | undefined;
|
||||
}
|
||||
|
||||
export const useConfigStore = create<ConfigState>((set, get) => ({
|
||||
taskStatuses: [],
|
||||
priorities: [],
|
||||
equipmentTypes: [],
|
||||
revisionTypes: [],
|
||||
rmaStatuses: [],
|
||||
rmaSolutions: [],
|
||||
userRoles: [],
|
||||
isLoading: false,
|
||||
isLoaded: false,
|
||||
|
||||
fetchConfig: async () => {
|
||||
if (get().isLoaded) return;
|
||||
|
||||
set({ isLoading: true });
|
||||
try {
|
||||
const [
|
||||
taskStatusesRes,
|
||||
prioritiesRes,
|
||||
equipmentTypesRes,
|
||||
revisionTypesRes,
|
||||
rmaStatusesRes,
|
||||
rmaSolutionsRes,
|
||||
userRolesRes,
|
||||
] = await Promise.all([
|
||||
settingsApi.getTaskStatuses(),
|
||||
settingsApi.getPriorities(),
|
||||
settingsApi.getEquipmentTypes(),
|
||||
settingsApi.getRevisionTypes(),
|
||||
settingsApi.getRMAStatuses(),
|
||||
settingsApi.getRMASolutions(),
|
||||
settingsApi.getUserRoles(),
|
||||
]);
|
||||
|
||||
set({
|
||||
taskStatuses: taskStatusesRes.data,
|
||||
priorities: prioritiesRes.data,
|
||||
equipmentTypes: equipmentTypesRes.data,
|
||||
revisionTypes: revisionTypesRes.data,
|
||||
rmaStatuses: rmaStatusesRes.data,
|
||||
rmaSolutions: rmaSolutionsRes.data,
|
||||
userRoles: userRolesRes.data,
|
||||
isLoading: false,
|
||||
isLoaded: true,
|
||||
});
|
||||
} catch {
|
||||
set({ isLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
getTaskStatusById: (id) => get().taskStatuses.find((s) => s.id === id),
|
||||
getPriorityById: (id) => get().priorities.find((p) => p.id === id),
|
||||
getEquipmentTypeById: (id) => get().equipmentTypes.find((t) => t.id === id),
|
||||
getRevisionTypeById: (id) => get().revisionTypes.find((t) => t.id === id),
|
||||
getRMAStatusById: (id) => get().rmaStatuses.find((s) => s.id === id),
|
||||
getRMASolutionById: (id) => get().rmaSolutions.find((s) => s.id === id),
|
||||
getUserRoleById: (id) => get().userRoles.find((r) => r.id === id),
|
||||
}));
|
||||
Reference in New Issue
Block a user