feat: implement onboarding flow with complex creation and email verification, and add Zustand for state management

This commit is contained in:
Jose Selesan
2026-04-21 09:14:45 -03:00
parent 23e4218f6f
commit 07408dbbbe
29 changed files with 843 additions and 71 deletions

View File

@@ -53,4 +53,4 @@ export function setApiAccessToken(_token: string | null) {
// accessToken = token;
}
export type ApiClient = typeof apiClient;
export type ApiClient = typeof apiClient;

View File

@@ -31,4 +31,4 @@ export function configureApiClient(nextHandlers: ErrorHandlers) {
handlers.onError = nextHandlers.onError;
}
export { handlers };
export { handlers };

View File

@@ -57,4 +57,4 @@ http.interceptors.response.use(
return Promise.reject(normalized);
}
);
);

View File

@@ -15,4 +15,4 @@ export {
listByComplex,
createAdmin,
updateStatus,
} from './resources/bookings';
} from './resources/bookings';

View File

@@ -57,4 +57,4 @@ export async function updateStatus(bookingId: string, payload: UpdateAdminBookin
payload
);
return response.data;
}
}

View File

@@ -9,7 +9,9 @@ import type {
} from '@repo/api-contract';
import { http } from '../http';
export async function create(payload: CreateComplexPayload) {
export async function create(
payload: CreateComplexPayload & { adminEmail?: string; userId?: string }
) {
const response = await http.post<CreateComplexResponse>('/api/complexes', payload);
return response.data;
}
@@ -46,4 +48,4 @@ export async function select(payload: SelectComplexInput) {
{ headers: { 'Content-Type': 'application/json' } }
);
return response.data;
}
}

View File

@@ -14,4 +14,4 @@ export async function create(complexId: string, payload: CreateCourtInput) {
export async function update(id: string, payload: UpdateCourtInput) {
const response = await http.patch<Court>(`/api/courts/${id}`, payload);
return response.data;
}
}

View File

@@ -32,9 +32,6 @@ export async function resendOtp(payload: OnboardingResendOtpInput) {
}
export async function complete(payload: OnboardingCompleteInput) {
const response = await http.post<OnboardingCompleteResponse>(
'/api/onboarding/complete',
payload
);
const response = await http.post<OnboardingCompleteResponse>('/api/onboarding/complete', payload);
return response.data;
}
}

View File

@@ -4,4 +4,4 @@ import { http } from '../http';
export async function list() {
const response = await http.get<PlanSummary[]>('/api/plans');
return response.data;
}
}

View File

@@ -14,4 +14,4 @@ export async function create(payload: CreateSportInput) {
export async function update(id: string, payload: UpdateSportInput) {
const response = await http.patch<Sport>(`/api/sports/${id}`, payload);
return response.data;
}
}

View File

@@ -4,4 +4,4 @@ import { http } from '../http';
export async function getProfile() {
const response = await http.get<UserProfileResponse>('/api/user/profile');
return response.data;
}
}

View File

@@ -1,4 +1,5 @@
const CURRENT_COMPLEX_SLUG_KEY = 'current-complex-slug';
export const COMPLEX_CHANGE_EVENT = 'complex-change';
export function getCurrentComplexSlug(): string | null {
if (typeof window === 'undefined') return null;
@@ -8,4 +9,5 @@ export function getCurrentComplexSlug(): string | null {
export function setCurrentComplexSlug(complexSlug: string) {
if (typeof window === 'undefined') return;
window.localStorage.setItem(CURRENT_COMPLEX_SLUG_KEY, complexSlug);
window.dispatchEvent(new Event(COMPLEX_CHANGE_EVENT));
}

View File

@@ -0,0 +1,19 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
interface CurrentComplexState {
currentComplexSlug: string | null;
setCurrentComplex: (slug: string | null) => void;
}
export const useCurrentComplexStore = create<CurrentComplexState>()(
persist(
(set) => ({
currentComplexSlug: null,
setCurrentComplex: (slug) => set({ currentComplexSlug: slug }),
}),
{
name: 'current-complex-slug',
}
)
);