diff --git a/first-app/package-lock.json b/first-app/package-lock.json
index d85e9f9..d54636a 100644
--- a/first-app/package-lock.json
+++ b/first-app/package-lock.json
@@ -13,7 +13,8 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.1.1",
- "react-router-dom": "^6.13.0"
+ "react-router-dom": "^6.13.0",
+ "react-toastify": "^9.1.3"
},
"devDependencies": {
"@types/react": "^18.0.37",
@@ -1686,6 +1687,14 @@
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
},
+ "node_modules/clsx": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
+ "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -3582,6 +3591,18 @@
"react-dom": ">=16.8"
}
},
+ "node_modules/react-toastify": {
+ "version": "9.1.3",
+ "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz",
+ "integrity": "sha512-fPfb8ghtn/XMxw3LkxQBk3IyagNpF/LIKjOBflbexr2AWxAH1MJgvnESwEwBn9liLFXgTKWgBSdZpw9m4OTHTg==",
+ "dependencies": {
+ "clsx": "^1.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16",
+ "react-dom": ">=16"
+ }
+ },
"node_modules/redux": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
diff --git a/first-app/package.json b/first-app/package.json
index 75fe6b2..d815ce5 100644
--- a/first-app/package.json
+++ b/first-app/package.json
@@ -15,7 +15,8 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.1.1",
- "react-router-dom": "^6.13.0"
+ "react-router-dom": "^6.13.0",
+ "react-toastify": "^9.1.3"
},
"devDependencies": {
"@types/react": "^18.0.37",
diff --git a/first-app/src/App.tsx b/first-app/src/App.tsx
index 509f3d7..a40b341 100644
--- a/first-app/src/App.tsx
+++ b/first-app/src/App.tsx
@@ -3,13 +3,12 @@ import {
RouterProvider,
} from "react-router-dom";
import './App.css'
-import { NotificationProvider } from "./context/NotificationContext";
+import { ToastContainer } from "./hooks/useToastfy";
//pages
import PageBase from "./pages/PageBase/PageBase";
import NewCliente from "./pages/Cliente/NewCliente";
-import { notification } from "antd";
-import { IconType } from "antd/es/notification/interface";
+import Clientes from "./pages/Cliente/Clientes";
const router = createBrowserRouter([
{
@@ -19,6 +18,10 @@ const router = createBrowserRouter([
{
path:"/cliente/new",
element:
+ },
+ {
+ path:"/cliente/list",
+ element:
}
]
},
@@ -27,22 +30,10 @@ const router = createBrowserRouter([
function App() {
- const [api, contextHolder] = notification.useNotification();
-
- const openNotification = (message:string, description:string, type:IconType) => {
- api.open({
- type:type,
- message: message,
- description: description,
- });
- };
-
return (
-
- {contextHolder}
+
-
)
}
diff --git a/first-app/src/components/ClienteForm.tsx b/first-app/src/components/ClienteForm.tsx
index 02628b6..b25c6ee 100644
--- a/first-app/src/components/ClienteForm.tsx
+++ b/first-app/src/components/ClienteForm.tsx
@@ -1,9 +1,9 @@
import { Button, Form, Input, Select } from 'antd';
import styles from '../pages/Cliente/Cliente.module.css';
import { useEffect } from 'react';
-import {
+import {
getAllPaises
- } from '../slices/ClienteSlice';
+} from '../slices/ClienteSlice';
import { useDispatch, useSelector } from 'react-redux';
import { Cliente } from '../interfaces/Cliente';
@@ -14,88 +14,95 @@ export interface FormClienteProps {
}
function ClienteForm(props: FormClienteProps) {
- const {paises} = useSelector((state:any)=>state.cliente);
+ const { paises, loading} = useSelector((state: any) => state.cliente);
const dispatch = useDispatch();
const onFinish = (values: any) => {
- const cliente:Cliente = {
- nome:values.nome,
- email:values.email,
- telefone:values.telefone,
- pais:{
- uid:values.pais,
- nome:''
+ const cliente: Cliente = {
+ nome: values.nome,
+ email: values.email,
+ telefone: values.telefone,
+ pais: {
+ uid: values.pais,
+ nome: ''
}
}
props.eventEmiter(cliente);
};
const onFinishFailed = (errorInfo: any) => {
- console.log('Failed:', errorInfo);
+ console.log('Failed:', errorInfo);
};
useEffect(() => {
- dispatch(getAllPaises())
+ dispatch(getAllPaises())
}, []);
return (
<>
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
-
-
+
+ {(loading === false) && (
+
+ )}
+ {(loading === true) && (
+
+ )}
+
+
>
)
}
diff --git a/first-app/src/components/sideBar.tsx b/first-app/src/components/sideBar.tsx
index cfb5bc8..2b0ff7f 100644
--- a/first-app/src/components/sideBar.tsx
+++ b/first-app/src/components/sideBar.tsx
@@ -33,8 +33,7 @@ function SideBar () {
const items: MenuItem[] = [
getItem('Clientes', 'sub1', , [
getItem((Novo Cliente), '1'),
- getItem('Listar todos', '3'),
- getItem('Alex', '4'),
+ getItem((Ver todos), '3'),
]),
getItem('Produtos', 'sub2', , [
getItem('Tom', '5'),
@@ -53,7 +52,7 @@ function SideBar () {
return (
setCollapsed(value)}>
-
+
)
}
diff --git a/first-app/src/hooks/useNotification.ts b/first-app/src/hooks/useNotification.ts
deleted file mode 100644
index ca59487..0000000
--- a/first-app/src/hooks/useNotification.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { notification } from "antd";
-import { IconType, NotificationInstance } from "antd/es/notification/interface";
-
- const [api, contextHolder] = notification.useNotification();
-
- const openNotification = (message:string, description:string, type:IconType) => {
- api.open({
- type:type,
- message: message,
- description: description,
- });
- };
-
-export {
- openNotification
-}
diff --git a/first-app/src/hooks/useToastfy.ts b/first-app/src/hooks/useToastfy.ts
index e69de29..ddac853 100644
--- a/first-app/src/hooks/useToastfy.ts
+++ b/first-app/src/hooks/useToastfy.ts
@@ -0,0 +1,8 @@
+import { ToastContainer, toast } from 'react-toastify';
+import 'react-toastify/dist/ReactToastify.css';
+
+
+const notify = (message:String,type:any) => toast(message,{type:type,autoClose:2000,theme:'dark'});
+
+
+export {notify, ToastContainer};
\ No newline at end of file
diff --git a/first-app/src/interfaces/ParamsType.ts b/first-app/src/interfaces/ParamsType.ts
new file mode 100644
index 0000000..abaae4c
--- /dev/null
+++ b/first-app/src/interfaces/ParamsType.ts
@@ -0,0 +1,7 @@
+export interface ParamsType {
+ pagination?:{
+ pageSize:number,
+ current:number
+ },
+ filter?:any
+}
\ No newline at end of file
diff --git a/first-app/src/pages/Cliente/Cliente.module.css b/first-app/src/pages/Cliente/Cliente.module.css
index 0dcac9a..2fc6aa6 100644
--- a/first-app/src/pages/Cliente/Cliente.module.css
+++ b/first-app/src/pages/Cliente/Cliente.module.css
@@ -1,3 +1,20 @@
.form_cliente{
width: 600px;
+}
+
+.container_table {
+ width: 800px;
+ display: flex;
+ flex-direction: column;
+}
+
+.container_table__filter{
+ width: 100%;
+ display: flex;
+ justify-content: end;
+ margin-bottom: 1em;
+}
+
+.container_table__search{
+ width: 300px;
}
\ No newline at end of file
diff --git a/first-app/src/pages/Cliente/Clientes.tsx b/first-app/src/pages/Cliente/Clientes.tsx
new file mode 100644
index 0000000..4dedc50
--- /dev/null
+++ b/first-app/src/pages/Cliente/Clientes.tsx
@@ -0,0 +1,141 @@
+import Table from "antd/es/table";
+import {
+ getAllClientes,
+ deleteCliente
+} from '../../slices/ClienteSlice';
+import { useDispatch, useSelector } from "react-redux";
+import { useEffect, useState } from "react";
+import { Cliente } from "../../interfaces/Cliente";
+import Column from "antd/es/table/Column";
+import { Button, Input, Popconfirm, Space } from "antd";
+import {
+ DeleteOutlined,
+ EditOutlined
+} from '@ant-design/icons'
+import { useNavigate } from "react-router-dom";
+import { ParamsType } from "../../interfaces/ParamsType";
+import styles from './Cliente.module.css';
+const { Search } = Input;
+
+function Clientes() {
+
+ const dispatch = useDispatch();
+ const navigate = useNavigate();
+ const { clientes, total, loading } = useSelector((state: any) => state.cliente);
+ const [nomeSearch, setNomeSearch] = useState('');
+
+ const onChangePage = (page: any, size: any) => {
+
+ const params: ParamsType = {
+ pagination: {
+ current: page,
+ pageSize: size
+ },
+ filter: {
+ nome: nomeSearch != '' ? nomeSearch : ''
+ }
+ }
+ dispatch(getAllClientes(params))
+ }
+
+ const handleDelete = (uid: string) => {
+ dispatch(deleteCliente(uid));
+ }
+
+ const handleSearch = (nome: string) => {
+
+ setNomeSearch(nome);
+ const params: ParamsType = {
+ pagination: {
+ current: 1,
+ pageSize: 5
+ },
+ filter: {
+ nome: nome
+ }
+ }
+ dispatch(getAllClientes(params))
+ }
+
+ useEffect(() => {
+ dispatch(getAllClientes(
+ { pagination: { current: 1, pageSize: 5 } }
+ ));
+ }, [])
+
+ return (
+
+
+
+
+
(
+ { key: cliente.uid, name: cliente.nome, email: cliente.email, pais: cliente.pais?.nome }
+ ))
+ }
+ pagination={{
+ position: ["bottomCenter"],
+ total: total,
+ defaultPageSize: 5,
+ onChange(page, pageSize) {
+ onChangePage(page, pageSize)
+ },
+ pageSizeOptions: [5, 10, 15],
+ showSizeChanger: true,
+ onShowSizeChange(current, size) {
+ onChangePage(current, size)
+ },
+ }}
+ loading={loading}
+ bordered={true}
+ >
+
+
+
+
+ (
+
+
+ { handleDelete(record.key) }}
+ okText="Sim"
+ cancelText="Não"
+ >
+ }
+ size="large"
+ title="Deletar"
+ />
+
+
+ } size="large"
+ title="Atualizar"
+ onClick={() => { navigate(`/cliente/new`) }}
+ />
+
+ )}
+ />
+
+
+
+
+
+ )
+}
+
+export default Clientes;
\ No newline at end of file
diff --git a/first-app/src/services/ClienteService.ts b/first-app/src/services/ClienteService.ts
index 9309ef4..7e43398 100644
--- a/first-app/src/services/ClienteService.ts
+++ b/first-app/src/services/ClienteService.ts
@@ -1,5 +1,6 @@
import { Environments } from "../environments"
import { Cliente } from "../interfaces/Cliente";
+import { ParamsType } from "../interfaces/ParamsType";
const { URLApi } = Environments;
@@ -29,7 +30,6 @@ const registerCliente = async (cliente:Cliente) => {
const data = await fetch(`${URLApi}/cliente`,config)
.then((res)=>res.json())
.catch((err)=>err);
- console.log(data);
return data;
} catch (error) {
console.info(error);
@@ -38,7 +38,34 @@ const registerCliente = async (cliente:Cliente) => {
}
+const getAllClientes = async (params:ParamsType) => {
+ const config = {
+ method:"POST",
+ body:JSON.stringify(params),
+ headers: {
+ "Content-type":"application/json",
+ }
+ }
+
+ const data = await fetch(`${URLApi}/cliente/list`,config)
+ .then((res)=>res.json())
+ .catch((err)=>err);
+
+ return data;
+}
+
+const deleteCliente = async (uid:string) => {
+
+ const data = await fetch(`${URLApi}/cliente?uid=${uid}`,{method:"DELETE"})
+ .then ((res)=>res.json())
+ .catch((err)=>err);
+
+ return data;
+}
+
export const ClienteServices = {
getAllPaises,
- registerCliente
+ registerCliente,
+ getAllClientes,
+ deleteCliente
}
\ No newline at end of file
diff --git a/first-app/src/slices/ClienteSlice.ts b/first-app/src/slices/ClienteSlice.ts
index 1f4d95a..f4abe7e 100644
--- a/first-app/src/slices/ClienteSlice.ts
+++ b/first-app/src/slices/ClienteSlice.ts
@@ -3,12 +3,14 @@ import {
ClienteServices
} from "../services/ClienteService";
import { Cliente } from "../interfaces/Cliente";
+import { notify } from "../hooks/useToastfy";
+import { ParamsType } from "../interfaces/ParamsType";
const initialState = {
- cliente:{},
paises:[] as any,
clientes:[] as any,
- loadind:false,
+ total:0,
+ loading:false,
error:false,
success:true,
message:''
@@ -33,13 +35,29 @@ export const registerCliente = createAsyncThunk(
}
)
+export const getAllClientes = createAsyncThunk(
+ "cliente/getAll",
+ async (params:ParamsType) => {
+ const data = await ClienteServices.getAllClientes(params);
+ return data;
+ }
+)
+
+export const deleteCliente = createAsyncThunk(
+ "cliente/delete",
+ async (uid:string) => {
+ const data = await ClienteServices.deleteCliente(uid);
+ return data;
+ }
+)
+
export const clienteSlice = createSlice({
name:"cliente",
initialState,
reducers:{
resetState:(state)=>{
- state.loadind = false;
+ state.loading = false;
state.error = false;
state.message = '';
},
@@ -48,22 +66,46 @@ export const clienteSlice = createSlice({
extraReducers(builder) {
builder
.addCase(getAllPaises.pending,(state)=>{
- state.loadind = true;
+ state.loading = true;
}).addCase(getAllPaises.fulfilled,(state,action)=>{
state.paises = action.payload.result;
- state.loadind = false;
+ state.loading = false;
})
.addCase(registerCliente.pending,(state)=>{
- state.loadind = true;
+ state.loading = true;
}).addCase(registerCliente.fulfilled, (state)=>{
- state.loadind = false;
+ state.loading = false;
state.success = true;
+ notify('Novo cliente cadastrado!','success');
}).addCase(registerCliente.rejected,(state,action:any)=>{
- state.loadind = false;
+ state.loading = false;
state.error = true;
state.success = false;
state.message = action.payload ? action.payload.message : 'Error ao cadastrar cliente, revise os dados e tente novamente!';
+ notify(state.message,'error');
+ })
+
+ .addCase(getAllClientes.pending,(state)=>{
+ state.loading = true;
+ }).addCase(getAllClientes.fulfilled,(state,action)=>{
+ state.clientes = action.payload.result;
+ state.total = action.payload.total;
+ state.loading = false;
+ })
+
+ .addCase(deleteCliente.pending,(state)=>{
+ state.loading = true;
+ }).addCase(deleteCliente.fulfilled,(state,action)=>{
+ state.clientes = state.clientes.filter((cliente:Cliente)=>(cliente.uid !== action.payload.uid));
+ state.total = state.total - 1;
+ state.loading = false;
+ notify('Cliente deletedo com sucesso!','success');
+ }).addCase(deleteCliente.rejected,(state,action:any)=>{
+ state.loading = true;
+ state.error = true;
+ state.message = action.payload.message ? action.payload.message : 'Erro ao deletar cliente, tente novamente!';
+ notify(state.message,'error');
})
},
});