Crear-editar productos, depuracion de archivos users
This commit is contained in:
@@ -18,12 +18,19 @@ export class CreateProductDto {
|
|||||||
price: string;
|
price: string;
|
||||||
|
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@IsString({
|
@IsInt({
|
||||||
message: 'stock must be a number',
|
message: 'stock must be a number',
|
||||||
})
|
})
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
stock: number;
|
stock: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsInt({
|
||||||
|
message: 'stock must be a number',
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
userId: number;
|
||||||
|
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@IsString({
|
@IsString({
|
||||||
message: 'urlImg must be a string',
|
message: 'urlImg must be a string',
|
||||||
|
|||||||
@@ -5,4 +5,15 @@ export class Product {
|
|||||||
price: string;
|
price: string;
|
||||||
stock: number;
|
stock: number;
|
||||||
urlImg: string;
|
urlImg: string;
|
||||||
|
UserId?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateProduct {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
price: string;
|
||||||
|
stock: string;
|
||||||
|
urlImg: string;
|
||||||
|
UserId: number;
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ import { InventoryService } from './inventory.service';
|
|||||||
import { CreateProductDto } from './dto/create-product.dto';
|
import { CreateProductDto } from './dto/create-product.dto';
|
||||||
import { UpdateProductDto } from './dto/update-product.dto';
|
import { UpdateProductDto } from './dto/update-product.dto';
|
||||||
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||||
import { Roles } from '../../common/decorators/roles.decorator';
|
// import { Roles } from '../../common/decorators/roles.decorator';
|
||||||
import { PaginationDto } from '../../common/dto/pagination.dto';
|
import { PaginationDto } from '../../common/dto/pagination.dto';
|
||||||
|
|
||||||
@ApiTags('inventory')
|
@ApiTags('inventory')
|
||||||
@@ -42,22 +42,19 @@ export class UsersController {
|
|||||||
@Body() createUserDto: CreateProductDto,
|
@Body() createUserDto: CreateProductDto,
|
||||||
@Query('roleId') roleId?: string,
|
@Query('roleId') roleId?: string,
|
||||||
) {
|
) {
|
||||||
const data = await this.inventoryService.create(
|
const data = await this.inventoryService.create(createUserDto)
|
||||||
createUserDto,
|
|
||||||
roleId ? parseInt(roleId) : undefined,
|
|
||||||
);
|
|
||||||
return { message: 'User created successfully', data };
|
return { message: 'User created successfully', data };
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Patch(':id')
|
@Patch(':id')
|
||||||
// @Roles('admin')
|
// @Roles('admin')
|
||||||
// @ApiOperation({ summary: 'Update a user' })
|
@ApiOperation({ summary: 'Update a product' })
|
||||||
// @ApiResponse({ status: 200, description: 'User updated successfully.' })
|
@ApiResponse({ status: 200, description: 'Product updated successfully.' })
|
||||||
// @ApiResponse({ status: 404, description: 'User not found.' })
|
@ApiResponse({ status: 404, description: 'Product not found.' })
|
||||||
// async update(@Param('id') id: string, @Body() UpdateProductDto: UpdateProductDto) {
|
async update(@Param('id') id: string, @Body() UpdateProductDto: UpdateProductDto) {
|
||||||
// const data = await this.inventoryService.update(id, UpdateProductDto);
|
const data = await this.inventoryService.update(id, UpdateProductDto);
|
||||||
// return { message: 'User updated successfully', data };
|
return { message: 'User updated successfully', data };
|
||||||
// }
|
}
|
||||||
|
|
||||||
// @Delete(':id')
|
// @Delete(':id')
|
||||||
// @Roles('admin')
|
// @Roles('admin')
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { products } from 'src/database/index';
|
|||||||
import { eq, like, or, SQL, sql, and, not } from 'drizzle-orm';
|
import { eq, like, or, SQL, sql, and, not } from 'drizzle-orm';
|
||||||
import { CreateProductDto } from './dto/create-product.dto';
|
import { CreateProductDto } from './dto/create-product.dto';
|
||||||
import { UpdateProductDto } from './dto/update-product.dto';
|
import { UpdateProductDto } from './dto/update-product.dto';
|
||||||
import { Product } from './entities/inventory.entity';
|
import { Product, CreateProduct } from './entities/inventory.entity';
|
||||||
import { PaginationDto } from '../../common/dto/pagination.dto';
|
import { PaginationDto } from '../../common/dto/pagination.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -54,13 +54,8 @@ export class InventoryService {
|
|||||||
price: products.price,
|
price: products.price,
|
||||||
urlImg: products.urlImg,
|
urlImg: products.urlImg,
|
||||||
stock: products.stock,
|
stock: products.stock,
|
||||||
// price: products.price,
|
|
||||||
// quantity: products.quantity,
|
|
||||||
// isActive: products.isActive
|
|
||||||
})
|
})
|
||||||
.from(products)
|
.from(products)
|
||||||
// .leftJoin(usersRole, eq(usersRole.userId, users.id))
|
|
||||||
// .leftJoin(roles, eq(roles.id, usersRole.roleId))
|
|
||||||
.where(searchCondition)
|
.where(searchCondition)
|
||||||
.orderBy(orderBy)
|
.orderBy(orderBy)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
@@ -77,9 +72,6 @@ export class InventoryService {
|
|||||||
nextPage: page < totalPages ? page + 1 : null,
|
nextPage: page < totalPages ? page + 1 : null,
|
||||||
previousPage: page > 1 ? page - 1 : null,
|
previousPage: page > 1 ? page - 1 : null,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
return { data, meta };
|
return { data, meta };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,16 +86,10 @@ export class InventoryService {
|
|||||||
stock: products.stock
|
stock: products.stock
|
||||||
})
|
})
|
||||||
.from(products)
|
.from(products)
|
||||||
// .leftJoin(usersRole, eq(usersRole.userId, users.id))
|
|
||||||
// .leftJoin(roles, eq(roles.id, usersRole.roleId))
|
|
||||||
// .leftJoin(schema.states, eq(schema.states.id, users.state))
|
|
||||||
// .leftJoin(schema.municipalities, eq(schema.municipalities.id, users.municipality))
|
|
||||||
// .leftJoin(schema.parishes, eq(schema.parishes.id, users.parish))
|
|
||||||
|
|
||||||
.where(eq(products.id, parseInt(id)));
|
.where(eq(products.id, parseInt(id)));
|
||||||
|
|
||||||
if (find.length === 0) {
|
if (find.length === 0) {
|
||||||
throw new HttpException('User does not exist', HttpStatus.BAD_REQUEST);
|
throw new HttpException('Product does not exist', HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
return find[0];
|
return find[0];
|
||||||
@@ -111,14 +97,13 @@ export class InventoryService {
|
|||||||
|
|
||||||
// Rest of the service remains the same
|
// Rest of the service remains the same
|
||||||
async create(
|
async create(
|
||||||
createProductDto: CreateProductDto,
|
createProductDto: CreateProductDto
|
||||||
roleId: number = 2,
|
): Promise<any> {
|
||||||
): Promise<Product> {
|
|
||||||
|
|
||||||
|
|
||||||
// Start a transaction
|
// Start a transaction
|
||||||
return await this.drizzle.transaction(async (tx) => {
|
return await this.drizzle.transaction(async (tx) => {
|
||||||
// Create the user
|
|
||||||
const [newProduct] = await tx
|
const [newProduct] = await tx
|
||||||
.insert(products)
|
.insert(products)
|
||||||
.values({
|
.values({
|
||||||
@@ -126,72 +111,33 @@ export class InventoryService {
|
|||||||
description: createProductDto.description,
|
description: createProductDto.description,
|
||||||
price: createProductDto.price,
|
price: createProductDto.price,
|
||||||
urlImg: createProductDto.urlImg,
|
urlImg: createProductDto.urlImg,
|
||||||
stock: createProductDto.stock
|
stock: createProductDto.stock,
|
||||||
|
userId: createProductDto.userId
|
||||||
})
|
})
|
||||||
.returning();
|
.returning();
|
||||||
|
return newProduct
|
||||||
// Assign role to user
|
|
||||||
// await tx.insert(usersRole).values({
|
|
||||||
// userId: newProduct.id,
|
|
||||||
// roleId: roleId,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// Return the created user with role
|
|
||||||
// const [userWithRole] = await tx
|
|
||||||
// .select({
|
|
||||||
// id: users.id,
|
|
||||||
// username: users.username,
|
|
||||||
// email: users.email,
|
|
||||||
// fullname: users.fullname,
|
|
||||||
// phone: users.phone,
|
|
||||||
// isActive: users.isActive,
|
|
||||||
// role: roles.name,
|
|
||||||
// })
|
|
||||||
// .from(users)
|
|
||||||
// .leftJoin(usersRole, eq(usersRole.userId, users.id))
|
|
||||||
// .leftJoin(roles, eq(roles.id, usersRole.roleId))
|
|
||||||
// .where(eq(users.id, newProduct.id));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return this.findOne(String(newProduct.id));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// async update(id: string, updateUserDto: UpdateUserDto): Promise<User> {
|
async update(id: string, updateProductDto: UpdateProductDto): Promise<Product> {
|
||||||
// const userId = parseInt(id);
|
const productId = parseInt(id);
|
||||||
|
|
||||||
// // Check if user exists
|
// Check if exists
|
||||||
// await this.findOne(id);
|
await this.findOne(id);
|
||||||
|
|
||||||
// // Prepare update data
|
// Prepare update data
|
||||||
// const updateData: any = {};
|
const updateData: any = {};
|
||||||
// if (updateUserDto.username) updateData.username = updateUserDto.username;
|
if (updateProductDto.title) updateData.title = updateProductDto.title;
|
||||||
// if (updateUserDto.email) updateData.email = updateUserDto.email;
|
if (updateProductDto.description) updateData.description = updateProductDto.description;
|
||||||
// if (updateUserDto.fullname) updateData.fullname = updateUserDto.fullname;
|
if (updateProductDto.price) updateData.price = updateProductDto.price;
|
||||||
// if (updateUserDto.password) {
|
if (updateProductDto.stock) updateData.stock = updateProductDto.stock;
|
||||||
// updateData.password = await bcrypt.hash(updateUserDto.password, 10);
|
if (updateProductDto.urlImg) updateData.urlImg = updateProductDto.urlImg;
|
||||||
// }
|
|
||||||
// if (updateUserDto.phone) updateData.phone = updateUserDto.phone;
|
|
||||||
// if (updateUserDto.isActive) updateData.isActive = updateUserDto.isActive;
|
|
||||||
|
|
||||||
// const updateDataRole: any = {};
|
const [updatedProduct] = await this.drizzle.update(products).set(updateData).where(eq(products.id, productId)).returning();
|
||||||
// if (updateUserDto.role) updateDataRole.roleId = updateUserDto.role;
|
return updatedProduct
|
||||||
// // Update user
|
// Return updated user
|
||||||
// await this.drizzle
|
|
||||||
// .update(users)
|
|
||||||
// .set(updateData)
|
|
||||||
// .where(eq(users.id, userId));
|
|
||||||
|
|
||||||
// await this.drizzle
|
|
||||||
// .update(usersRole)
|
|
||||||
// .set(updateDataRole)
|
|
||||||
// .where(eq(usersRole.userId, userId));
|
|
||||||
|
|
||||||
|
|
||||||
// // Return updated user
|
|
||||||
// return this.findOne(id);
|
// return this.findOne(id);
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
|
||||||
// async remove(id: string): Promise<{ message: string, data: User }> {
|
// async remove(id: string): Promise<{ message: string, data: User }> {
|
||||||
|
|||||||
@@ -1,49 +1,14 @@
|
|||||||
'use server';
|
'use server';
|
||||||
import { safeFetchApi } from '@/lib/fetch.api';
|
import { safeFetchApi } from '@/lib/fetch.api';
|
||||||
import {
|
import {
|
||||||
surveysApiResponseSchema,
|
ApiResponseSchema,
|
||||||
CreateUser,
|
InventoryTable,
|
||||||
productMutate,
|
productMutate,
|
||||||
UpdateUser
|
editInventory
|
||||||
} from '../schemas/inventory';
|
} from '../schemas/inventory';
|
||||||
|
|
||||||
import { auth } from '@/lib/auth';
|
import { auth } from '@/lib/auth';
|
||||||
|
|
||||||
|
|
||||||
export const getProfileAction = async () => {
|
|
||||||
const session = await auth()
|
|
||||||
const id = session?.user?.id
|
|
||||||
|
|
||||||
const [error, response] = await safeFetchApi(
|
|
||||||
productMutate,
|
|
||||||
`/users/${id}`,
|
|
||||||
'GET'
|
|
||||||
);
|
|
||||||
if (error) throw new Error(error.message);
|
|
||||||
return response;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateProfileAction = async (payload: UpdateUser) => {
|
|
||||||
const { id, ...payloadWithoutId } = payload;
|
|
||||||
|
|
||||||
const [error, data] = await safeFetchApi(
|
|
||||||
productMutate,
|
|
||||||
`/users/profile/${id}`,
|
|
||||||
'PATCH',
|
|
||||||
payloadWithoutId,
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(payload);
|
|
||||||
if (error) {
|
|
||||||
if (error.message === 'Email already exists') {
|
|
||||||
throw new Error('Ese correo ya está en uso');
|
|
||||||
}
|
|
||||||
// console.error('Error:', error);
|
|
||||||
throw new Error('Error al crear el usuario');
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getInventoryAction = async (params: {
|
export const getInventoryAction = async (params: {
|
||||||
page?: number;
|
page?: number;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
@@ -61,7 +26,7 @@ export const getInventoryAction = async (params: {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [error, response] = await safeFetchApi(
|
const [error, response] = await safeFetchApi(
|
||||||
surveysApiResponseSchema,
|
ApiResponseSchema,
|
||||||
`/inventory?${searchParams}`,
|
`/inventory?${searchParams}`,
|
||||||
'GET',
|
'GET',
|
||||||
);
|
);
|
||||||
@@ -71,8 +36,6 @@ export const getInventoryAction = async (params: {
|
|||||||
|
|
||||||
throw new Error(error.message);
|
throw new Error(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// const transformedData = response?.data ? transformSurvey(response?.data) : undefined;
|
// const transformedData = response?.data ? transformSurvey(response?.data) : undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -90,37 +53,35 @@ export const getInventoryAction = async (params: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createUserAction = async (payload: CreateUser) => {
|
export const createProductAction = async (payload: InventoryTable) => {
|
||||||
const { id, confirmPassword, ...payloadWithoutId } = payload;
|
const session = await auth()
|
||||||
|
const userId = session?.user?.id
|
||||||
|
const { id, ...payloadWithoutId } = payload;
|
||||||
|
|
||||||
|
payloadWithoutId.userId = userId
|
||||||
|
|
||||||
const [error, data] = await safeFetchApi(
|
const [error, data] = await safeFetchApi(
|
||||||
productMutate,
|
productMutate,
|
||||||
'/users',
|
'/inventory',
|
||||||
'POST',
|
'POST',
|
||||||
payloadWithoutId,
|
payloadWithoutId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
if (error.message === 'Username already exists') {
|
console.error(error);
|
||||||
throw new Error('Ese usuario ya existe');
|
|
||||||
}
|
|
||||||
if (error.message === 'Email already exists') {
|
|
||||||
throw new Error('Ese correo ya está en uso');
|
|
||||||
}
|
|
||||||
// console.error('Error:', error);
|
|
||||||
throw new Error('Error al crear el usuario');
|
throw new Error('Error al crear el usuario');
|
||||||
}
|
}
|
||||||
|
|
||||||
return payloadWithoutId;
|
return payloadWithoutId;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateUserAction = async (payload: UpdateUser) => {
|
export const updateUserAction = async (payload: InventoryTable) => {
|
||||||
try {
|
try {
|
||||||
const { id, ...payloadWithoutId } = payload;
|
const { id, ...payloadWithoutId } = payload;
|
||||||
|
|
||||||
const [error, data] = await safeFetchApi(
|
const [error, data] = await safeFetchApi(
|
||||||
productMutate,
|
productMutate,
|
||||||
`/users/${id}`,
|
`/inventory/${id}`,
|
||||||
'PATCH',
|
'PATCH',
|
||||||
payloadWithoutId,
|
payloadWithoutId,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { Button } from '@repo/shadcn/button';
|
import { Button } from '@repo/shadcn/button';
|
||||||
import {
|
import {
|
||||||
@@ -11,38 +10,30 @@ import {
|
|||||||
FormMessage,
|
FormMessage,
|
||||||
} from '@repo/shadcn/form';
|
} from '@repo/shadcn/form';
|
||||||
import { Input } from '@repo/shadcn/input';
|
import { Input } from '@repo/shadcn/input';
|
||||||
import {
|
// import {
|
||||||
Select,
|
// Select,
|
||||||
SelectContent,
|
// SelectContent,
|
||||||
SelectItem,
|
// SelectItem,
|
||||||
SelectTrigger,
|
// SelectTrigger,
|
||||||
SelectValue,
|
// SelectValue,
|
||||||
} from '@repo/shadcn/select';
|
// } from '@repo/shadcn/select';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { useCreateUser } from "../../hooks/use-mutation-users";
|
import { useCreateUser } from "@/feactures/inventory/hooks/use-mutation";
|
||||||
import { CreateUser, createUser } from '../../schemas/inventory';
|
import { EditInventory, editInventory } from '@/feactures/inventory/schemas/inventory';
|
||||||
|
import { parse } from 'path';
|
||||||
|
|
||||||
const ROLES = {
|
|
||||||
// 1: 'Superadmin',
|
|
||||||
2: 'Administrador',
|
|
||||||
3: 'autoridad',
|
|
||||||
4: 'Gerente',
|
|
||||||
5: 'Usuario',
|
|
||||||
6: 'Productor',
|
|
||||||
7: 'Organización'
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CreateUserFormProps {
|
interface CreateFormProps {
|
||||||
onSuccess?: () => void;
|
onSuccess?: () => void;
|
||||||
onCancel?: () => void;
|
onCancel?: () => void;
|
||||||
defaultValues?: Partial<CreateUser>;
|
defaultValues?: Partial<EditInventory>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CreateUserForm({
|
export function CreateForm({
|
||||||
onSuccess,
|
onSuccess,
|
||||||
onCancel,
|
onCancel,
|
||||||
defaultValues,
|
defaultValues,
|
||||||
}: CreateUserFormProps) {
|
}: CreateFormProps) {
|
||||||
const {
|
const {
|
||||||
mutate: saveAccountingAccounts,
|
mutate: saveAccountingAccounts,
|
||||||
isPending: isSaving,
|
isPending: isSaving,
|
||||||
@@ -52,23 +43,20 @@ export function CreateUserForm({
|
|||||||
// const { data: AccoutingAccounts } = useSurveyMutation();
|
// const { data: AccoutingAccounts } = useSurveyMutation();
|
||||||
|
|
||||||
const defaultformValues = {
|
const defaultformValues = {
|
||||||
username: defaultValues?.username || '',
|
title: defaultValues?.title || '',
|
||||||
fullname: defaultValues?.fullname || '',
|
description: defaultValues?.description || '',
|
||||||
email: defaultValues?.email || '',
|
price: defaultValues?.price || '',
|
||||||
password: '',
|
stock: defaultValues?.stock || 0,
|
||||||
confirmPassword: '',
|
urlImg: defaultValues?.urlImg || ''
|
||||||
id: defaultValues?.id,
|
|
||||||
phone: defaultValues?.phone || '',
|
|
||||||
role: defaultValues?.role,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const form = useForm<CreateUser>({
|
const form = useForm<EditInventory>({
|
||||||
resolver: zodResolver(createUser),
|
resolver: zodResolver(editInventory),
|
||||||
defaultValues: defaultformValues,
|
defaultValues: defaultformValues,
|
||||||
mode: 'onChange', // Enable real-time validation
|
mode: 'onChange', // Enable real-time validation
|
||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit = async (data: CreateUser) => {
|
const onSubmit = async (data: EditInventory) => {
|
||||||
|
|
||||||
const formData = data
|
const formData = data
|
||||||
|
|
||||||
@@ -97,10 +85,10 @@ export function CreateUserForm({
|
|||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="username"
|
name="title"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Usuario</FormLabel>
|
<FormLabel>Nombre/Título</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input {...field} />
|
<Input {...field} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
@@ -111,10 +99,10 @@ export function CreateUserForm({
|
|||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="fullname"
|
name="description"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Nombre completo</FormLabel>
|
<FormLabel>Descripción</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input {...field} />
|
<Input {...field} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
@@ -125,10 +113,26 @@ export function CreateUserForm({
|
|||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="email"
|
name="price"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Correo</FormLabel>
|
<FormLabel>Precio</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field}
|
||||||
|
// value={field.value?.toString() ?? ''}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="stock"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Cantidad/Stock</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input {...field} />
|
<Input {...field} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
@@ -139,73 +143,17 @@ export function CreateUserForm({
|
|||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="phone"
|
name="urlImg"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Teléfono</FormLabel>
|
<FormLabel>Imagen</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input {...field} value={field.value?.toString() ?? ''}/>
|
<Input {...field}/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="password"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Contraseña</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input type="password" {...field}/>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name='confirmPassword'
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Confirmar Contraseña</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input type="password" {...field}/>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="role"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="w-full">
|
|
||||||
<FormLabel>Rol</FormLabel>
|
|
||||||
<Select
|
|
||||||
onValueChange={(value) => field.onChange(Number(value))}
|
|
||||||
defaultValue={String(field.value)}
|
|
||||||
>
|
|
||||||
<FormControl>
|
|
||||||
<SelectTrigger className="w-full">
|
|
||||||
<SelectValue placeholder="Selecciona un rol" />
|
|
||||||
</SelectTrigger>
|
|
||||||
</FormControl>
|
|
||||||
<SelectContent className="w-full min-w-[200px]">
|
|
||||||
{Object.entries(ROLES).map(([value, label]) => (
|
|
||||||
<SelectItem key={value} value={value}>
|
|
||||||
{label}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-end gap-4">
|
<div className="flex justify-end gap-4">
|
||||||
@@ -7,21 +7,22 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from '@repo/shadcn/dialog';
|
} from '@repo/shadcn/dialog';
|
||||||
import { AccountPlan } from '@/feactures/users/schemas/account-plan.schema';
|
// import { AccountPlan } from '@/feactures/users/schemas/account-plan.schema';
|
||||||
import { CreateUserForm } from './create-user-form';
|
import { EditInventory, editInventory } from '../../schemas/inventory';
|
||||||
import { UpdateUserForm } from './update-user-form';
|
import { CreateForm } from './create-product-form';
|
||||||
|
import { UpdateForm } from './update-product-form';
|
||||||
|
|
||||||
interface AccountPlanModalProps {
|
interface ModalProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onOpenChange: (open: boolean) => void;
|
onOpenChange: (open: boolean) => void;
|
||||||
defaultValues?: Partial<AccountPlan>;
|
defaultValues?: Partial<EditInventory>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AccountPlanModal({
|
export function AccountPlanModal({
|
||||||
open,
|
open,
|
||||||
onOpenChange,
|
onOpenChange,
|
||||||
defaultValues,
|
defaultValues,
|
||||||
}: AccountPlanModalProps) {
|
}: ModalProps) {
|
||||||
const handleSuccess = () => {
|
const handleSuccess = () => {
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
};
|
};
|
||||||
@@ -43,21 +44,21 @@ export function AccountPlanModal({
|
|||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
{defaultValues?.id
|
{defaultValues?.id
|
||||||
? 'Actualizar usuario'
|
? 'Actualizar producto'
|
||||||
: 'Crear usuario'}
|
: 'Registrar producto'}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
Complete los campos para {defaultValues?.id ? 'actualizar' : 'crear'} un usuario
|
Complete los campos para {defaultValues?.id ? 'actualizar' : 'registrar'} un producto
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
{defaultValues?.id ? (
|
{defaultValues?.id ? (
|
||||||
<UpdateUserForm
|
<UpdateForm
|
||||||
onSuccess={handleSuccess}
|
onSuccess={handleSuccess}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
defaultValues={defaultValues}
|
defaultValues={defaultValues}
|
||||||
/>
|
/>
|
||||||
): (
|
): (
|
||||||
<CreateUserForm
|
<CreateForm
|
||||||
onSuccess={handleSuccess}
|
onSuccess={handleSuccess}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
defaultValues={defaultValues}
|
defaultValues={defaultValues}
|
||||||
@@ -27,10 +27,7 @@ export default function UsersAdminList({
|
|||||||
|
|
||||||
const {data, isLoading} = useProductQuery(filters)
|
const {data, isLoading} = useProductQuery(filters)
|
||||||
|
|
||||||
|
// console.log(data?.data);
|
||||||
// const {data, isLoading} = useUsersQuery(filters)
|
|
||||||
|
|
||||||
console.log(data?.data);
|
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <DataTableSkeleton columnCount={6} rowCount={initialLimit} />;
|
return <DataTableSkeleton columnCount={6} rowCount={initialLimit} />;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
import { Edit, Trash, User } from 'lucide-react';
|
import { Edit, Trash, User } from 'lucide-react';
|
||||||
import { InventoryTable } from '@/feactures/inventory/schemas/inventory';
|
import { InventoryTable } from '@/feactures/inventory/schemas/inventory';
|
||||||
import { useDeleteUser } from '@/feactures/users/hooks/use-mutation-users';
|
import { useDeleteUser } from '@/feactures/users/hooks/use-mutation-users';
|
||||||
import { AccountPlanModal } from '../user-modal';
|
import { AccountPlanModal } from '../inventory-modal';
|
||||||
|
|
||||||
interface CellActionProps {
|
interface CellActionProps {
|
||||||
data: InventoryTable;
|
data: InventoryTable;
|
||||||
|
|||||||
@@ -0,0 +1,168 @@
|
|||||||
|
'use client';
|
||||||
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
import { Button } from '@repo/shadcn/button';
|
||||||
|
import {
|
||||||
|
Form,
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from '@repo/shadcn/form';
|
||||||
|
import { Input } from '@repo/shadcn/input';
|
||||||
|
// import {
|
||||||
|
// Select,
|
||||||
|
// SelectContent,
|
||||||
|
// SelectItem,
|
||||||
|
// SelectTrigger,
|
||||||
|
// SelectValue,
|
||||||
|
// } from '@repo/shadcn/select';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { useUpdateUser } from "@/feactures/inventory/hooks/use-mutation";
|
||||||
|
import { EditInventory, editInventory } from '@/feactures/inventory/schemas/inventory';
|
||||||
|
|
||||||
|
|
||||||
|
interface UpdateFormProps {
|
||||||
|
onSuccess?: () => void;
|
||||||
|
onCancel?: () => void;
|
||||||
|
defaultValues?: Partial<EditInventory>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UpdateForm({
|
||||||
|
onSuccess,
|
||||||
|
onCancel,
|
||||||
|
defaultValues,
|
||||||
|
}: UpdateFormProps) {
|
||||||
|
const {
|
||||||
|
mutate: saveAccountingAccounts,
|
||||||
|
isPending: isSaving,
|
||||||
|
isError,
|
||||||
|
} = useUpdateUser();
|
||||||
|
|
||||||
|
const defaultformValues = {
|
||||||
|
id: defaultValues?.id,
|
||||||
|
title: defaultValues?.title || '',
|
||||||
|
description: defaultValues?.description || '',
|
||||||
|
price: defaultValues?.price || '',
|
||||||
|
stock: defaultValues?.stock || 0,
|
||||||
|
urlImg: defaultValues?.urlImg || '',
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(defaultValues);
|
||||||
|
|
||||||
|
const form = useForm<EditInventory>({
|
||||||
|
resolver: zodResolver(editInventory),
|
||||||
|
defaultValues: defaultformValues,
|
||||||
|
mode: 'onChange', // Enable real-time validation
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = async (data: EditInventory) => {
|
||||||
|
|
||||||
|
const formData = data
|
||||||
|
|
||||||
|
saveAccountingAccounts(formData, {
|
||||||
|
onSuccess: () => {
|
||||||
|
form.reset();
|
||||||
|
onSuccess?.();
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
form.setError('root', {
|
||||||
|
type: 'manual',
|
||||||
|
message: 'Error al guardar la cuenta contable',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form {...form}>
|
||||||
|
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||||
|
{form.formState.errors.root && (
|
||||||
|
<div className="text-destructive text-sm">
|
||||||
|
{form.formState.errors.root.message}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="title"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Nombre/Título</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="description"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Descripción</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="price"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Precio</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field} value={field.value?.toString() ?? ''}/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="stock"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Cantidad/Stock</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field}/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="urlImg"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Imagen</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field}/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex justify-end gap-4">
|
||||||
|
<Button variant="outline" type="button" onClick={onCancel}>
|
||||||
|
Cancelar
|
||||||
|
</Button>
|
||||||
|
<Button type="submit" disabled={isSaving}>
|
||||||
|
{isSaving ? 'Guardando...' : 'Guardar'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,227 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
|
||||||
import { Button } from '@repo/shadcn/button';
|
|
||||||
import {
|
|
||||||
Form,
|
|
||||||
FormControl,
|
|
||||||
FormField,
|
|
||||||
FormItem,
|
|
||||||
FormLabel,
|
|
||||||
FormMessage,
|
|
||||||
} from '@repo/shadcn/form';
|
|
||||||
import { Input } from '@repo/shadcn/input';
|
|
||||||
import {
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from '@repo/shadcn/select';
|
|
||||||
import { useForm } from 'react-hook-form';
|
|
||||||
import { useUpdateUser } from "@/feactures/users/hooks/use-mutation-users";
|
|
||||||
import { UpdateUser, updateUser } from '@/feactures/users/schemas/users';
|
|
||||||
|
|
||||||
const ROLES = {
|
|
||||||
// 1: 'Superadmin',
|
|
||||||
2: 'Administrador',
|
|
||||||
3: 'autoridad',
|
|
||||||
4: 'Gerente',
|
|
||||||
5: 'Usuario',
|
|
||||||
6: 'Productor',
|
|
||||||
7: 'Organización'
|
|
||||||
}
|
|
||||||
|
|
||||||
interface UserFormProps {
|
|
||||||
onSuccess?: () => void;
|
|
||||||
onCancel?: () => void;
|
|
||||||
defaultValues?: Partial<UpdateUser>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function UpdateUserForm({
|
|
||||||
onSuccess,
|
|
||||||
onCancel,
|
|
||||||
defaultValues,
|
|
||||||
}: UserFormProps) {
|
|
||||||
const {
|
|
||||||
mutate: saveAccountingAccounts,
|
|
||||||
isPending: isSaving,
|
|
||||||
isError,
|
|
||||||
} = useUpdateUser();
|
|
||||||
|
|
||||||
const defaultformValues = {
|
|
||||||
username: defaultValues?.username || '',
|
|
||||||
fullname: defaultValues?.fullname || '',
|
|
||||||
email: defaultValues?.email || '',
|
|
||||||
password: '',
|
|
||||||
id: defaultValues?.id,
|
|
||||||
phone: defaultValues?.phone || '',
|
|
||||||
role: undefined,
|
|
||||||
isActive: defaultValues?.isActive
|
|
||||||
}
|
|
||||||
|
|
||||||
// console.log(defaultValues);
|
|
||||||
|
|
||||||
const form = useForm<UpdateUser>({
|
|
||||||
resolver: zodResolver(updateUser),
|
|
||||||
defaultValues: defaultformValues,
|
|
||||||
mode: 'onChange', // Enable real-time validation
|
|
||||||
});
|
|
||||||
|
|
||||||
const onSubmit = async (data: UpdateUser) => {
|
|
||||||
|
|
||||||
const formData = data
|
|
||||||
|
|
||||||
saveAccountingAccounts(formData, {
|
|
||||||
onSuccess: () => {
|
|
||||||
form.reset();
|
|
||||||
onSuccess?.();
|
|
||||||
},
|
|
||||||
onError: () => {
|
|
||||||
form.setError('root', {
|
|
||||||
type: 'manual',
|
|
||||||
message: 'Error al guardar la cuenta contable',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Form {...form}>
|
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
|
||||||
{form.formState.errors.root && (
|
|
||||||
<div className="text-destructive text-sm">
|
|
||||||
{form.formState.errors.root.message}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="username"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Usuario</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="fullname"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Nombre completo</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="email"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Correo</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="phone"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Teléfono</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input {...field} value={field.value?.toString() ?? ''}/>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name='password'
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Nueva Contraseña</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input type="password" {...field}/>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="role"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="w-full">
|
|
||||||
<FormLabel>Rol</FormLabel>
|
|
||||||
<Select onValueChange={(value) => field.onChange(Number(value))}
|
|
||||||
// defaultValue={String(field.value)}
|
|
||||||
>
|
|
||||||
<FormControl>
|
|
||||||
<SelectTrigger className="w-full">
|
|
||||||
<SelectValue placeholder="Selecciona un rol" />
|
|
||||||
</SelectTrigger>
|
|
||||||
</FormControl>
|
|
||||||
<SelectContent className="w-full min-w-[200px]">
|
|
||||||
{Object.entries(ROLES).map(([value, label]) => (
|
|
||||||
<SelectItem key={value} value={value}>
|
|
||||||
{label}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="isActive"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="w-full">
|
|
||||||
<FormLabel>Estatus</FormLabel>
|
|
||||||
<Select defaultValue={String(field.value)} onValueChange={(value) => field.onChange(Boolean(value))}>
|
|
||||||
<SelectTrigger className="w-full">
|
|
||||||
<SelectValue placeholder="Seleccione un estatus" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="true">Activo</SelectItem>
|
|
||||||
<SelectItem value="false">Inactivo</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex justify-end gap-4">
|
|
||||||
<Button variant="outline" type="button" onClick={onCancel}>
|
|
||||||
Cancelar
|
|
||||||
</Button>
|
|
||||||
<Button type="submit" disabled={isSaving}>
|
|
||||||
{isSaving ? 'Guardando...' : 'Guardar'}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { useRouter } from 'next/navigation';
|
// import { useRouter } from 'next/navigation';
|
||||||
import { Button } from '@repo/shadcn/button';
|
import { Button } from '@repo/shadcn/button';
|
||||||
import { Heading } from '@repo/shadcn/heading';
|
import { Heading } from '@repo/shadcn/heading';
|
||||||
import { Plus } from 'lucide-react';
|
import { Plus } from 'lucide-react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { AccountPlanModal } from './user-modal';
|
import { AccountPlanModal } from './inventory-modal';
|
||||||
|
|
||||||
export function UsersHeader() {
|
export function UsersHeader() {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
@@ -17,7 +17,7 @@ export function UsersHeader() {
|
|||||||
description="Gestione aquí los productos que usted registre en la plataforma"
|
description="Gestione aquí los productos que usted registre en la plataforma"
|
||||||
/>
|
/>
|
||||||
<Button onClick={() => setOpen(true)} size="sm">
|
<Button onClick={() => setOpen(true)} size="sm">
|
||||||
<Plus className="mr-2 h-4 w-4" /> Agregar Usuario
|
<Plus className="mr-2 h-4 w-4" /> Agregar Producto
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Dialog,
|
|
||||||
DialogContent,
|
|
||||||
DialogDescription,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
} from '@repo/shadcn/dialog';
|
|
||||||
import { AccountPlan } from '@/feactures/users/schemas/account-plan.schema';
|
|
||||||
import { ModalForm } from './update-user-form';
|
|
||||||
|
|
||||||
interface AccountPlanModalProps {
|
|
||||||
open: boolean;
|
|
||||||
onOpenChange: (open: boolean) => void;
|
|
||||||
defaultValues?: Partial<AccountPlan>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AccountPlanModal({
|
|
||||||
open,
|
|
||||||
onOpenChange,
|
|
||||||
defaultValues,
|
|
||||||
}: AccountPlanModalProps) {
|
|
||||||
const handleSuccess = () => {
|
|
||||||
onOpenChange(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCancel = () => {
|
|
||||||
onOpenChange(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dialog
|
|
||||||
open={open}
|
|
||||||
onOpenChange={(open) => {
|
|
||||||
if (!open) {
|
|
||||||
onOpenChange(false);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DialogContent className="sm:max-w-[600px] z-50 backdrop-blur-lg bg-background/80">
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>Actualizar Perfil</DialogTitle>
|
|
||||||
<DialogDescription>
|
|
||||||
Complete los campos para actualizar sus datos.<br/>Los campos vacios no seran actualizados.
|
|
||||||
</DialogDescription>
|
|
||||||
</DialogHeader>
|
|
||||||
<ModalForm
|
|
||||||
onSuccess={handleSuccess}
|
|
||||||
onCancel={handleCancel}
|
|
||||||
defaultValues={defaultValues}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
// 'use client';
|
|
||||||
import {
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from '@repo/shadcn/select';
|
|
||||||
import {
|
|
||||||
Form,
|
|
||||||
FormControl,
|
|
||||||
FormField,
|
|
||||||
FormItem,
|
|
||||||
FormLabel,
|
|
||||||
FormMessage,
|
|
||||||
} from '@repo/shadcn/form';
|
|
||||||
import { UpdateUser, updateUser } from '@/feactures/users/schemas/users';
|
|
||||||
import { useForm } from 'react-hook-form';
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
|
||||||
|
|
||||||
interface SelectListProps {
|
|
||||||
label: string
|
|
||||||
// values:
|
|
||||||
values: Array<object>
|
|
||||||
form: any
|
|
||||||
name: string
|
|
||||||
handleChange: any
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SelectList({ label, values, form, name, handleChange }: SelectListProps) {
|
|
||||||
// const { label, values, form, name } = props;
|
|
||||||
// handleChange
|
|
||||||
|
|
||||||
// const defaultformValues = {
|
|
||||||
// username: '',
|
|
||||||
// fullname: '',
|
|
||||||
// email: '',
|
|
||||||
// password: '',
|
|
||||||
// id: 0,
|
|
||||||
// phone: '',
|
|
||||||
// role: undefined,
|
|
||||||
// isActive: false
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const form = useForm<UpdateUser>({
|
|
||||||
// resolver: zodResolver(updateUser),
|
|
||||||
// defaultValues: defaultformValues,
|
|
||||||
// mode: 'onChange', // Enable real-time validation
|
|
||||||
// });
|
|
||||||
|
|
||||||
|
|
||||||
return <FormField
|
|
||||||
control={form.control}
|
|
||||||
name={name}
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="w-full">
|
|
||||||
<FormLabel>{label}</FormLabel>
|
|
||||||
<Select onValueChange={handleChange}
|
|
||||||
// defaultValue={String(field.value)}
|
|
||||||
>
|
|
||||||
<FormControl>
|
|
||||||
<SelectTrigger className="w-full">
|
|
||||||
<SelectValue placeholder="Selecciona una opción" />
|
|
||||||
</SelectTrigger>
|
|
||||||
</FormControl>
|
|
||||||
<SelectContent className="w-full min-w-[200px]">
|
|
||||||
{values.map((item: any) => (
|
|
||||||
<SelectItem key={item.id} value={item.id}>
|
|
||||||
{item.name}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
{/* <SelectItem key={0} value="0">Hola1</SelectItem>
|
|
||||||
<SelectItem key={1} value="1">Hola2</SelectItem> */}
|
|
||||||
{/* {Object.entries(values).map(([id, label]) => (
|
|
||||||
<SelectItem key={id} value={id}>
|
|
||||||
{label}
|
|
||||||
</SelectItem>
|
|
||||||
))} */}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { SurveyResponse } from '@/feactures/surveys/components/survey-response';
|
|
||||||
import { useSurveysByIdQuery } from '@/feactures/surveys/hooks/use-query-surveys';
|
|
||||||
|
|
||||||
import { notFound, useParams } from 'next/navigation';
|
|
||||||
|
|
||||||
|
|
||||||
export default function SurveyPage() {
|
|
||||||
const params = useParams();
|
|
||||||
const surveyId = params?.id as string | undefined;
|
|
||||||
|
|
||||||
|
|
||||||
if (!surveyId || surveyId === '') {
|
|
||||||
notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
const { data: survey, isLoading } = useSurveysByIdQuery(Number(surveyId));
|
|
||||||
console.log('🎯 useSurveysByIdQuery ejecutado, data:', survey, 'isLoading:', isLoading);
|
|
||||||
|
|
||||||
if (!survey?.data || !survey?.data.published) {
|
|
||||||
notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SurveyResponse survey={survey?.data} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,268 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
|
||||||
import { Button } from '@repo/shadcn/button';
|
|
||||||
import {
|
|
||||||
Form,
|
|
||||||
FormControl,
|
|
||||||
FormField,
|
|
||||||
FormItem,
|
|
||||||
FormLabel,
|
|
||||||
FormMessage,
|
|
||||||
} from '@repo/shadcn/form';
|
|
||||||
import { Input } from '@repo/shadcn/input';
|
|
||||||
// import {
|
|
||||||
// Select,
|
|
||||||
// SelectContent,
|
|
||||||
// SelectItem,
|
|
||||||
// SelectTrigger,
|
|
||||||
// SelectValue,
|
|
||||||
// } from '@repo/shadcn/select';
|
|
||||||
import { SelectSearchable } from '@repo/shadcn/select-searchable'
|
|
||||||
import { useForm } from 'react-hook-form';
|
|
||||||
import { useUpdateProfile } from "@/feactures/users/hooks/use-mutation-users";
|
|
||||||
import { UpdateUser, updateUser } from '@/feactures/users/schemas/users';
|
|
||||||
import { toast } from 'sonner';
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { useStateQuery, useMunicipalityQuery, useParishQuery } from '@/feactures/location/hooks/use-query-location';
|
|
||||||
|
|
||||||
interface UserFormProps {
|
|
||||||
onSuccess?: () => void;
|
|
||||||
onCancel?: () => void;
|
|
||||||
defaultValues?: Partial<UpdateUser>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ModalForm({
|
|
||||||
onSuccess,
|
|
||||||
onCancel,
|
|
||||||
defaultValues,
|
|
||||||
}: UserFormProps) {
|
|
||||||
const {
|
|
||||||
mutate: saveAccountingAccounts,
|
|
||||||
isPending: isSaving,
|
|
||||||
isError,
|
|
||||||
} = useUpdateProfile();
|
|
||||||
|
|
||||||
const [state, setState] = React.useState(0);
|
|
||||||
const [municipality, setMunicipality] = React.useState(0);
|
|
||||||
const [parish, setParish] = React.useState(0);
|
|
||||||
|
|
||||||
const [disabledMunicipality, setDisabledMunicipality] = React.useState(true);
|
|
||||||
const [disabledParish, setDisabledParish] = React.useState(true);
|
|
||||||
|
|
||||||
const { data : dataState } = useStateQuery()
|
|
||||||
const { data : dataMunicipality } = useMunicipalityQuery(state)
|
|
||||||
const { data : dataParish } = useParishQuery(municipality)
|
|
||||||
|
|
||||||
const stateOptions = dataState?.data || [{id:0,name:'Sin estados'}]
|
|
||||||
|
|
||||||
const municipalityOptions = Array.isArray(dataMunicipality?.data) && dataMunicipality.data.length > 0
|
|
||||||
? dataMunicipality.data
|
|
||||||
: [{id:0,stateId:0,name:'Sin Municipios'}]
|
|
||||||
// const parishOptions = dataParish?.data || [{id:0,municipalityId:0,name:'Sin Parroquias'}]
|
|
||||||
const parishOptions = Array.isArray(dataParish?.data) && dataParish.data.length > 0
|
|
||||||
? dataParish.data
|
|
||||||
: [{id:0,stateId:0,name:'Sin Parroquias'}]
|
|
||||||
|
|
||||||
|
|
||||||
const defaultformValues = {
|
|
||||||
username: defaultValues?.username || '',
|
|
||||||
fullname: defaultValues?.fullname || '',
|
|
||||||
email: defaultValues?.email || '',
|
|
||||||
password: '',
|
|
||||||
id: defaultValues?.id,
|
|
||||||
phone: defaultValues?.phone || '',
|
|
||||||
role: undefined,
|
|
||||||
isActive: defaultValues?.isActive,
|
|
||||||
state: defaultValues?.state,
|
|
||||||
municipality: defaultValues?.municipality,
|
|
||||||
parish: defaultValues?.parish
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// console.log(defaultValues);
|
|
||||||
|
|
||||||
const form = useForm<UpdateUser>({
|
|
||||||
resolver: zodResolver(updateUser),
|
|
||||||
defaultValues: defaultformValues,
|
|
||||||
mode: 'onChange', // Enable real-time validation
|
|
||||||
});
|
|
||||||
|
|
||||||
const onSubmit = async (data: UpdateUser) => {
|
|
||||||
|
|
||||||
const formData = data
|
|
||||||
|
|
||||||
saveAccountingAccounts(formData, {
|
|
||||||
onSuccess: () => {
|
|
||||||
form.reset();
|
|
||||||
onSuccess?.();
|
|
||||||
toast.success('Actualizado exitosamente!');
|
|
||||||
},
|
|
||||||
onError: (e) => {
|
|
||||||
form.setError('root', {
|
|
||||||
type: 'manual',
|
|
||||||
message: e.message,
|
|
||||||
});
|
|
||||||
// toast.error(e.message);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Form {...form}>
|
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
|
||||||
{form.formState.errors.root && (
|
|
||||||
<div className="text-destructive text-sm">
|
|
||||||
{form.formState.errors.root.message}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="fullname"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Nombre completo</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="email"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Correo</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="phone"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Teléfono</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input {...field} value={field.value?.toString() ?? ''}/>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="state"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="w-full">
|
|
||||||
<FormLabel>Estado</FormLabel>
|
|
||||||
|
|
||||||
<SelectSearchable
|
|
||||||
options={
|
|
||||||
stateOptions?.map((item) => ({
|
|
||||||
value: item.id.toString(),
|
|
||||||
label: item.name,
|
|
||||||
})) || []
|
|
||||||
}
|
|
||||||
onValueChange={(value : any) =>
|
|
||||||
{field.onChange(Number(value)); setState(value); setDisabledMunicipality(false); setDisabledParish(true)}
|
|
||||||
}
|
|
||||||
placeholder="Selecciona un estado"
|
|
||||||
defaultValue={field.value?.toString()}
|
|
||||||
// disabled={readOnly}
|
|
||||||
/>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="municipality"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="w-full">
|
|
||||||
<FormLabel>Municipio</FormLabel>
|
|
||||||
|
|
||||||
<SelectSearchable
|
|
||||||
options={
|
|
||||||
municipalityOptions?.map((item) => ({
|
|
||||||
value: item.id.toString(),
|
|
||||||
label: item.name,
|
|
||||||
})) || []
|
|
||||||
}
|
|
||||||
onValueChange={(value : any) =>
|
|
||||||
{field.onChange(Number(value)); setMunicipality(value); setDisabledParish(false)}
|
|
||||||
}
|
|
||||||
placeholder="Selecciona un Municipio"
|
|
||||||
defaultValue={field.value?.toString()}
|
|
||||||
disabled={disabledMunicipality}
|
|
||||||
/>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="parish"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="w-full">
|
|
||||||
<FormLabel>Parroquia</FormLabel>
|
|
||||||
|
|
||||||
<SelectSearchable
|
|
||||||
options={
|
|
||||||
parishOptions?.map((item) => ({
|
|
||||||
value: item.id.toString(),
|
|
||||||
label: item.name,
|
|
||||||
})) || []
|
|
||||||
}
|
|
||||||
onValueChange={(value : any) =>
|
|
||||||
field.onChange(Number(value))
|
|
||||||
}
|
|
||||||
placeholder="Selecciona una Parroquia"
|
|
||||||
defaultValue={field.value?.toString()}
|
|
||||||
disabled={disabledParish}
|
|
||||||
/>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name='password'
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Nueva Contraseña</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input type="password" {...field}/>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex justify-end gap-4">
|
|
||||||
<Button variant="outline" type="button" onClick={onCancel}>
|
|
||||||
Cancelar
|
|
||||||
</Button>
|
|
||||||
<Button type="submit" disabled={isSaving}>
|
|
||||||
{isSaving ? 'Guardando...' : 'Guardar'}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
'use client';
|
|
||||||
import { useUserByProfile } from '@/feactures/users/hooks/use-query-users';
|
|
||||||
import { Button } from '@repo/shadcn/button';
|
|
||||||
import { Edit, Edit2 } from 'lucide-react';
|
|
||||||
import { useState } from 'react';
|
|
||||||
import { AccountPlanModal } from './modal-profile';
|
|
||||||
|
|
||||||
export function Profile() {
|
|
||||||
const [open, setOpen] = useState(false);
|
|
||||||
|
|
||||||
const { data } = useUserByProfile();
|
|
||||||
|
|
||||||
// console.log("🎯 data:", data);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Button onClick={() => setOpen(true)} size="sm">
|
|
||||||
<Edit2 className="mr-2 h-4 w-4" /> Editar Perfil
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<AccountPlanModal open={open} onOpenChange={setOpen} defaultValues={data?.data}/>
|
|
||||||
|
|
||||||
<h2 className='mt-3 mb-1'>Datos del usuario</h2>
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
||||||
<section className='border bg-muted p-2 rounded-md'>
|
|
||||||
<p className='font-bold text-lg'>Usuario:</p>
|
|
||||||
<p>{data?.data.username || 'Sin Nombre de Usuario'}</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className='border bg-muted p-2 rounded-md'>
|
|
||||||
<p className='font-bold text-lg'>Rol:</p>
|
|
||||||
<p>{data?.data.role || 'Sin Rol'}</p>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2 className='mt-3 mb-1'>Información personal</h2>
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
||||||
<section className='border bg-muted p-2 rounded-md'>
|
|
||||||
<p className='font-bold text-lg'>Nombre completo:</p>
|
|
||||||
<p>{data?.data.fullname || 'Sin nombre y apellido'}</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className='border bg-muted p-2 rounded-md'>
|
|
||||||
<p className='font-bold text-lg'>Correo:</p>
|
|
||||||
<p>{data?.data.email || 'Sin correo'}</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className='border bg-muted p-2 rounded-md'>
|
|
||||||
<p className='font-bold text-lg'>Teléfono:</p>
|
|
||||||
<p>{data?.data.phone || 'Sin teléfono'}</p>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2 className='mt-3 mb-1'>Información de ubicación</h2>
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
||||||
<section className='border bg-muted p-2 rounded-md'>
|
|
||||||
<p className='font-bold text-lg'>Estado:</p>
|
|
||||||
<p>{data?.data.state || 'Sin Estado'}</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className='border bg-muted p-2 rounded-md'>
|
|
||||||
<p className='font-bold text-lg'>Municipio:</p>
|
|
||||||
<p>{data?.data.municipality || 'Sin Municipio'}</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className='border bg-muted p-2 rounded-md'>
|
|
||||||
<p className='font-bold text-lg'>Parroquia:</p>
|
|
||||||
<p>{data?.data.parish || 'Sin Parroquia'}</p>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
||||||
import { CreateUser, UpdateUser } from "../schemas/inventory";
|
|
||||||
import { updateUserAction, createUserAction, deleteUserAction, updateProfileAction } from "../actions/actions";
|
|
||||||
|
|
||||||
// Create mutation
|
|
||||||
export function useCreateUser() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const mutation = useMutation({
|
|
||||||
mutationFn: (data: CreateUser) => createUserAction(data),
|
|
||||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['users'] }),
|
|
||||||
// onError: (e) => console.error('Error:', e),
|
|
||||||
})
|
|
||||||
return mutation
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update mutation
|
|
||||||
export function useUpdateUser() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const mutation = useMutation({
|
|
||||||
mutationFn: (data: UpdateUser) => updateUserAction(data),
|
|
||||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['users'] }),
|
|
||||||
onError: (e) => console.error('Error:', e)
|
|
||||||
})
|
|
||||||
return mutation;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useUpdateProfile() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const mutation = useMutation({
|
|
||||||
mutationFn: (data: UpdateUser) => updateProfileAction(data),
|
|
||||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['users'] }),
|
|
||||||
// onError: (e) => console.error('Error:', e)
|
|
||||||
})
|
|
||||||
return mutation;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete mutation
|
|
||||||
export function useDeleteUser() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: (id: number) => deleteUserAction(id),
|
|
||||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['users'] }),
|
|
||||||
onError: (e) => console.error('Error:', e)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
35
apps/web/feactures/inventory/hooks/use-mutation.ts
Normal file
35
apps/web/feactures/inventory/hooks/use-mutation.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { EditInventory } from "../schemas/inventory";
|
||||||
|
import { updateUserAction, createProductAction } from "../actions/actions";
|
||||||
|
|
||||||
|
// Create mutation
|
||||||
|
export function useCreateUser() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const mutation = useMutation({
|
||||||
|
mutationFn: (data: EditInventory) => createProductAction(data),
|
||||||
|
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['product'] }),
|
||||||
|
// onError: (e) => console.error('Error:', e),
|
||||||
|
})
|
||||||
|
return mutation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update mutation
|
||||||
|
export function useUpdateUser() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const mutation = useMutation({
|
||||||
|
mutationFn: (data: EditInventory) => updateUserAction(data),
|
||||||
|
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['product'] }),
|
||||||
|
onError: (e) => console.error('Error:', e)
|
||||||
|
})
|
||||||
|
return mutation;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete mutation
|
||||||
|
// export function useDeleteUser() {
|
||||||
|
// const queryClient = useQueryClient();
|
||||||
|
// return useMutation({
|
||||||
|
// mutationFn: (id: number) => deleteUserAction(id),
|
||||||
|
// onSuccess: () => queryClient.invalidateQueries({ queryKey: ['users'] }),
|
||||||
|
// onError: (e) => console.error('Error:', e)
|
||||||
|
// })
|
||||||
|
// }
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
'use client'
|
|
||||||
import { useSafeQuery } from "@/hooks/use-safe-query";
|
|
||||||
import { getUsersAction,getProfileAction} from "../actions/actions";
|
|
||||||
|
|
||||||
// Hook for users
|
|
||||||
export function useUsersQuery(params = {}) {
|
|
||||||
return useSafeQuery(['users',params], () => getUsersAction(params))
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useUserByProfile() {
|
|
||||||
return useSafeQuery(['users'], () => getProfileAction())
|
|
||||||
}
|
|
||||||
@@ -1,54 +1,31 @@
|
|||||||
import { title } from 'process';
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export type InventoryTable = z.infer<typeof product>;
|
export type InventoryTable = z.infer<typeof product>;
|
||||||
export type CreateUser = z.infer<typeof createUser>;
|
export type EditInventory = z.infer<typeof editInventory>;
|
||||||
export type UpdateUser = z.infer<typeof updateUser>;
|
|
||||||
|
|
||||||
export const product = z.object({
|
export const product = z.object({
|
||||||
id: z.number().optional(),
|
id: z.number().optional(),
|
||||||
title: z.string(),
|
title: z.string(),
|
||||||
description: z.string(),
|
description: z.string(),
|
||||||
// price: z.number(),
|
|
||||||
// quantity: z.number(),
|
|
||||||
// category: z.string(),
|
// category: z.string(),
|
||||||
// image: z.string().optional(),
|
|
||||||
stock: z.number(),
|
stock: z.number(),
|
||||||
price: z.string(),
|
price: z.string(),
|
||||||
urlImg: z.string(),
|
urlImg: z.string(),
|
||||||
userId: z.number().optional(),
|
userId: z.number().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const createUser = z.object({
|
export const editInventory = z.object({
|
||||||
id: z.number().optional(),
|
id: z.number().optional(),
|
||||||
username: z.string().min(5, { message: "Debe de tener 5 o más caracteres" }),
|
title: z.string().min(5, { message: "Debe de tener 5 o más caracteres" }),
|
||||||
password: z.string().min(8, { message: "Debe de tener 8 o más caracteres" }),
|
description: z.string().min(10, { message: "Debe de tener 10 o más caracteres" }),
|
||||||
email: z.string().email({ message: "Correo no válido" }),
|
stock: z.string().transform(val => Number(val)),
|
||||||
fullname: z.string(),
|
price: z.string(),
|
||||||
phone: z.string(),
|
urlImg: z.string(),
|
||||||
confirmPassword: z.string(),
|
userId: z.number().optional(),
|
||||||
role: z.number()
|
|
||||||
})
|
|
||||||
.refine((data) => data.password === data.confirmPassword, {
|
|
||||||
message: 'La contraseña no coincide',
|
|
||||||
path: ['confirmPassword'],
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const updateUser = z.object({
|
|
||||||
id: z.number(),
|
|
||||||
username: z.string().min(5, { message: "Debe de tener 5 o más caracteres" }).or(z.literal('')),
|
|
||||||
password: z.string().min(6, { message: "Debe de tener 6 o más caracteres" }).or(z.literal('')),
|
|
||||||
email: z.string().email({ message: "Correo no válido" }).or(z.literal('')),
|
|
||||||
fullname: z.string().optional(),
|
|
||||||
phone: z.string().optional(),
|
|
||||||
role: z.number().optional(),
|
|
||||||
isActive: z.boolean().optional(),
|
|
||||||
state: z.number().optional().nullable(),
|
|
||||||
municipality: z.number().optional().nullable(),
|
|
||||||
parish: z.number().optional().nullable(),
|
|
||||||
})
|
|
||||||
|
|
||||||
export const surveysApiResponseSchema = z.object({
|
export const ApiResponseSchema = z.object({
|
||||||
message: z.string(),
|
message: z.string(),
|
||||||
data: z.array(product),
|
data: z.array(product),
|
||||||
meta: z.object({
|
meta: z.object({
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
// 'use client';
|
|
||||||
import {
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from '@repo/shadcn/select';
|
|
||||||
import {
|
|
||||||
Form,
|
|
||||||
FormControl,
|
|
||||||
FormField,
|
|
||||||
FormItem,
|
|
||||||
FormLabel,
|
|
||||||
FormMessage,
|
|
||||||
} from '@repo/shadcn/form';
|
|
||||||
|
|
||||||
|
|
||||||
interface SelectListProps {
|
|
||||||
label: string
|
|
||||||
// values:
|
|
||||||
values: Array<object>
|
|
||||||
form: any
|
|
||||||
name: string
|
|
||||||
handleChange: any
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SelectList({ label, values, form, name, handleChange }: SelectListProps) {
|
|
||||||
// const { label, values, form, name } = props;
|
|
||||||
// handleChange
|
|
||||||
|
|
||||||
// const defaultformValues = {
|
|
||||||
// username: '',
|
|
||||||
// fullname: '',
|
|
||||||
// email: '',
|
|
||||||
// password: '',
|
|
||||||
// id: 0,
|
|
||||||
// phone: '',
|
|
||||||
// role: undefined,
|
|
||||||
// isActive: false
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const form = useForm<UpdateUser>({
|
|
||||||
// resolver: zodResolver(updateUser),
|
|
||||||
// defaultValues: defaultformValues,
|
|
||||||
// mode: 'onChange', // Enable real-time validation
|
|
||||||
// });
|
|
||||||
|
|
||||||
|
|
||||||
return <FormField
|
|
||||||
control={form.control}
|
|
||||||
name={name}
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="w-full">
|
|
||||||
<FormLabel>{label}</FormLabel>
|
|
||||||
<Select onValueChange={handleChange}
|
|
||||||
// defaultValue={String(field.value)}
|
|
||||||
>
|
|
||||||
<FormControl>
|
|
||||||
<SelectTrigger className="w-full">
|
|
||||||
<SelectValue placeholder="Selecciona una opción" />
|
|
||||||
</SelectTrigger>
|
|
||||||
</FormControl>
|
|
||||||
<SelectContent className="w-full min-w-[200px]">
|
|
||||||
{values.map((item: any) => (
|
|
||||||
<SelectItem key={item.id} value={item.id}>
|
|
||||||
{item.name}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
{/* <SelectItem key={0} value="0">Hola1</SelectItem>
|
|
||||||
<SelectItem key={1} value="1">Hola2</SelectItem> */}
|
|
||||||
{/* {Object.entries(values).map(([id, label]) => (
|
|
||||||
<SelectItem key={id} value={id}>
|
|
||||||
{label}
|
|
||||||
</SelectItem>
|
|
||||||
))} */}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { SurveyResponse } from '@/feactures/surveys/components/survey-response';
|
|
||||||
import { useSurveysByIdQuery } from '@/feactures/surveys/hooks/use-query-surveys';
|
|
||||||
|
|
||||||
import { notFound, useParams } from 'next/navigation';
|
|
||||||
|
|
||||||
|
|
||||||
export default function SurveyPage() {
|
|
||||||
const params = useParams();
|
|
||||||
const surveyId = params?.id as string | undefined;
|
|
||||||
|
|
||||||
|
|
||||||
if (!surveyId || surveyId === '') {
|
|
||||||
notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
const { data: survey, isLoading } = useSurveysByIdQuery(Number(surveyId));
|
|
||||||
console.log('🎯 useSurveysByIdQuery ejecutado, data:', survey, 'isLoading:', isLoading);
|
|
||||||
|
|
||||||
if (!survey?.data || !survey?.data.published) {
|
|
||||||
notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SurveyResponse survey={survey?.data} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user