- Add /api/v1/ prefix to all Unit 2 API calls (Setup/status, Setup/owner,
Invitation/validate, Invitation/complete) to match backend ApiPrefixConvention
- Fix setup status endpoint to POST /api/v1/Setup/owner (not /Setup)
- Handle PascalCase 'Initialized' response from .NET backend without camelCase policy
- Update all MSW mock handlers to match corrected /api/v1/ URL patterns
- Remove unused imports from RouteGuard.test.tsx
Root cause: backend uses ApiPrefixConvention('api/v1') but frontend calls
were missing the prefix, and .NET defaults to PascalCase JSON serialization.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
84 lines
2.2 KiB
TypeScript
84 lines
2.2 KiB
TypeScript
import { useState, useCallback, useEffect } from 'react';
|
|
import { api } from '../lib/api-client';
|
|
|
|
interface InvitationValidationResponse {
|
|
valid: boolean;
|
|
email?: string;
|
|
error?: string;
|
|
}
|
|
|
|
interface InvitationCompleteRequest {
|
|
token: string;
|
|
name: string;
|
|
password: string;
|
|
}
|
|
|
|
interface InvitationCompleteResponse {
|
|
message: string;
|
|
user: {
|
|
id: string;
|
|
name: string;
|
|
email: string;
|
|
role: string;
|
|
};
|
|
}
|
|
|
|
export function useValidateInvitation(token: string | null) {
|
|
const [data, setData] = useState<InvitationValidationResponse | null>(null);
|
|
const [isPending, setIsPending] = useState(false);
|
|
const [error, setError] = useState<Error | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (!token) return;
|
|
|
|
const fetchValidation = async () => {
|
|
setIsPending(true);
|
|
setError(null);
|
|
try {
|
|
const url = `/api/v1/Invitation/validate?token=${encodeURIComponent(token)}`;
|
|
const response = await api.get(url);
|
|
setData(response as InvitationValidationResponse);
|
|
} catch (err: unknown) {
|
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
setData(null);
|
|
} finally {
|
|
setIsPending(false);
|
|
}
|
|
};
|
|
|
|
fetchValidation();
|
|
}, [token]);
|
|
|
|
return {
|
|
data,
|
|
isPending,
|
|
error
|
|
};
|
|
}
|
|
|
|
export function useCompleteInvitation() {
|
|
const [isPending, setIsPending] = useState(false);
|
|
const [error, setError] = useState<Error | null>(null);
|
|
|
|
const mutateAsync = useCallback(async (data: InvitationCompleteRequest): Promise<InvitationCompleteResponse> => {
|
|
setIsPending(true);
|
|
setError(null);
|
|
try {
|
|
const response = await api.post('/api/v1/Invitation/complete', data);
|
|
return response as InvitationCompleteResponse;
|
|
} catch (err: unknown) {
|
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
setError(error);
|
|
throw error;
|
|
} finally {
|
|
setIsPending(false);
|
|
}
|
|
}, []);
|
|
|
|
return {
|
|
mutateAsync,
|
|
isPending,
|
|
error
|
|
};
|
|
}
|