base con autenticacion, registro, modulo encuestas
This commit is contained in:
222
apps/web/feactures/users/components/admin/create-user-form.tsx
Normal file
222
apps/web/feactures/users/components/admin/create-user-form.tsx
Normal file
@@ -0,0 +1,222 @@
|
||||
'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 { useCreateUser } from "../../hooks/use-mutation-users";
|
||||
import { CreateUser, createUser } from '../../schemas/users';
|
||||
|
||||
const ROLES = {
|
||||
// 1: 'Superadmin',
|
||||
2: 'Administrador',
|
||||
3: 'autoridad',
|
||||
4: 'Gerente',
|
||||
5: 'Usuario',
|
||||
6: 'Productor',
|
||||
7: 'Organización'
|
||||
}
|
||||
|
||||
interface CreateUserFormProps {
|
||||
onSuccess?: () => void;
|
||||
onCancel?: () => void;
|
||||
defaultValues?: Partial<CreateUser>;
|
||||
}
|
||||
|
||||
export function CreateUserForm({
|
||||
onSuccess,
|
||||
onCancel,
|
||||
defaultValues,
|
||||
}: CreateUserFormProps) {
|
||||
const {
|
||||
mutate: saveAccountingAccounts,
|
||||
isPending: isSaving,
|
||||
isError,
|
||||
} = useCreateUser();
|
||||
|
||||
// const { data: AccoutingAccounts } = useSurveyMutation();
|
||||
|
||||
const defaultformValues = {
|
||||
username: defaultValues?.username || '',
|
||||
fullname: defaultValues?.fullname || '',
|
||||
email: defaultValues?.email || '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
id: defaultValues?.id,
|
||||
phone: defaultValues?.phone || '',
|
||||
role: defaultValues?.role,
|
||||
}
|
||||
|
||||
const form = useForm<CreateUser>({
|
||||
resolver: zodResolver(createUser),
|
||||
defaultValues: defaultformValues,
|
||||
mode: 'onChange', // Enable real-time validation
|
||||
});
|
||||
|
||||
const onSubmit = async (data: CreateUser) => {
|
||||
|
||||
const formData = data
|
||||
|
||||
saveAccountingAccounts(formData, {
|
||||
onSuccess: () => {
|
||||
form.reset();
|
||||
onSuccess?.();
|
||||
},
|
||||
onError: (e) => {
|
||||
form.setError('root', {
|
||||
type: 'manual',
|
||||
message: 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="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>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 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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
'use client';
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { AlertModal } from '@/components/modal/alert-modal';
|
||||
import { Button } from '@repo/shadcn/button';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from '@repo/shadcn/tooltip';
|
||||
import { Edit, Trash, User } from 'lucide-react';
|
||||
import { SurveyTable } from '@/feactures/users/schemas/users';
|
||||
import { useDeleteUser } from '@/feactures/users/hooks/use-mutation-users';
|
||||
import { AccountPlanModal } from '../user-modal';
|
||||
|
||||
interface CellActionProps {
|
||||
data: SurveyTable;
|
||||
}
|
||||
|
||||
export const CellAction: React.FC<CellActionProps> = ({ data }) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [edit, setEdit] = useState(false);
|
||||
const { mutate: deleteUser } = useDeleteUser();
|
||||
const router = useRouter();
|
||||
|
||||
const onConfirm = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
deleteUser(data.id!);
|
||||
setOpen(false);
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<AlertModal
|
||||
isOpen={open}
|
||||
onClose={() => setOpen(false)}
|
||||
onConfirm={onConfirm}
|
||||
loading={loading}
|
||||
title="¿Estás seguro que desea deshabilitar este usuario?"
|
||||
description="Esta acción no se puede deshacer."
|
||||
/>
|
||||
|
||||
<AccountPlanModal open={edit} onOpenChange={setEdit} defaultValues={data}/>
|
||||
|
||||
<div className="flex gap-1">
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => setEdit(true)}
|
||||
>
|
||||
<Edit className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>Editar</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
<Trash className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>Deshabilitar</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Badge } from "@repo/shadcn/badge";
|
||||
|
||||
import { ColumnDef } from '@tanstack/react-table';
|
||||
import { CellAction } from './cell-action';
|
||||
import { SurveyTable } from '@/feactures/users/schemas/users';
|
||||
|
||||
export const columns: ColumnDef<SurveyTable>[] = [
|
||||
{
|
||||
accessorKey: 'username',
|
||||
header: 'Usuario',
|
||||
},
|
||||
{
|
||||
accessorKey: "email",
|
||||
header: "Correo",
|
||||
},
|
||||
{
|
||||
accessorKey: 'role',
|
||||
header: 'Rol',
|
||||
},
|
||||
{
|
||||
accessorKey: 'isActive',
|
||||
header: 'Status',
|
||||
cell: ({ row }) => {
|
||||
const status = row.getValue("isActive");
|
||||
return (
|
||||
<Badge variant={status == true ? "default" : "secondary"}>
|
||||
{status == true ? 'Activo' : 'Inactivo'}
|
||||
</Badge>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
header: 'Acciones',
|
||||
cell: ({ row }) => <CellAction data={row.original} />,
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,59 @@
|
||||
'use client';
|
||||
|
||||
import { PUBLISHED_TYPES } from '@/feactures/surveys/schemas/surveys-options';
|
||||
import { searchParams } from '@repo/shadcn/lib/searchparams';
|
||||
import { useQueryState } from 'nuqs';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
|
||||
export const TYPE_OPTIONS = Object.entries(PUBLISHED_TYPES).map(
|
||||
([value, label]) => ({
|
||||
value,
|
||||
label,
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
export function useSurveyTableFilters() {
|
||||
const [searchQuery, setSearchQuery] = useQueryState(
|
||||
'q',
|
||||
searchParams.q
|
||||
.withOptions({
|
||||
shallow: false,
|
||||
throttleMs: 500, // Add 500ms delay
|
||||
// Removed dedupingInterval as it's not a valid option
|
||||
})
|
||||
.withDefault(''),
|
||||
);
|
||||
|
||||
const [typeFilter, setTypeFilter] = useQueryState(
|
||||
'published',
|
||||
searchParams.q.withOptions({ shallow: false }).withDefault(''),
|
||||
);
|
||||
|
||||
const [page, setPage] = useQueryState(
|
||||
'page',
|
||||
searchParams.page.withDefault(1),
|
||||
);
|
||||
|
||||
const resetFilters = useCallback(() => {
|
||||
setSearchQuery(null);
|
||||
setTypeFilter(null);
|
||||
setPage(1);
|
||||
}, [setSearchQuery, setPage]);
|
||||
|
||||
const isAnyFilterActive = useMemo(() => {
|
||||
return !!searchQuery || !!typeFilter;
|
||||
}, [searchQuery]);
|
||||
|
||||
return {
|
||||
searchQuery,
|
||||
setSearchQuery,
|
||||
page,
|
||||
setPage,
|
||||
resetFilters,
|
||||
isAnyFilterActive,
|
||||
typeFilter,
|
||||
setTypeFilter
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
'use client';
|
||||
|
||||
import { DataTableFilterBox } from '@repo/shadcn/table/data-table-filter-box';
|
||||
import { DataTableSearch } from '@repo/shadcn/table/data-table-search';
|
||||
import {
|
||||
TYPE_OPTIONS,
|
||||
useSurveyTableFilters,
|
||||
} from './use-survey-table-filters';
|
||||
|
||||
export default function UserTableAction() {
|
||||
const {
|
||||
typeFilter,
|
||||
searchQuery,
|
||||
setPage,
|
||||
setTypeFilter,
|
||||
setSearchQuery,
|
||||
} = useSurveyTableFilters();
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap items-center gap-4 pt-2">
|
||||
<DataTableSearch
|
||||
searchKey={searchQuery}
|
||||
searchQuery={searchQuery || ''}
|
||||
setSearchQuery={setSearchQuery}
|
||||
setPage={setPage}
|
||||
/>
|
||||
{/* <DataTableFilterBox
|
||||
filterKey="type"
|
||||
title="Estado"
|
||||
options={TYPE_OPTIONS}
|
||||
setFilterValue={setTypeFilter}
|
||||
filterValue={typeFilter}
|
||||
/> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
227
apps/web/feactures/users/components/admin/update-user-form.tsx
Normal file
227
apps/web/feactures/users/components/admin/update-user-form.tsx
Normal file
@@ -0,0 +1,227 @@
|
||||
'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>
|
||||
);
|
||||
}
|
||||
69
apps/web/feactures/users/components/admin/user-modal.tsx
Normal file
69
apps/web/feactures/users/components/admin/user-modal.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@repo/shadcn/dialog';
|
||||
import { AccountPlan } from '@/feactures/users/schemas/account-plan.schema';
|
||||
import { CreateUserForm } from './create-user-form';
|
||||
import { UpdateUserForm } 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>
|
||||
{defaultValues?.id
|
||||
? 'Actualizar usuario'
|
||||
: 'Crear usuario'}
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
Complete los campos para {defaultValues?.id ? 'actualizar' : 'crear'} un usuario
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
{defaultValues?.id ? (
|
||||
<UpdateUserForm
|
||||
onSuccess={handleSuccess}
|
||||
onCancel={handleCancel}
|
||||
defaultValues={defaultValues}
|
||||
/>
|
||||
): (
|
||||
<CreateUserForm
|
||||
onSuccess={handleSuccess}
|
||||
onCancel={handleCancel}
|
||||
defaultValues={defaultValues}
|
||||
/>
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
'use client';
|
||||
|
||||
import { DataTable } from '@repo/shadcn/table/data-table';
|
||||
import { DataTableSkeleton } from '@repo/shadcn/table/data-table-skeleton';
|
||||
import { columns } from './surveys-tables/columns';
|
||||
import { useUsersQuery } from '../../hooks/use-query-users';
|
||||
|
||||
interface SurveysAdminListProps {
|
||||
initialPage: number;
|
||||
initialSearch?: string | null;
|
||||
initialLimit: number;
|
||||
initialType?: string | null;
|
||||
}
|
||||
|
||||
export default function UsersAdminList({
|
||||
initialPage,
|
||||
initialSearch,
|
||||
initialLimit,
|
||||
initialType,
|
||||
}: SurveysAdminListProps) {
|
||||
const filters = {
|
||||
page: initialPage,
|
||||
limit: initialLimit,
|
||||
...(initialSearch && { search: initialSearch }),
|
||||
...(initialType && { type: initialType }),
|
||||
};
|
||||
|
||||
const {data, isLoading} = useUsersQuery(filters)
|
||||
|
||||
// console.log(data?.data);
|
||||
|
||||
if (isLoading) {
|
||||
return <DataTableSkeleton columnCount={6} rowCount={initialLimit} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={data?.data || []}
|
||||
totalItems={data?.meta.totalCount || 0}
|
||||
pageSizeOptions={[10, 20, 30, 40, 50]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
27
apps/web/feactures/users/components/admin/users-header.tsx
Normal file
27
apps/web/feactures/users/components/admin/users-header.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
'use client';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Button } from '@repo/shadcn/button';
|
||||
import { Heading } from '@repo/shadcn/heading';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { AccountPlanModal } from './user-modal';
|
||||
|
||||
export function UsersHeader() {
|
||||
const [open, setOpen] = useState(false);
|
||||
// const router = useRouter();
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-start justify-between">
|
||||
<Heading
|
||||
title="Administración de usuarios"
|
||||
description="Gestiona los usuarios registrados en la plataforma"
|
||||
/>
|
||||
<Button onClick={() => setOpen(true)} size="sm">
|
||||
<Plus className="mr-2 h-4 w-4" /> Agregar Usuario
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<AccountPlanModal open={open} onOpenChange={setOpen} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user