Files
clinicpro/assets/admin/stores/authStore.ts
T
hamed e7b90a6399 feat(api): add dashboard endpoints for clinic, doctor, and secretary roles
- Implemented GET /api/v1/dashboard/clinic to return clinic stats and today's schedule for clinic owners.
- Implemented GET /api/v1/dashboard/doctor to return doctor's stats and today's schedule for doctors.
- Implemented GET /api/v1/dashboard/secretary to return stats and conditional appointments for secretaries.

feat(migrations): create user_active_context and mobile_verification_otp tables

- Added migration to create user_active_context table for tracking active user sessions.
- Added migration to create mobile_verification_otp table for handling mobile number verification.

feat(migrations): create site_config table for application settings

- Added migration to create site_config table to store various site configuration settings.

feat(appointments): create MyAppointmentsController for user-specific appointments

- Added MyAppointmentsController to handle fetching user-specific appointments with pagination and filtering.

feat(auth): implement NotificationMobileController for mobile number verification

- Added NotificationMobileController to handle OTP requests and verification for mobile number changes.

feat(auth): create MobileVerificationOtp entity for OTP management

- Created MobileVerificationOtp entity to manage OTP records for mobile verification.

feat(auth): create UserActiveContext entity for user session management

- Created UserActiveContext entity to manage user active sessions.

feat(config): implement SiteConfigController for managing site settings

- Added SiteConfigController to handle fetching and updating site configuration settings.

feat(config): create SiteConfig entity and repository for configuration management

- Created SiteConfig entity and repository to manage site configuration data.
2026-06-11 12:20:12 +03:30

136 lines
3.6 KiB
TypeScript

import { create } from 'zustand';
import { persist } from 'zustand/middleware';
export interface ContextItem {
type: 'doctor' | 'clinic';
db_uuid: string;
name: string;
role: 'admin' | 'clinic' | 'doctor' | 'secretary' | 'user';
permissions?: Record<string, any>;
}
interface AuthState {
token: string | null;
refreshToken: string | null;
isAuthenticated: boolean;
userUuid: string | null;
userName: string | null;
primaryRole: 'admin' | 'clinic' | 'doctor' | 'secretary' | 'user' | null;
dbUuid: string | null;
dbKey: string | null;
context: ContextItem | null;
availableContexts: ContextItem[];
login: (token: string, refreshToken: string) => void;
logout: () => void;
fetchMe: () => Promise<void>;
switchContext: (dbUuid: string) => Promise<void>;
}
function getToken(): string | null {
try {
const raw = localStorage.getItem('clinicpro-auth');
if (!raw) return null;
return JSON.parse(raw)?.state?.token ?? null;
} catch {
return null;
}
}
async function apiFetch(path: string, options: RequestInit = {}) {
const token = getToken();
const res = await fetch(path, {
...options,
headers: {
'Content-Type': 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
...options.headers,
},
});
return res.json();
}
export const useAuthStore = create<AuthState>()(
persist(
(set, get) => ({
token: null,
refreshToken: null,
isAuthenticated: false,
userUuid: null,
userName: null,
primaryRole: null,
dbUuid: null,
dbKey: null,
context: null,
availableContexts: [],
login: (token, refreshToken) => {
set({ token, refreshToken, isAuthenticated: true });
get().fetchMe();
},
logout: () =>
set({
token: null,
refreshToken: null,
isAuthenticated: false,
userUuid: null,
userName: null,
primaryRole: null,
dbUuid: null,
dbKey: null,
context: null,
availableContexts: [],
}),
fetchMe: async () => {
try {
const res = await apiFetch('/oauth/userinfo');
if (!res.success) return;
const d = res.data;
set({
userUuid: d.uuid,
userName: d.realName,
primaryRole: d.primary_role ?? null,
dbUuid: d.db_uuid ?? null,
dbKey: d.db_key ?? null,
context: d.context ?? null,
availableContexts: d.available_contexts ?? [],
});
} catch {
// شبکه در دسترس نیست — state دست‌نخورده بماند
}
},
switchContext: async (dbUuid: string) => {
const res = await apiFetch('/api/v1/auth/switch-context', {
method: 'POST',
body: JSON.stringify({ db_uuid: dbUuid }),
});
if (res.success) {
set({
dbUuid: res.data.db_uuid,
dbKey: res.data.db_key,
context: res.data.context,
});
}
},
}),
{
name: 'clinicpro-auth',
partialize: (s) => ({
token: s.token,
refreshToken: s.refreshToken,
isAuthenticated: s.isAuthenticated,
userUuid: s.userUuid,
userName: s.userName,
primaryRole: s.primaryRole,
dbUuid: s.dbUuid,
dbKey: s.dbKey,
context: s.context,
availableContexts: s.availableContexts,
}),
}
)
);