Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
"@types/react-router-dom": "^5.1.7",
"@types/styled-components": "^5.1.10",
"@types/yup": "^0.29.11",
"ag-grid-community": "30.0.6",
"ag-grid-react": "30.0.6",
"formik": "^2.2.9",
"react": "^17.0.2",
"react-dom": "^17.0.2",
Expand Down
2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Customer List</title>
<title>Customer Management</title>
</head>
<body style="padding: 0; margin: 0">
<noscript>You need to enable JavaScript to run this app.</noscript>
Expand Down
6 changes: 5 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from "react";
import { StyledMain, StyledHeader, StyledHeaderText } from "./StyledApp";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Home from "./views/Home";
import { AddCustomerForm } from "./components/AddCustomer/AddCustomerForm";

const App: React.FC = () => {
return (
Expand All @@ -11,9 +12,12 @@ const App: React.FC = () => {
</StyledHeader>
<Router>
<Switch>
<Route path="/">
<Route exact path="/">
<Home />
</Route>
<Route exact path="/addCustomer">
<AddCustomerForm />
</Route>
</Switch>
</Router>
</StyledMain>
Expand Down
155 changes: 122 additions & 33 deletions src/components/AddCustomer/AddCustomerForm.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,72 @@
import { Field, Formik, FormikHelpers } from "formik";
import * as React from "react";
import { ICustomer, Customer } from "../../types/types";
import { ICustomer, Customer, CustomerState } from "../../types/types";
import {
StyledForm,
StyledInput,
StyledLabel,
StyledAddButton,
StyledCancelButton,
StyledError,
} from "./StyledAddCustomerForm";
import { addCustomer } from "../../redux/actions/customerActions";
import { Dispatch } from "redux";
import { shallowEqual, useDispatch, useSelector } from "react-redux";
import { useHistory } from "react-router-dom";
import * as Yup from "yup";

type Props = {
saveCustomer: (customer: ICustomer | any) => void;
};
const CustomerSchema = Yup.object().shape({
firstName: Yup.string()
.min(2, "Too Short!")
.max(50, "Too Long!")
.required("Required"),
lastName: Yup.string()
.min(2, "Too Short!")
.max(50, "Too Long!")
.required("Required"),
phoneNumber: Yup.string()
.matches(/^(\(0[1-9]\)|0[1-9])?( ?-?[0-9]){10,10}$/, "Invalid phone number")
.required("Required"),
birthday: Yup.date().required("Required"),
});

export const AddCustomerForm: React.FC = () => {
let history = useHistory();
const dispatch: Dispatch<any> = useDispatch();

const customers: ICustomer[] = useSelector(
(state: CustomerState) => state.customers,
shallowEqual
);

const saveCustomer = React.useCallback(
(customer: ICustomer | any) => {
let isCustomerFound = customers.find(cust => cust.firstName === customer.firstName && cust.lastName === customer.lastName && cust.phoneNumber === customer.phoneNumber)
if(!isCustomerFound) {
dispatch(addCustomer(customer));
history.push("/");
} else {
alert('Customer already exist')
}


},
[dispatch]
);

const cancel = () => {
history.push("/");
};

export const AddCustomerForm: React.FC<Props> = ({ saveCustomer }) => {
return (
<Formik
initialValues={{
firstName: "",
lastName: "",
phoneNumber: "",
birthday: "",
}}
validationSchema={CustomerSchema}
onSubmit={(
values: Customer,
{ setSubmitting }: FormikHelpers<Customer>
Expand All @@ -28,34 +75,76 @@ export const AddCustomerForm: React.FC<Props> = ({ saveCustomer }) => {
setSubmitting(false);
}}
>
<StyledForm>
<StyledLabel htmlFor="firstName">First Name</StyledLabel>
<Field
as={StyledInput}
id="firstName"
name="firstName"
placeholder="John"
/>

<StyledLabel htmlFor="lastName">Last Name</StyledLabel>
<Field
as={StyledInput}
id="lastName"
name="lastName"
placeholder="Doe"
/>

<StyledLabel htmlFor="phoneNumber">Phone Number</StyledLabel>
<Field
as={StyledInput}
id="phoneNumber"
name="phoneNumber"
placeholder="john@acme.com"
type="tel"
/>

<StyledAddButton type="submit">Add Customer</StyledAddButton>
</StyledForm>
{({ errors, touched }) => (
<StyledForm>
<StyledLabel htmlFor="firstName">
First Name*{" "}
{errors.firstName && touched.firstName ? (
<StyledError>{errors.firstName}</StyledError>
) : null}
</StyledLabel>
<Field
as={StyledInput}
id="firstName"
name="firstName"
placeholder="John"
aria-label={'First Name'}
aria-required="true"
/>

<StyledLabel htmlFor="lastName">
Last Name*{" "}
{errors.lastName && touched.lastName ? (
<StyledError>{errors.lastName}</StyledError>
) : null}
</StyledLabel>
<Field
as={StyledInput}
id="lastName"
name="lastName"
placeholder="Doe"
aria-label={'Last Name'}
aria-required="true"
/>

<StyledLabel htmlFor="phoneNumber">
Phone Number*{" "}
{errors.phoneNumber && touched.phoneNumber ? (
<StyledError>{errors.phoneNumber}</StyledError>
) : null}
</StyledLabel>

<Field
as={StyledInput}
id="phoneNumber"
name="phoneNumber"
placeholder="03 333 333 333"
type="tel"
aria-label={'Phone'}
aria-required="true"
/>

<StyledLabel htmlFor="birthday">
Birthday*{" "}
{errors.birthday && touched.birthday ? (
<StyledError>{errors.birthday}</StyledError>
) : null}
</StyledLabel>

<Field
as={StyledInput}
id="birthday"
name="birthday"
placeholder="DD/MM/YYYY"
type="date"
aria-label={'Birthday'}
aria-required="true"
/>

<StyledAddButton type="submit">Add Customer</StyledAddButton>
<StyledCancelButton onClick={cancel}>Cancel</StyledCancelButton>
</StyledForm>
)}
</Formik>
);
};
17 changes: 17 additions & 0 deletions src/components/AddCustomer/StyledAddCustomerForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,20 @@ export const StyledAddButton = styled.button`
border-radius: 4px;
font-size: 16px;
`;

export const StyledCancelButton = styled.button`
padding: 1rem;
background-color: gray;
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
margin-top: 5px
`;

export const StyledError = styled.div`
float: right;
font-size: 14px;
color: red;
`;
3 changes: 3 additions & 0 deletions src/components/Customer/Customer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export const Customer: React.FC<Props> = ({ customer, removeCustomer }) => {
<StyledCustomerInfo>
Phone number: {customer.phoneNumber}
</StyledCustomerInfo>
<StyledCustomerInfo>
Birthday: {customer.birthday}
</StyledCustomerInfo>
<StyledCustomerDelete onClick={() => deleteCustomer(customer)}>
Delete
</StyledCustomerDelete>
Expand Down
3 changes: 2 additions & 1 deletion src/components/Customer/StyledCustomer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ export const StyledCustomerInfo = styled.p`
`;

export const StyledCustomerDelete = styled.button`
padding: 1rem;
padding: 6px;
height: 30px;
background-color: #dc1616;
color: white;
border: none;
Expand Down
21 changes: 21 additions & 0 deletions src/components/Grid/ButtonCellRenderer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react";
import { StyledCustomerDelete } from "../Customer/StyledCustomer";
import { Dispatch } from "redux";
import { useDispatch } from "react-redux";
import { ICustomer } from "../../types/types";
import { removeCustomer } from "../../redux/actions/customerActions";

export const ButtonCellRenderer: React.FC<any> = (params) => {
const dispatch: Dispatch<any> = useDispatch();

const deleteCustomer = React.useCallback(
(customer: ICustomer) => dispatch(removeCustomer(customer)),
[dispatch, removeCustomer]
);

return (
<StyledCustomerDelete onClick={() => deleteCustomer(params.data)}>
Delete
</StyledCustomerDelete>
);
};
4 changes: 4 additions & 0 deletions src/redux/reducers/customerReducers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,21 @@ export const initialState: CustomerState = {
firstName: "Charles",
lastName: "Babbage",
phoneNumber: "0412 123 123",
birthday: "1992-10-05",
},
{
id: 2,
firstName: "Alan",
lastName: "Turing",
phoneNumber: "(03) 9599 1234",
birthday: "1990-11-02",
},
{
id: 3,
firstName: "Ada",
lastName: "Lovelace",
phoneNumber: "+61 423 345 567",
birthday: "1984-04-09",
},
],
};
Expand All @@ -35,6 +38,7 @@ export const customerReducer = (
firstName: action.customer.firstName,
lastName: action.customer.lastName,
phoneNumber: action.customer.phoneNumber,
birthday: action.customer.birthday,
};
return {
...state,
Expand Down
1 change: 1 addition & 0 deletions src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export interface Customer {
firstName: string;
lastName: string;
phoneNumber: string;
birthday: string;
}

export interface ICustomer extends Customer {
Expand Down
Loading