all changes

This commit is contained in:
Emmanuel committed 2026-08-28 21:17:22 -05:00
1 parent cba8d4055b
commit 9dfced04f1
103 files changed
+7378 -31250

No files matched your search

+14
View File
@@ -0,0 +1,14 @@
export const API_URL = process.env.NEXT_PUBLIC_API_URL ?? "https://localhost:7030";
export async function apiFetch<T>(path: string): Promise<T> {
const res = await fetch(`${API_URL}${path}`);
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
return res.json() as Promise<T>;
}
/** Convierte rutas relativas del API (/uploads/...) a URL absoluta */
export function assetUrl(path?: string | null): string | undefined {
if (!path) return undefined;
if (path.startsWith('http')) return path;
return `${API_URL}${path}`;
}
+23
View File
@@ -0,0 +1,23 @@
import { useQuery } from '@tanstack/react-query';
import { apiFetch } from './api';
export interface BlogPost {
id: string;
title: string;
slug: string;
summary: string;
content: string;
category: string;
imageUrl?: string;
authorName?: string;
isPublished: boolean;
publishedAt?: string;
}
export function useBlogPosts() {
return useQuery<BlogPost[]>({
queryKey: ['blog'],
queryFn: () => apiFetch<BlogPost[]>('/api/blog'),
staleTime: 1000 * 60 * 5,
});
}
+17
View File
@@ -0,0 +1,17 @@
import { useQuery } from '@tanstack/react-query';
import { apiFetch } from './api';
export interface Company {
id: string;
name: string;
logoUrl?: string;
showInLanding?: boolean;
}
export function useCompanies() {
return useQuery<Company[]>({
queryKey: ['companies'],
queryFn: () => apiFetch<Company[]>('/api/companies'),
staleTime: 1000 * 60 * 5,
});
}
+19
View File
@@ -0,0 +1,19 @@
import { useQuery } from '@tanstack/react-query';
import { apiFetch } from './api';
export interface Product {
id: string;
name: string;
description?: string;
imageUrl?: string;
badges: string[];
isActive: boolean;
}
export function useProducts() {
return useQuery<Product[]>({
queryKey: ['products'],
queryFn: () => apiFetch<Product[]>('/api/products'),
staleTime: 1000 * 60 * 5,
});
}
+40
View File
@@ -0,0 +1,40 @@
import { useQuery } from '@tanstack/react-query';
import { apiFetch } from './api';
export interface TeamMember {
id: string;
firstName: string;
lastName: string;
positionName?: string;
departmentName?: string;
departmentOrder?: number;
positionOrder?: number;
}
export interface Department {
name: string;
order: number;
members: TeamMember[];
}
export function useTeam() {
return useQuery<TeamMember[]>({
queryKey: ['team'],
queryFn: () => apiFetch<TeamMember[]>('/api/employees/public'),
staleTime: 1000 * 60 * 5,
});
}
export function groupByDepartment(members: TeamMember[]): Department[] {
const map = new Map<string, Department>();
for (const m of members) {
const key = m.departmentName ?? 'Sin departamento';
if (!map.has(key)) {
map.set(key, { name: key, order: m.departmentOrder ?? 99, members: [] });
}
map.get(key)!.members.push(m);
}
return Array.from(map.values()).sort((a, b) => a.order - b.order);
}
+31
View File
@@ -0,0 +1,31 @@
import { useQuery } from '@tanstack/react-query';
import { apiFetch } from './api';
interface OnboardingCompleted {
clientCompanyName: string;
testimonialQuote?: string;
testimonialAuthor?: string;
}
export interface Testimonial {
quote: string;
author: string;
company: string;
}
export function useTestimonials() {
return useQuery<Testimonial[]>({
queryKey: ['testimonials'],
queryFn: async () => {
const data = await apiFetch<OnboardingCompleted[]>('/api/onboarding/completed');
return data
.filter(o => o.testimonialQuote)
.map(o => ({
quote: o.testimonialQuote!,
author: o.testimonialAuthor ?? '',
company: o.clientCompanyName,
}));
},
staleTime: 1000 * 60 * 5,
});
}