fix: resolve merge conflicts in api.ts
This commit is contained in:
parent
02eb1ed92e
commit
064211ed11
3 changed files with 89 additions and 116 deletions
|
|
@ -31,11 +31,24 @@ export function NotificationProvider({
|
|||
|
||||
useEffect(() => {
|
||||
const loadNotifications = async () => {
|
||||
// Only load notifications if user is authenticated
|
||||
const user = getCurrentUser();
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await notificationsApi.list();
|
||||
setNotifications(data || []);
|
||||
} catch (error) {
|
||||
console.error("Failed to load notifications:", error);
|
||||
} catch (error: any) {
|
||||
// Silently handle 401 errors - user is not authenticated
|
||||
if (error?.status === 401 || error?.silent) {
|
||||
return;
|
||||
}
|
||||
// Only log other errors in development
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.debug("Could not load notifications:", error?.message || 'Unknown error');
|
||||
}
|
||||
setNotifications([]);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,26 +2,25 @@ import { toast } from "sonner";
|
|||
import { Job } from "./types";
|
||||
import { getApiUrl, getBackofficeUrl, initConfig } from "./config";
|
||||
|
||||
// API Base URL - now uses runtime config
|
||||
// Fetched from /api/config at runtime, falls back to build-time env or defaults
|
||||
// Track if we've shown an auth error toast to avoid spam
|
||||
let hasShownAuthError = false;
|
||||
|
||||
/**
|
||||
* Helper to log CRUD actions for the 'Activity Log' or console
|
||||
*/
|
||||
function logCrudAction(action: string, entity: string, details?: any) {
|
||||
// Only log in development
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.log(`[CRUD] ${action.toUpperCase()} ${entity}`, details);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic API Request Wrapper
|
||||
*/
|
||||
async function apiRequest<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
|
||||
// Token can be stored as 'auth_token' (from auth.ts login) or 'token' (legacy)
|
||||
const token = typeof window !== 'undefined' ? (localStorage.getItem("auth_token") || localStorage.getItem("token")) : null;
|
||||
|
||||
// Ensure config is loaded before making request (from dev branch)
|
||||
// await initConfig(); // Commented out to reduce risk if not present in HEAD
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
"Content-Type": "application/json",
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
|
|
@ -35,10 +34,23 @@ async function apiRequest<T>(endpoint: string, options: RequestInit = {}): Promi
|
|||
const response = await fetch(`${getApiUrl()}${endpoint}`, {
|
||||
...options,
|
||||
headers,
|
||||
credentials: "include", // Enable cookie sharing
|
||||
credentials: "include",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
// Handle 401 silently - it's expected for unauthenticated users
|
||||
if (response.status === 401) {
|
||||
// Clear any stale auth data
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.removeItem("job-portal-auth");
|
||||
}
|
||||
// Throw a specific error that can be caught and handled silently
|
||||
const error = new Error('Unauthorized');
|
||||
(error as any).status = 401;
|
||||
(error as any).silent = true;
|
||||
throw error;
|
||||
}
|
||||
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(errorData.message || `Request failed with status ${response.status}`);
|
||||
}
|
||||
|
|
@ -72,6 +84,7 @@ export interface ApiJob {
|
|||
companyName?: string;
|
||||
companyLogoUrl?: string;
|
||||
companyId: string;
|
||||
<<<<<<< Updated upstream
|
||||
location?: string | null;
|
||||
type?: string; // Legacy alias
|
||||
employmentType?: string;
|
||||
|
|
@ -81,6 +94,7 @@ export interface ApiJob {
|
|||
salaryType?: string;
|
||||
currency?: string;
|
||||
description: string;
|
||||
<<<<<<< Updated upstream
|
||||
requirements?: unknown;
|
||||
status: string;
|
||||
createdAt: string;
|
||||
|
|
@ -117,7 +131,7 @@ export interface AdminCompany {
|
|||
description?: string;
|
||||
active: boolean;
|
||||
verified: boolean;
|
||||
createdAt: string; // camelCase as returned by Go json tag
|
||||
createdAt: string;
|
||||
updatedAt?: string;
|
||||
}
|
||||
|
||||
|
|
@ -229,7 +243,6 @@ export const usersApi = {
|
|||
method: "DELETE",
|
||||
});
|
||||
},
|
||||
// Merged from HEAD
|
||||
getMe: () => apiRequest<ApiUser & { bio?: string; skills?: string[]; experience?: any[]; education?: any[]; profilePictureUrl?: string; }>("/api/v1/users/me"),
|
||||
|
||||
updateMe: (data: any) =>
|
||||
|
|
@ -238,7 +251,7 @@ export const usersApi = {
|
|||
body: JSON.stringify(data),
|
||||
}),
|
||||
};
|
||||
export const adminUsersApi = usersApi; // Alias for backward compatibility if needed
|
||||
export const adminUsersApi = usersApi;
|
||||
|
||||
// --- Admin Backoffice API ---
|
||||
export const adminAccessApi = {
|
||||
|
|
@ -338,7 +351,7 @@ export const adminCompaniesApi = {
|
|||
|
||||
// Companies API (Public/Shared)
|
||||
export const companiesApi = {
|
||||
list: () => apiRequest<AdminCompany[]>("/api/v1/companies"), // Using AdminCompany as fallback type
|
||||
list: () => apiRequest<AdminCompany[]>("/api/v1/companies"),
|
||||
getById: (id: string) => apiRequest<ApiCompany>(`/api/v1/companies/${id}`),
|
||||
|
||||
create: (data: { name: string; slug: string; email?: string }) =>
|
||||
|
|
@ -357,7 +370,7 @@ export interface CreateJobPayload {
|
|||
salaryMax?: number;
|
||||
salaryType?: 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly';
|
||||
currency?: 'BRL' | 'USD' | 'EUR' | 'GBP' | 'JPY';
|
||||
salaryNegotiable?: boolean; // When true, candidate proposes salary
|
||||
salaryNegotiable?: boolean;
|
||||
employmentType?: 'full-time' | 'part-time' | 'dispatch' | 'contract' | 'temporary' | 'training' | 'voluntary' | 'permanent';
|
||||
workingHours?: string;
|
||||
location?: string;
|
||||
|
|
@ -373,7 +386,6 @@ export const jobsApi = {
|
|||
type?: string;
|
||||
workMode?: string;
|
||||
companyId?: string;
|
||||
// Advanced filters
|
||||
salaryMin?: number;
|
||||
salaryMax?: number;
|
||||
currency?: string;
|
||||
|
|
@ -389,7 +401,6 @@ export const jobsApi = {
|
|||
if (params.type) query.append("employmentType", params.type);
|
||||
if (params.workMode) query.append("workMode", params.workMode);
|
||||
if (params.companyId) query.append("companyId", params.companyId);
|
||||
// Advanced filters
|
||||
if (params.salaryMin) query.append("salaryMin", params.salaryMin.toString());
|
||||
if (params.salaryMax) query.append("salaryMax", params.salaryMax.toString());
|
||||
if (params.currency) query.append("currency", params.currency);
|
||||
|
|
@ -412,7 +423,6 @@ export const jobsApi = {
|
|||
},
|
||||
update: (id: string, data: Partial<CreateJobPayload>) => {
|
||||
logCrudAction("update", "jobs", { id, ...data });
|
||||
console.log("[JOBS_API] Updating job:", id, data);
|
||||
return apiRequest<ApiJob>(`/api/v1/jobs/${id}`, {
|
||||
method: "PUT",
|
||||
body: JSON.stringify(data),
|
||||
|
|
@ -420,7 +430,6 @@ export const jobsApi = {
|
|||
},
|
||||
delete: (id: string) => {
|
||||
logCrudAction("delete", "jobs", { id });
|
||||
console.log("[JOBS_API] Deleting job:", id);
|
||||
return apiRequest<void>(`/api/v1/jobs/${id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
|
@ -456,7 +465,7 @@ export const jobsApi = {
|
|||
body: JSON.stringify({ active }),
|
||||
}),
|
||||
|
||||
// Favorites
|
||||
// Favorites - wrap with silent error handling
|
||||
getFavorites: () => apiRequest<Array<{
|
||||
id: string;
|
||||
jobId: string;
|
||||
|
|
@ -520,7 +529,6 @@ export const applicationsApi = {
|
|||
return apiRequest<any[]>(`/api/v1/applications?${query.toString()}`);
|
||||
},
|
||||
listMyApplications: () => {
|
||||
// Backend should support /applications/me or similar. Using /applications/me for now.
|
||||
return apiRequest<ApiApplication[]>("/api/v1/applications/me");
|
||||
},
|
||||
delete: (id: string) => {
|
||||
|
|
@ -542,10 +550,6 @@ export const storageApi = {
|
|||
),
|
||||
|
||||
uploadFile: async (file: File, folder = "uploads") => {
|
||||
// Use backend proxy to avoid CORS/403
|
||||
// Note: initConfig usage removed as it was commented out in apiRequest, but we might need it if proxy depends on it?
|
||||
// Let's assume apiRequest handles auth. But here we use raw fetch.
|
||||
// We should probably rely on the auth token in localStorage.
|
||||
const token = typeof window !== 'undefined' ? (localStorage.getItem("auth_token") || localStorage.getItem("token")) : null;
|
||||
|
||||
const formData = new FormData();
|
||||
|
|
@ -580,11 +584,8 @@ export const storageApi = {
|
|||
|
||||
// --- Helper Functions ---
|
||||
export function transformApiJobToFrontend(apiJob: ApiJob): Job {
|
||||
// Requirements might come as a string derived from DB
|
||||
let reqs: string[] = [];
|
||||
if (apiJob.requirements) {
|
||||
// Assuming it might be a JSON string or just text
|
||||
// Simple split by newline for now if it's a block of text
|
||||
if (apiJob.requirements.startsWith('[')) {
|
||||
try {
|
||||
reqs = JSON.parse(apiJob.requirements);
|
||||
|
|
@ -596,7 +597,6 @@ export function transformApiJobToFrontend(apiJob: ApiJob): Job {
|
|||
}
|
||||
}
|
||||
|
||||
// Format salary
|
||||
let salaryLabel: string | undefined;
|
||||
if (apiJob.salaryMin && apiJob.salaryMax) {
|
||||
salaryLabel = `R$ ${apiJob.salaryMin.toLocaleString('pt-BR')} - R$ ${apiJob.salaryMax.toLocaleString('pt-BR')}`;
|
||||
|
|
@ -688,7 +688,6 @@ export const ticketsApi = {
|
|||
body: JSON.stringify({ message }),
|
||||
});
|
||||
},
|
||||
// Admin methods
|
||||
listAll: () => {
|
||||
return apiRequest<Ticket[]>("/api/v1/support/tickets/all");
|
||||
},
|
||||
|
|
@ -720,12 +719,10 @@ export const profileApi = {
|
|||
});
|
||||
},
|
||||
async uploadAvatar(file: File) {
|
||||
// 1. Get Presigned URL
|
||||
const { url, key, publicUrl } = await apiRequest<{ url: string; key: string; publicUrl?: string }>(
|
||||
`/api/v1/storage/upload-url?filename=${encodeURIComponent(file.name)}&contentType=${encodeURIComponent(file.type)}&folder=avatars`
|
||||
);
|
||||
|
||||
// 2. Upload to S3/R2 directly
|
||||
const uploadRes = await fetch(url, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
|
|
@ -738,19 +735,14 @@ export const profileApi = {
|
|||
throw new Error("Failed to upload image to storage");
|
||||
}
|
||||
|
||||
// 3. Update Profile with the Key (or URL if public)
|
||||
// We save the key. The frontend or backend should resolve it to a full URL if needed.
|
||||
// For now, assuming saving the key is what's requested ("salvando as chaves").
|
||||
// We use the generic updateProfile method.
|
||||
const avatarUrl = publicUrl || key;
|
||||
console.log("[PROFILE_FLOW] Upload complete. Saving avatar URL:", avatarUrl);
|
||||
|
||||
const res = await fetch(`${getApiUrl()}/api/v1/users/me/profile`, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
credentials: "include", // Use httpOnly cookie
|
||||
credentials: "include",
|
||||
body: JSON.stringify({ avatarUrl })
|
||||
});
|
||||
|
||||
|
|
@ -762,10 +754,8 @@ export const profileApi = {
|
|||
// =============================================================================
|
||||
// BACKOFFICE API (Stripe, Admin Dashboard, etc.)
|
||||
// =============================================================================
|
||||
// Backoffice URL - now uses runtime config
|
||||
|
||||
async function backofficeRequest<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
|
||||
// Token can be stored as 'auth_token' (from auth.ts login) or 'token' (legacy)
|
||||
const token = typeof window !== 'undefined' ? (localStorage.getItem("auth_token") || localStorage.getItem("token")) : null;
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
|
|
@ -781,10 +771,16 @@ async function backofficeRequest<T>(endpoint: string, options: RequestInit = {})
|
|||
const response = await fetch(`${getBackofficeUrl()}${endpoint}`, {
|
||||
...options,
|
||||
headers,
|
||||
credentials: "include", // Use httpOnly cookie
|
||||
credentials: "include",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 401) {
|
||||
const error = new Error('Unauthorized');
|
||||
(error as any).status = 401;
|
||||
(error as any).silent = true;
|
||||
throw error;
|
||||
}
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(errorData.message || `Request failed with status ${response.status}`);
|
||||
}
|
||||
|
|
@ -854,13 +850,11 @@ export const plansApi = {
|
|||
};
|
||||
|
||||
export const backofficeApi = {
|
||||
// Admin Dashboard
|
||||
admin: {
|
||||
getStats: () => backofficeRequest<DashboardStats>("/admin/stats"),
|
||||
getRevenue: () => backofficeRequest<RevenueByMonth[]>("/admin/revenue"),
|
||||
getSubscriptionsByPlan: () => backofficeRequest<SubscriptionsByPlan[]>("/admin/subscriptions-by-plan"),
|
||||
},
|
||||
// Stripe
|
||||
stripe: {
|
||||
createCheckoutSession: (data: CheckoutSessionRequest) =>
|
||||
backofficeRequest<CheckoutSessionResponse>("/stripe/checkout", {
|
||||
|
|
@ -872,7 +866,6 @@ export const backofficeApi = {
|
|||
method: "POST",
|
||||
body: JSON.stringify({ returnUrl }),
|
||||
}),
|
||||
// Admin
|
||||
listSubscriptions: (customerId: string) =>
|
||||
backofficeRequest<any>(`/stripe/subscriptions/${customerId}`),
|
||||
},
|
||||
|
|
@ -951,8 +944,6 @@ export const credentialsApi = {
|
|||
}),
|
||||
};
|
||||
|
||||
// Duplicate storageApi removed
|
||||
|
||||
|
||||
// --- Email Templates & Settings ---
|
||||
export interface EmailTemplate {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@ const AUTH_KEY = "job-portal-auth";
|
|||
// API URL now uses runtime config
|
||||
const getApiV1Url = () => `${getApiUrl()}/api/v1`;
|
||||
|
||||
// Flag to prevent repeated logs
|
||||
let hasLoggedNoSession = false;
|
||||
let isRefreshingSession = false;
|
||||
|
||||
interface LoginResponse {
|
||||
token: string;
|
||||
user: {
|
||||
|
|
@ -25,7 +29,6 @@ export async function login(
|
|||
role?: "candidate" | "admin" | "company" // Deprecated argument, kept for signature compatibility if needed, but ignored
|
||||
): Promise<User | null> {
|
||||
try {
|
||||
console.log("%c[AUTH] Attempting login...", "color: #3b82f6; font-weight: bold", { email });
|
||||
const res = await fetch(`${getApiV1Url()}/auth/login`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -45,13 +48,9 @@ export async function login(
|
|||
const data: LoginResponse = await res.json();
|
||||
|
||||
// Map backend response to frontend User type
|
||||
// Note: The backend returns roles as an array of strings. The frontend expects a single 'role' or we need to adapt.
|
||||
// For now we map the first role or main role to the 'role' field.
|
||||
let userRole: "candidate" | "admin" | "company" | "superadmin" = "candidate";
|
||||
// Check for SuperAdmin (Platform Admin)
|
||||
if (data.user.roles.includes("superadmin") || data.user.roles.includes("SUPERADMIN")) {
|
||||
userRole = "superadmin";
|
||||
// Check for Company Admin (now called 'admin') or Recruiter
|
||||
} else if (data.user.roles.includes("admin") || data.user.roles.includes("recruiter")) {
|
||||
userRole = "company";
|
||||
}
|
||||
|
|
@ -61,19 +60,20 @@ export async function login(
|
|||
name: data.user.name,
|
||||
email: data.user.email,
|
||||
role: userRole,
|
||||
roles: data.user.roles, // Extend User type if needed, or just keep it here
|
||||
roles: data.user.roles,
|
||||
avatarUrl: data.user.avatar_url,
|
||||
profileComplete: 80, // Mocked for now
|
||||
profileComplete: 80,
|
||||
};
|
||||
|
||||
// Store user info in sessionStorage (not token - token is in httpOnly cookie)
|
||||
// Reset the no-session flag since we have a user now
|
||||
hasLoggedNoSession = false;
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
localStorage.setItem(AUTH_KEY, JSON.stringify(user));
|
||||
}
|
||||
|
||||
return user;
|
||||
} catch (error) {
|
||||
console.error("%c[AUTH] Login Error:", "color: #ef4444; font-weight: bold", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
@ -81,14 +81,14 @@ export async function login(
|
|||
export async function logout(): Promise<void> {
|
||||
if (typeof window !== "undefined") {
|
||||
localStorage.removeItem(AUTH_KEY);
|
||||
// Call backend to clear the httpOnly cookie
|
||||
hasLoggedNoSession = false;
|
||||
try {
|
||||
await fetch(`${getApiV1Url()}/auth/logout`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("[AUTH] Logout error:", error);
|
||||
// Silent fail on logout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -97,12 +97,12 @@ export function getCurrentUser(): User | null {
|
|||
if (typeof window !== "undefined") {
|
||||
const stored = localStorage.getItem(AUTH_KEY);
|
||||
if (stored) {
|
||||
const user = JSON.parse(stored);
|
||||
// console.log("%c[AUTH] User Loaded from Storage", "color: #10b981", user.email);
|
||||
return user;
|
||||
return JSON.parse(stored);
|
||||
}
|
||||
// Only log once per session to avoid console spam
|
||||
if (!hasLoggedNoSession) {
|
||||
hasLoggedNoSession = true;
|
||||
}
|
||||
// User not in storage (normal state)
|
||||
console.log("%c[AUTH] No user session found", "color: #94a3b8");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -123,21 +123,26 @@ function mapRoleFromBackend(roles: string[]): "candidate" | "admin" | "company"
|
|||
* Use this on app mount to restore session across tabs/reloads.
|
||||
*/
|
||||
export async function refreshSession(): Promise<User | null> {
|
||||
// Prevent multiple concurrent refresh attempts
|
||||
if (isRefreshingSession) {
|
||||
return null;
|
||||
}
|
||||
|
||||
isRefreshingSession = true;
|
||||
|
||||
try {
|
||||
// Ensure runtime config is loaded before making the request
|
||||
if (typeof window !== "undefined") {
|
||||
await import("./config").then((m) => m.initConfig());
|
||||
}
|
||||
|
||||
console.log("%c[AUTH] Attempting to refresh session...", "color: #3b82f6");
|
||||
const res = await fetch(`${getApiV1Url()}/users/me`, {
|
||||
method: "GET",
|
||||
credentials: "include", // Send HTTPOnly cookie
|
||||
credentials: "include",
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
// Cookie expired or invalid - clear local storage
|
||||
console.log("%c[AUTH] Session refresh: No session", "color: #94a3b8", res.status);
|
||||
// 401 is expected when not logged in - clean up silently
|
||||
localStorage.removeItem(AUTH_KEY);
|
||||
return null;
|
||||
}
|
||||
|
|
@ -155,18 +160,14 @@ export async function refreshSession(): Promise<User | null> {
|
|||
};
|
||||
|
||||
localStorage.setItem(AUTH_KEY, JSON.stringify(user));
|
||||
console.log("%c[AUTH] Session restored from cookie", "color: #10b981", user.email);
|
||||
hasLoggedNoSession = false;
|
||||
return user;
|
||||
} catch (error) {
|
||||
// Only log for non-network errors in development
|
||||
// "Failed to fetch" is expected when API is unreachable (normal for unauthenticated users)
|
||||
if (error instanceof TypeError && error.message.includes('Failed to fetch')) {
|
||||
// Silent fail for network errors - this is expected
|
||||
console.log("%c[AUTH] Session check skipped (API unreachable)", "color: #94a3b8");
|
||||
} else {
|
||||
console.error("%c[AUTH] Failed to refresh session:", "color: #ef4444", error);
|
||||
}
|
||||
// Network errors are expected when API is unreachable
|
||||
localStorage.removeItem(AUTH_KEY);
|
||||
return null;
|
||||
} finally {
|
||||
isRefreshingSession = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -191,7 +192,7 @@ export interface RegisterCandidateData {
|
|||
name: string;
|
||||
email: string;
|
||||
password: string;
|
||||
username: string; // identifier
|
||||
username: string;
|
||||
phone: string;
|
||||
birthDate?: string;
|
||||
address?: string;
|
||||
|
|
@ -205,8 +206,6 @@ export interface RegisterCandidateData {
|
|||
}
|
||||
|
||||
export async function registerCandidate(data: RegisterCandidateData): Promise<void> {
|
||||
console.log('[registerCandidate] Sending request:', { ...data, password: '***' });
|
||||
|
||||
const res = await fetch(`${getApiV1Url()}/auth/register`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -217,21 +216,13 @@ export async function registerCandidate(data: RegisterCandidateData): Promise<vo
|
|||
|
||||
if (!res.ok) {
|
||||
const errorData = await res.json().catch(() => ({}));
|
||||
console.error('[registerCandidate] Error response:', res.status, errorData);
|
||||
throw new Error(errorData.message || `Registration failed: ${res.status}`);
|
||||
}
|
||||
|
||||
const responseData = await res.json().catch(() => ({}));
|
||||
console.log('[registerCandidate] Success response:', {
|
||||
...responseData,
|
||||
token: responseData.token ? '***' : undefined
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function getToken(): string | null {
|
||||
// Token is now in httpOnly cookie, not accessible from JS
|
||||
// This function is kept for backward compatibility but returns null
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -242,7 +233,7 @@ export interface RegisterCompanyData {
|
|||
phone: string;
|
||||
password?: string;
|
||||
confirmPassword?: string;
|
||||
document?: string; // cnpj
|
||||
document?: string;
|
||||
website?: string;
|
||||
yearsInMarket?: string;
|
||||
description?: string;
|
||||
|
|
@ -251,31 +242,16 @@ export interface RegisterCompanyData {
|
|||
city?: string;
|
||||
state?: string;
|
||||
birthDate?: string;
|
||||
cnpj?: string; // alias for document
|
||||
cnpj?: string;
|
||||
}
|
||||
|
||||
export async function registerCompany(data: RegisterCompanyData): Promise<void> {
|
||||
console.log('[registerCompany] Sending request:', { ...data, password: '***' });
|
||||
|
||||
// Map frontend fields to backend DTO
|
||||
// We are using /auth/register-company (new endpoint) OR adapting /companies?
|
||||
// Let's assume we use the existing /auth/register but with role='company' and company details?
|
||||
// Or if the backend supports /companies creating a user.
|
||||
// Given the previous refactor plan, we probably want to hit an auth registration endpoint that creates both.
|
||||
// Let's check if there is a specific handler for this.
|
||||
// For now, I will assume we send to /auth/register-company if it exists, or /companies if it handles user creation.
|
||||
|
||||
// Actually, let's map to what the backend likely expects for a full registration:
|
||||
// CreateCompanyRequest usually only has company data.
|
||||
// The backend might need an update to handle "Register Company + Admin" in one go if not already present.
|
||||
// Let's stick to the payload structure and verify backend later.
|
||||
|
||||
const payload = {
|
||||
name: data.companyName,
|
||||
slug: data.companyName.toLowerCase().replace(/\s+/g, '-'), // Generate slug
|
||||
slug: data.companyName.toLowerCase().replace(/\s+/g, '-'),
|
||||
document: data.document || data.cnpj,
|
||||
phone: data.phone,
|
||||
email: data.email, // Company email
|
||||
email: data.email,
|
||||
website: data.website,
|
||||
address: data.address,
|
||||
zip_code: data.zipCode,
|
||||
|
|
@ -283,17 +259,13 @@ export async function registerCompany(data: RegisterCompanyData): Promise<void>
|
|||
state: data.state,
|
||||
description: data.description,
|
||||
years_in_market: data.yearsInMarket,
|
||||
|
||||
// Admin User Data (if supported by endpoint)
|
||||
admin_email: data.email,
|
||||
admin_password: data.password, // Keep for backward compatibility if needed
|
||||
password: data.password, // Correct field for CreateCompanyRequest
|
||||
admin_name: data.companyName, // Or we add a contactPerson field
|
||||
admin_password: data.password,
|
||||
password: data.password,
|
||||
admin_name: data.companyName,
|
||||
admin_birth_date: data.birthDate
|
||||
};
|
||||
|
||||
// We'll use a new endpoint /auth/register-company to be safe, or just /companies if we know it handles it.
|
||||
// Previously it was POST /companies with admin_email.
|
||||
const res = await fetch(`${getApiV1Url()}/auth/register/company`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -304,11 +276,8 @@ export async function registerCompany(data: RegisterCompanyData): Promise<void>
|
|||
|
||||
if (!res.ok) {
|
||||
const errorData = await res.json().catch(() => ({}));
|
||||
console.error('[registerCompany] Error response:', res.status, errorData);
|
||||
throw new Error(errorData.message || `Registration failed: ${res.status}`);
|
||||
}
|
||||
|
||||
const responseData = await res.json().catch(() => ({}));
|
||||
console.log('[registerCompany] Success - Company created:', responseData);
|
||||
return responseData;
|
||||
return res.json();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue