Exportar excel con imagen y ahora guarda las imagenes como .png
This commit is contained in:
@@ -21,14 +21,14 @@ export default function EditTrainingPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<PageContainer scrollable>
|
||||
<div className="flex-1 space-y-4">
|
||||
<CreateTrainingForm
|
||||
defaultValues={training}
|
||||
onSuccess={() => router.push('/dashboard/formulario')}
|
||||
onCancel={() => router.back()}
|
||||
/>
|
||||
</div>
|
||||
</PageContainer>
|
||||
// <PageContainer scrollable>
|
||||
<div className="p-6 space-y-6">
|
||||
<CreateTrainingForm
|
||||
defaultValues={training}
|
||||
onSuccess={() => router.push('/dashboard/formulario')}
|
||||
onCancel={() => router.back()}
|
||||
/>
|
||||
</div>
|
||||
// </PageContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,17 +23,18 @@ export default async function Page({ searchParams }: PageProps) {
|
||||
} = searchParamsCache.parse(await searchParams);
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<div className="flex flex-1 flex-col space-y-6">
|
||||
<TrainingHeader />
|
||||
<TrainingTableAction />
|
||||
<TrainingList
|
||||
initialPage={page}
|
||||
initialSearch={searchQuery}
|
||||
initialLimit={limit || 10}
|
||||
apiUrl={env.API_URL}
|
||||
/>
|
||||
</div>
|
||||
</PageContainer>
|
||||
// <PageContainer>
|
||||
// <div className="flex flex-1 flex-col space-y-6">
|
||||
< div className="p-6 space-y-6" >
|
||||
<TrainingHeader />
|
||||
<TrainingTableAction />
|
||||
<TrainingList
|
||||
initialPage={page}
|
||||
initialSearch={searchQuery}
|
||||
initialLimit={limit || 10}
|
||||
apiUrl={env.API_URL}
|
||||
/>
|
||||
</div >
|
||||
// </PageContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { auth } from '@/lib/auth';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
export default async function Dashboard() {
|
||||
console.log('La sesion es llamada');
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user) {
|
||||
|
||||
@@ -44,6 +44,7 @@ const RootLayout = async ({
|
||||
}: Readonly<{
|
||||
children: ReactNode;
|
||||
}>) => {
|
||||
console.log('La sesion es llamada');
|
||||
const session = await auth();
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
'use server';
|
||||
import { safeFetchApi } from '@/lib';
|
||||
import { safeFetchApi } from '@/lib/fetch.api';
|
||||
import { loginResponseSchema, UserFormValue } from '../schemas/login';
|
||||
|
||||
type LoginActionSuccess = {
|
||||
@@ -20,9 +20,9 @@ type LoginActionSuccess = {
|
||||
}
|
||||
|
||||
type LoginActionError = {
|
||||
type: 'API_ERROR' | 'VALIDATION_ERROR' | 'UNKNOWN_ERROR'; // **Asegúrate de que el tipo de `type` sea este aquí**
|
||||
message: string;
|
||||
details?: any;
|
||||
type: 'API_ERROR' | 'VALIDATION_ERROR' | 'UNKNOWN_ERROR'; // **Asegúrate de que el tipo de `type` sea este aquí**
|
||||
message: string;
|
||||
details?: any;
|
||||
};
|
||||
|
||||
// Si SignInAction también puede devolver null, asegúralo en su tipo de retorno
|
||||
@@ -37,7 +37,7 @@ export const SignInAction = async (payload: UserFormValue): Promise<LoginActionR
|
||||
);
|
||||
if (error) {
|
||||
return {
|
||||
type: error.type as 'API_ERROR' | 'VALIDATION_ERROR' | 'UNKNOWN_ERROR',
|
||||
type: error.type as 'API_ERROR' | 'VALIDATION_ERROR' | 'UNKNOWN_ERROR',
|
||||
message: error.message,
|
||||
details: error.details
|
||||
};
|
||||
|
||||
@@ -90,7 +90,7 @@ export const createTrainingAction = async (
|
||||
payloadToSend = rest as any;
|
||||
}
|
||||
|
||||
console.log(payloadToSend);
|
||||
// console.log(payloadToSend);
|
||||
|
||||
const [error, data] = await safeFetchApi(
|
||||
TrainingMutate,
|
||||
|
||||
@@ -166,7 +166,7 @@ export function CreateTrainingForm({
|
||||
mode: 'onChange',
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Cascading Select Logic
|
||||
const ecoSector = useWatch({ control: form.control, name: 'ecoSector' });
|
||||
const productiveSector = useWatch({
|
||||
@@ -217,7 +217,7 @@ export function CreateTrainingForm({
|
||||
|
||||
const coorMunicipalityOptions =
|
||||
Array.isArray(dataCoorMunicipality?.data) &&
|
||||
dataCoorMunicipality.data.length > 0
|
||||
dataCoorMunicipality.data.length > 0
|
||||
? dataCoorMunicipality.data
|
||||
: [{ id: 0, stateId: 0, name: 'Sin Municipios' }];
|
||||
|
||||
@@ -268,7 +268,7 @@ export function CreateTrainingForm({
|
||||
// 1. Definimos las claves que NO queremos enviar en el bucle general
|
||||
// 'files' se procesa aparte.
|
||||
// 'photo1/2/3' son strings (urls viejas) que no queremos reenviar como texto.
|
||||
const excludedKeys = ['files', 'photo1', 'photo2', 'photo3', 'coorState', 'coorMunicipality', 'coorParish'];
|
||||
const excludedKeys = ['files', 'photo1', 'photo2', 'photo3', 'coorState', 'coorMunicipality', 'coorParish'];
|
||||
|
||||
Object.entries(formData).forEach(([key, value]) => {
|
||||
// 2. Condición actualizada: Si la key está en la lista de excluidos, la saltamos
|
||||
@@ -287,17 +287,17 @@ export function CreateTrainingForm({
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 2. Mapeo manual y conversión a numérico
|
||||
// if (formData.state) {
|
||||
// data.append('state', Number(formData.state).toString());
|
||||
// }
|
||||
// if (formData.municipality) {
|
||||
// data.append('municipality', Number(formData.municipality).toString());
|
||||
// }
|
||||
// if (formData.parish) {
|
||||
// data.append('parish', Number(formData.parish).toString());
|
||||
// }
|
||||
|
||||
// 2. Mapeo manual y conversión a numérico
|
||||
// if (formData.state) {
|
||||
// data.append('state', Number(formData.state).toString());
|
||||
// }
|
||||
// if (formData.municipality) {
|
||||
// data.append('municipality', Number(formData.municipality).toString());
|
||||
// }
|
||||
// if (formData.parish) {
|
||||
// data.append('parish', Number(formData.parish).toString());
|
||||
// }
|
||||
if (defaultValues?.id) {
|
||||
data.append('id', defaultValues.id.toString());
|
||||
}
|
||||
@@ -305,24 +305,24 @@ export function CreateTrainingForm({
|
||||
// 4. Aquí se agregan las NUEVAS fotos (binary) si el usuario seleccionó alguna
|
||||
selectedFiles.forEach((file) => {
|
||||
data.append('files', file);
|
||||
});
|
||||
console.log(data);
|
||||
console.log(file);
|
||||
});
|
||||
const mutation = defaultValues?.id ? updateTraining : createTraining;
|
||||
|
||||
// mutation(data as any, {
|
||||
// onSuccess: () => {
|
||||
// form.reset();
|
||||
// setSelectedFiles([]);
|
||||
// onSuccess?.();
|
||||
// },
|
||||
// onError: (e) => {
|
||||
// console.error(e);
|
||||
// form.setError('root', {
|
||||
// type: 'manual',
|
||||
// message: 'Error al guardar el registro',
|
||||
// });
|
||||
// },
|
||||
// });
|
||||
mutation(data as any, {
|
||||
onSuccess: () => {
|
||||
form.reset();
|
||||
setSelectedFiles([]);
|
||||
onSuccess?.();
|
||||
},
|
||||
onError: (e) => {
|
||||
console.error(e);
|
||||
form.setError('root', {
|
||||
type: 'manual',
|
||||
message: 'Error al guardar el registro',
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -417,7 +417,7 @@ export function CreateTrainingForm({
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="state"
|
||||
render={({ field }) => (
|
||||
@@ -921,7 +921,7 @@ export function CreateTrainingForm({
|
||||
<CardTitle>3. Detalles de la ubicación</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="grid grid-cols-1 lg:grid-cols-2 gap-6 items-start">
|
||||
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="ospAddress"
|
||||
|
||||
@@ -77,7 +77,7 @@ export const CellAction: React.FC<CellActionProps> = ({ data, apiUrl }) => {
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
|
||||
{/* <TooltipProvider>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
@@ -92,7 +92,7 @@ export const CellAction: React.FC<CellActionProps> = ({ data, apiUrl }) => {
|
||||
<p>Exportar Excel</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider> */}
|
||||
</TooltipProvider>
|
||||
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// lib/auth.config.ts
|
||||
import { SignInAction } from '@/feactures/auth/actions/login-action';
|
||||
import { resfreshTokenAction } from '@/feactures/auth/actions/refresh-token-action';
|
||||
import { CredentialsSignin, NextAuthConfig, Session, User } from 'next-auth';
|
||||
import { DefaultJWT } from 'next-auth/jwt';
|
||||
// import { DefaultJWT } from 'next-auth/jwt';
|
||||
import CredentialProvider from 'next-auth/providers/credentials';
|
||||
|
||||
|
||||
@@ -92,8 +91,6 @@ const authConfig: NextAuthConfig = {
|
||||
refresh_token: response?.tokens.refresh_token ?? '',
|
||||
refresh_expire_in: response?.tokens.refresh_expire_in ?? 0,
|
||||
};
|
||||
|
||||
|
||||
},
|
||||
}),
|
||||
],
|
||||
@@ -101,11 +98,7 @@ const authConfig: NextAuthConfig = {
|
||||
signIn: '/', //sigin page
|
||||
},
|
||||
callbacks: {
|
||||
async jwt({ token, user }:{
|
||||
user: User
|
||||
token: any
|
||||
|
||||
}) {
|
||||
async jwt({ token, user }: { user: User, token: any }) {
|
||||
// 1. Manejar el inicio de sesión inicial
|
||||
// El `user` solo se proporciona en el primer inicio de sesión.
|
||||
if (user) {
|
||||
@@ -120,7 +113,6 @@ const authConfig: NextAuthConfig = {
|
||||
refresh_token: user.refresh_token,
|
||||
refresh_expire_in: user.refresh_expire_in
|
||||
}
|
||||
// return token;
|
||||
}
|
||||
|
||||
// 2. Si no es un nuevo login, verificar la expiración del token
|
||||
@@ -131,42 +123,33 @@ const authConfig: NextAuthConfig = {
|
||||
return token; // Si no ha expirado, no hacer nada y devolver el token actual
|
||||
}
|
||||
|
||||
// console.log("Now Access Expire:",token.access_expire_in);
|
||||
|
||||
|
||||
// 3. Si el token de acceso ha expirado, verificar el refresh token
|
||||
// console.log("Access token ha expirado. Verificando refresh token...");
|
||||
if (now > (token.refresh_expire_in as number)) {
|
||||
// console.log("Refresh token ha expirado. Forzando logout.");
|
||||
return null; // Forzar el logout al devolver null
|
||||
}
|
||||
|
||||
// console.log("token:", token.refresh_token);
|
||||
|
||||
|
||||
// 4. Si el token de acceso ha expirado pero el refresh token es válido, renovar
|
||||
console.log("Renovando token de acceso...");
|
||||
try {
|
||||
const refresh_token = { token: token.refresh_token as string, user_id: Number(token.id) as number}
|
||||
|
||||
const res = await resfreshTokenAction(refresh_token);
|
||||
const refresh_token = { token: token.refresh_token as string, user_id: Number(token.id) as number }
|
||||
|
||||
// console.log('res', res);
|
||||
|
||||
const res = await resfreshTokenAction(refresh_token);
|
||||
|
||||
if (!res || !res.tokens) {
|
||||
throw new Error('Fallo en la respuesta de la API de refresco.');
|
||||
}
|
||||
}
|
||||
|
||||
// Actualizar el token directamente con los nuevos valores
|
||||
token.access_token = res.tokens.access_token;
|
||||
token.access_expire_in = res.tokens.access_expire_in;
|
||||
token.refresh_token = res.tokens.refresh_token;
|
||||
token.refresh_expire_in = res.tokens.refresh_expire_in;
|
||||
|
||||
console.log("Token renovado exitosamente.");
|
||||
return token;
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error al renovar el token: ", error);
|
||||
console.error(error);
|
||||
return null; // Fallo al renovar, forzar logout
|
||||
}
|
||||
},
|
||||
@@ -182,6 +165,7 @@ const authConfig: NextAuthConfig = {
|
||||
email: token.email as string,
|
||||
role: token.role as Array<{ id: number; rol: string }>,
|
||||
};
|
||||
console.log("Session: Habilitado");
|
||||
return session;
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user