Sử dụng @faker-js/faker, mock (ok)
https://www.npmjs.com/package/@faker-js/faker
Last updated
Was this helpful?
https://www.npmjs.com/package/@faker-js/faker
Last updated
Was this helpful?
Nó là một phần của dự án này
src\mocks\users.mock.ts
import { User } from '@/types/users.type';
import { faker } from '@faker-js/faker';
export const mockUsers: User[] = [];
for (let index = 0; index < 10; index++) {
mockUsers.push({
id: faker.number.int(),
email: faker.internet.email(),
first_name: faker.person.firstName(),
last_name: faker.person.lastName(),
avatar: faker.image.url({width:500, height:500}),
});
}
src\pages\users\index.tsx
import React, { useCallback, useEffect, useState } from 'react';
import { User, UserGetParams } from '@/types/users.type';
import UserList from '@/views/users/UserList';
import Head from 'next/head';
import UserFilter from '@/views/users/UserFilter';
function UserPage() {
const [filter, setFilter] = useState<UserGetParams>({});
const [justCreatedUser, setJustCreatedUser] = useState<User[]>([]);
const handleChangeFilter = useCallback((newFilter: UserGetParams) => {
setFilter(newFilter);
}, []);
const handleCreatedUser = useCallback((data: User) => {
setJustCreatedUser((prev) => [data, ...prev]);
}, []);
return (
<>
<Head>
<title>Users</title>
</Head>
<UserFilter filter={filter} onChange={handleChangeFilter} onCreatedUser={handleCreatedUser} />
<UserList filter={filter} justCreatedUser={justCreatedUser} />
</>
);
}
export const getServerSideProps = async () => ({
props: {}
});
export default UserPage;
src\views\users\UserFilter.tsx
import React, { ProviderProps, useEffect, useState } from 'react';
import { Dialog, DialogBackdrop, DialogPanel, DialogTitle } from '@headlessui/react'
import { User, UserGetParams } from '@/types/users.type';
import { GoPersonAdd } from "react-icons/go";
import { Controller, useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import useCreateUser from '@/hooks/users/useCreateUser';
import { faker } from '@faker-js/faker';
import * as yup from 'yup';
type Props = {
filter: UserGetParams;
onChange: (newFilter: UserGetParams) => void;
onCreatedUser: (data: User) => void;
};
const schema = yup.object().shape({
first_name: yup.string().min(1).max(40).required(),
last_name: yup.string().min(1).max(40).required(),
email: yup.string().min(1).max(1000).email().required(),
});
const defaultValues = {
first_name: '',
last_name: '',
email: '',
};
function UserFilter({ filter, onChange, onCreatedUser }: Props) {
const [per_page, setLimit] = useState('10');
const [keyword, setKeyword] = useState('');
const [openCreate, toggleCreateCreate] = useState(false);
const toggleCreate = () => {
toggleCreateCreate((prev) => !prev);
};
const handleChangePageSize = (e: React.ChangeEvent<HTMLSelectElement>) => {
setLimit(e.target.value);
};
const handleKeywordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setKeyword(e.target.value);
};
useEffect(() => {
const timer = setTimeout(() => {
if (keyword != filter.keyword) {
onChange({ ...filter, keyword });
}
}, 500);
return () => clearTimeout(timer);
}, [keyword, filter, onChange]);
useEffect(() => {
if (filter.per_page != parseInt(per_page)) {
onChange({ ...filter, per_page: parseInt(per_page) });
}
}, [filter, per_page, onChange]);
const [{ loading, error }, doCreate] = useCreateUser({
first_name: '',
last_name: '',
email: "",
avatar: faker.image.url({ width: 500, height: 500 }),
id: 0
});
const { reset, control, handleSubmit, formState: { errors }, register } = useForm({ defaultValues, mode: 'onChange', resolver: yupResolver(schema), });
const onSubmit = (data: Partial<User>) => {
doCreate({ data })
.then((res) => {
if (res.status == 201) {
toggleCreate();
onCreatedUser({ ...res.data, ...data });
reset();
}
})
.catch((error) => {
console.log(error);
});
};
return (
<div className='container ml-auto mr-auto flex items-center'>
<div className='container ml-auto mr-auto flex items-center'>
<button onClick={toggleCreate} className='text-5xl'>
<GoPersonAdd />
</button>
<input type="text" placeholder="Search term..." onChange={handleKeywordChange} className='border p-2 ml-2' />
</div>
<Dialog open={openCreate} onClose={toggleCreate} className="relative z-10">
<DialogBackdrop transition className="fixed inset-0 bg-gray-500/75 transition-opacity data-closed:opacity-0 data-enter:duration-300 data-enter:ease-out data-leave:duration-200 data-leave:ease-in" />
<div className="fixed inset-0 z-10 w-screen overflow-y-auto">
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<DialogPanel
transition
className="relative transform overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all data-closed:translate-y-4 data-closed:opacity-0 data-enter:duration-300 data-enter:ease-out data-leave:duration-200 data-leave:ease-in sm:my-8 sm:w-full sm:max-w-lg data-closed:sm:translate-y-0 data-closed:sm:scale-95"
>
<div className="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div className="mt-3 w-full">
<DialogTitle as="h3" className="text-base font-semibold text-gray-900 ">
Add User
</DialogTitle>
<form onSubmit={handleSubmit(onSubmit)} className='grid grid-cols-1 grow-0 gap-2'>
<input type="text" {...register("first_name")} className='border py-2 px-4' placeholder="Enter your first name" />
<input type="text" {...register("last_name")} className='border py-2 px-4' placeholder="Enter your last name" />
<input type="email" {...register("email")} className='border py-2 px-4' placeholder="Enter your email" />
<button type="submit" disabled={loading} className='border py-2 px-4 hover:bg-cyan-400 hover:text-amber-50'>Save</button>
</form>
</div>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6">
<button
type="button"
data-autofocus
onClick={() => toggleCreate()}
className="mt-3 inline-flex w-full justify-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 shadow-xs ring-gray-300 ring-inset hover:bg-gray-50 sm:mt-0 sm:w-auto"
>
Cancel
</button>
</div>
</DialogPanel>
</div>
</div >
</Dialog >
<form className="max-w-sm mx-auto">
<select onChange={handleChangePageSize} className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
<option selected>Page Size</option>
<option value={10}>10</option>
<option value={20}>20</option>
<option value={30}>30</option>
</select>
</form>
</div >
);
}
export default UserFilter;
src\views\users\UserList.tsx
import React from 'react';
import useUserList from '@/hooks/users/useGetListUsers';
import { User, UserGetParams } from '@/types/users.type';
import UserListItem from './UserListItem';
type Props = {
filter: UserGetParams;
justCreatedUser: User[];
};
function UserList({ filter, justCreatedUser }: Props) {
const [{ data, error, loading }] = useUserList(filter);
return (
<div className='container ml-auto mr-auto grid grid-cols-4 gap-2'>
{justCreatedUser.map((user) => (
<div key={user.id}>
<UserListItem user={user} isNew />
</div>
))}
{data && data.data?.map((user) => (
<div key={user.id}>
<UserListItem user={user} />
</div>
))}
</div>
);
}
export default UserList;
src\views\users\UserListItem.tsx
import React, { useState } from 'react';
import { User } from '@/types/users.type';
import { useRouter } from 'next/router';
import { GoXCircleFill } from "react-icons/go";
import { GoThumbsup } from "react-icons/go";
type Props = {
user: User;
isNew?: boolean;
};
function UserListItem({ user, isNew = false }: Props) {
const router = useRouter();
const [openEdit, setOpenEdit] = useState(false);
const [openDelete, setOpenDelete] = useState(false);
const [visible, setVisible] = useState(true);
const [data, setData] = useState(user);
const toggleEdit = () => {
setOpenEdit((prev) => !prev);
};
const toggleDelete = () => {
setOpenDelete((prev) => !prev);
};
const toggleVisible = () => {
setVisible((prev) => !prev);
};
const handleItemClick = () => {
router.push(`/users/${user.id}`);
};
const handleUpdatedProduct = (newData: User) => {
setData(newData);
};
return (
<>
<div onClick={handleItemClick}>
<img src={data.avatar} alt="avatar" />
</div>
<p className='text-3xl font-bold'>
{data.first_name} {data.last_name}
</p>
<div className='text-7xl flex gap-2'>
<button onClick={toggleEdit}>
<GoThumbsup />
</button>
<button onClick={toggleDelete}>
<GoXCircleFill />
</button>
</div>
</>
);
}
export default UserListItem;