diff --git a/.eslintrc.json b/.eslintrc.backup.json
similarity index 100%
rename from .eslintrc.json
rename to .eslintrc.backup.json
diff --git a/package.json b/package.json
index 7fca2da57..49d87214a 100644
--- a/package.json
+++ b/package.json
@@ -18,13 +18,16 @@
"@emotion/styled": "11.10.8",
"@mui/icons-material": "5.11.16",
"@mui/material": "5.12.3",
+ "@reduxjs/toolkit": "^1.8.5",
"chart.js": "4.3.0",
"chroma-js": "2.4.2",
+ "classnames": "^2.3.2",
"prop-types": "15.8.1",
"react": "18.2.0",
"react-chartjs-2": "5.2.0",
"react-dom": "18.2.0",
"react-github-btn": "1.4.0",
+ "react-redux": "^8.0.4",
"react-router-dom": "6.11.0",
"react-scripts": "5.0.1",
"react-table": "7.8.0",
@@ -59,6 +62,7 @@
},
"devDependencies": {
"ajv": "^7.2.4",
+ "axios": "^1.1.3",
"eslint": "8.39.0",
"eslint-config-prettier": "8.8.0",
"eslint-plugin-import": "2.27.5",
diff --git a/src/App.js b/src/App.js
index 5ba40edb9..065435559 100644
--- a/src/App.js
+++ b/src/App.js
@@ -16,6 +16,7 @@ Coded by www.creative-tim.com
import { useState, useEffect, useMemo } from "react";
// react-router components
+import { Provider } from 'react-redux';
import { Routes, Route, Navigate, useLocation } from "react-router-dom";
// @mui material components
@@ -53,6 +54,9 @@ import { useMaterialUIController, setMiniSidenav, setOpenConfigurator } from "co
import brandWhite from "assets/images/logo-ct.png";
import brandDark from "assets/images/logo-ct-dark.png";
+// Store
+import store from './store'
+
export default function App() {
const [controller, dispatch] = useMaterialUIController();
const {
@@ -147,8 +151,35 @@ export default function App() {
);
return direction === "rtl" ? (
-
-
+
+
+
+
+ {layout === "dashboard" && (
+ <>
+
+
+ {configsButton}
+ >
+ )}
+ {layout === "vr" && }
+
+ {getRoutes(routes)}
+ } />
+
+
+
+
+ ) : (
+
+
{layout === "dashboard" && (
<>
@@ -170,29 +201,6 @@ export default function App() {
} />
-
- ) : (
-
-
- {layout === "dashboard" && (
- <>
-
-
- {configsButton}
- >
- )}
- {layout === "vr" && }
-
- {getRoutes(routes)}
- } />
-
-
+
);
}
diff --git a/src/assets/images/small-store.jpeg b/src/assets/images/small-store.jpeg
new file mode 100644
index 000000000..ee265e7e2
Binary files /dev/null and b/src/assets/images/small-store.jpeg differ
diff --git a/src/examples/Sidenav/index.js b/src/examples/Sidenav/index.js
index 5efd2d2c7..acf2d3b86 100644
--- a/src/examples/Sidenav/index.js
+++ b/src/examples/Sidenav/index.js
@@ -179,7 +179,8 @@ function Sidenav({ color, brand, brandName, routes, ...rest }) {
}
/>
{renderRoutes}
-
+ {/* // ! CHECK THIS OUT */}
+ {/*
upgrade to pro
-
+ */}
);
}
diff --git a/src/interfaces/clients.interface.ts b/src/interfaces/clients.interface.ts
new file mode 100644
index 000000000..230b6f934
--- /dev/null
+++ b/src/interfaces/clients.interface.ts
@@ -0,0 +1,8 @@
+export interface Client {
+ id: string;
+ full_name: string;
+ tax_id: string;
+ phone: string;
+ email: string;
+ _deleted: boolean;
+}
diff --git a/src/interfaces/discounts.interface.ts b/src/interfaces/discounts.interface.ts
new file mode 100644
index 000000000..e03defe94
--- /dev/null
+++ b/src/interfaces/discounts.interface.ts
@@ -0,0 +1,10 @@
+export interface Discount {
+ id: string;
+ products: string[];
+ type: 'total' | 'percentage';
+ amount: number;
+ start_date: Date;
+ end_date: Date;
+ enabled: boolean;
+ _deleted: boolean;
+}
diff --git a/src/interfaces/products.interface.ts b/src/interfaces/products.interface.ts
new file mode 100644
index 000000000..78039b38b
--- /dev/null
+++ b/src/interfaces/products.interface.ts
@@ -0,0 +1,9 @@
+export interface Product {
+ id: string;
+ internal_code: string;
+ name: string;
+ description: string;
+ price: number;
+ measurement: string;
+ _deleted: boolean;
+}
diff --git a/src/interfaces/sales.interface.ts b/src/interfaces/sales.interface.ts
new file mode 100644
index 000000000..0b32ca45d
--- /dev/null
+++ b/src/interfaces/sales.interface.ts
@@ -0,0 +1,10 @@
+export interface Sale {
+ id: string;
+ products: {
+ product_id: string,
+ quantity: number
+ }[];
+ client_id: string;
+ amount: number;
+ _deleted: boolean;
+}
diff --git a/src/layouts/create-sale/CreateSale.jsx b/src/layouts/create-sale/CreateSale.jsx
new file mode 100644
index 000000000..3bac2ef46
--- /dev/null
+++ b/src/layouts/create-sale/CreateSale.jsx
@@ -0,0 +1,52 @@
+import { useNavigate } from "react-router-dom";
+
+import SaleForm from "../sale-form";
+import GeneralButton from "../../shared/components/button";
+
+import "../../shared/styles/GeneralStyles.css";
+
+function CreateSale({ addSale, updateField, saleSelected, fetchClients, clientsList }) {
+
+ const navigate = useNavigate();
+ const navigateData = {
+ url: '/sales/list',
+ }
+
+ const addSaleData = {
+ saleSelected: saleSelected,
+ }
+
+ return (
+ <>
+
+ >
+ )
+}
+
+export default CreateSale;
\ No newline at end of file
diff --git a/src/layouts/create-sale/index.js b/src/layouts/create-sale/index.js
new file mode 100644
index 000000000..dc72225bb
--- /dev/null
+++ b/src/layouts/create-sale/index.js
@@ -0,0 +1,25 @@
+import { useSelector, useDispatch } from 'react-redux';
+
+import CreateSale from "./CreateSale";
+import fromSales from '../../store/sales/selectors';
+import fromClients from '../../store/clients/selectors';
+import salesCommands from '../../store/sales/commands';
+import clientsCommands from '../../store/clients/commands';
+
+const ConnectedCreateSale = () => {
+ const dispatch = useDispatch();
+
+ const selectorProps = {
+ saleSelected: useSelector(fromSales.currentSaleSelected),
+ clientsList: useSelector(fromClients.currentClients),
+ }
+
+ const dispatchProps = {
+ addSale: sale => dispatch(salesCommands.addSale(sale)),
+ updateField: (value, field) => dispatch(salesCommands.updateField(value, field)),
+ fetchClients: filter => dispatch(clientsCommands.getClients(filter)),
+ }
+ return ()
+}
+
+export default ConnectedCreateSale;
\ No newline at end of file
diff --git a/src/layouts/profile/components/PlatformSettings/index.js b/src/layouts/profile/components/PlatformSettings/index.js
deleted file mode 100644
index 398c0d4b6..000000000
--- a/src/layouts/profile/components/PlatformSettings/index.js
+++ /dev/null
@@ -1,115 +0,0 @@
-/**
-=========================================================
-* Material Dashboard 2 React - v2.2.0
-=========================================================
-
-* Product Page: https://www.creative-tim.com/product/material-dashboard-react
-* Copyright 2023 Creative Tim (https://www.creative-tim.com)
-
-Coded by www.creative-tim.com
-
- =========================================================
-
-* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-*/
-
-import { useState } from "react";
-
-// @mui material components
-import Card from "@mui/material/Card";
-import Switch from "@mui/material/Switch";
-
-// Material Dashboard 2 React components
-import MDBox from "components/MDBox";
-import MDTypography from "components/MDTypography";
-
-function PlatformSettings() {
- const [followsMe, setFollowsMe] = useState(true);
- const [answersPost, setAnswersPost] = useState(false);
- const [mentionsMe, setMentionsMe] = useState(true);
- const [newLaunches, setNewLaunches] = useState(false);
- const [productUpdate, setProductUpdate] = useState(true);
- const [newsletter, setNewsletter] = useState(false);
-
- return (
-
-
-
- platform settings
-
-
-
-
- account
-
-
-
- setFollowsMe(!followsMe)} />
-
-
-
- Email me when someone follows me
-
-
-
-
-
- setAnswersPost(!answersPost)} />
-
-
-
- Email me when someone answers on my post
-
-
-
-
-
- setMentionsMe(!mentionsMe)} />
-
-
-
- Email me when someone mentions me
-
-
-
-
-
- application
-
-
-
-
- setNewLaunches(!newLaunches)} />
-
-
-
- New launches and projects
-
-
-
-
-
- setProductUpdate(!productUpdate)} />
-
-
-
- Monthly product updates
-
-
-
-
-
- setNewsletter(!newsletter)} />
-
-
-
- Subscribe to newsletter
-
-
-
-
-
- );
-}
-
-export default PlatformSettings;
diff --git a/src/layouts/profile/data/profilesListData.js b/src/layouts/profile/data/profilesListData.js
deleted file mode 100644
index 61a4aecdf..000000000
--- a/src/layouts/profile/data/profilesListData.js
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
-=========================================================
-* Material Dashboard 2 React - v2.2.0
-=========================================================
-
-* Product Page: https://www.creative-tim.com/product/material-dashboard-react
-* Copyright 2023 Creative Tim (https://www.creative-tim.com)
-
-Coded by www.creative-tim.com
-
- =========================================================
-
-* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-*/
-
-// Images
-import kal from "assets/images/kal-visuals-square.jpg";
-import marie from "assets/images/marie.jpg";
-import ivana from "assets/images/ivana-square.jpg";
-import team3 from "assets/images/team-3.jpg";
-import team4 from "assets/images/team-4.jpg";
-
-export default [
- {
- image: kal,
- name: "Sophie B.",
- description: "Hi! I need more information..",
- action: {
- type: "internal",
- route: "/pages/profile/profile-overview",
- color: "info",
- label: "reply",
- },
- },
- {
- image: marie,
- name: "Anne Marie",
- description: "Awesome work, can you..",
- action: {
- type: "internal",
- route: "/pages/profile/profile-overview",
- color: "info",
- label: "reply",
- },
- },
- {
- image: ivana,
- name: "Ivanna",
- description: "About files I can..",
- action: {
- type: "internal",
- route: "/pages/profile/profile-overview",
- color: "info",
- label: "reply",
- },
- },
- {
- image: team4,
- name: "Peterson",
- description: "Have a great afternoon..",
- action: {
- type: "internal",
- route: "/pages/profile/profile-overview",
- color: "info",
- label: "reply",
- },
- },
- {
- image: team3,
- name: "Nick Daniel",
- description: "Hi! I need more information..",
- action: {
- type: "internal",
- route: "/pages/profile/profile-overview",
- color: "info",
- label: "reply",
- },
- },
-];
diff --git a/src/layouts/profile/index.js b/src/layouts/profile/index.js
deleted file mode 100644
index f51f6108f..000000000
--- a/src/layouts/profile/index.js
+++ /dev/null
@@ -1,203 +0,0 @@
-/**
-=========================================================
-* Material Dashboard 2 React - v2.2.0
-=========================================================
-
-* Product Page: https://www.creative-tim.com/product/material-dashboard-react
-* Copyright 2023 Creative Tim (https://www.creative-tim.com)
-
-Coded by www.creative-tim.com
-
- =========================================================
-
-* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-*/
-
-// @mui material components
-import Grid from "@mui/material/Grid";
-import Divider from "@mui/material/Divider";
-
-// @mui icons
-import FacebookIcon from "@mui/icons-material/Facebook";
-import TwitterIcon from "@mui/icons-material/Twitter";
-import InstagramIcon from "@mui/icons-material/Instagram";
-
-// Material Dashboard 2 React components
-import MDBox from "components/MDBox";
-import MDTypography from "components/MDTypography";
-
-// Material Dashboard 2 React example components
-import DashboardLayout from "examples/LayoutContainers/DashboardLayout";
-import DashboardNavbar from "examples/Navbars/DashboardNavbar";
-import Footer from "examples/Footer";
-import ProfileInfoCard from "examples/Cards/InfoCards/ProfileInfoCard";
-import ProfilesList from "examples/Lists/ProfilesList";
-import DefaultProjectCard from "examples/Cards/ProjectCards/DefaultProjectCard";
-
-// Overview page components
-import Header from "layouts/profile/components/Header";
-import PlatformSettings from "layouts/profile/components/PlatformSettings";
-
-// Data
-import profilesListData from "layouts/profile/data/profilesListData";
-
-// Images
-import homeDecor1 from "assets/images/home-decor-1.jpg";
-import homeDecor2 from "assets/images/home-decor-2.jpg";
-import homeDecor3 from "assets/images/home-decor-3.jpg";
-import homeDecor4 from "assets/images/home-decor-4.jpeg";
-import team1 from "assets/images/team-1.jpg";
-import team2 from "assets/images/team-2.jpg";
-import team3 from "assets/images/team-3.jpg";
-import team4 from "assets/images/team-4.jpg";
-
-function Overview() {
- return (
-
-
-
-
-
-
-
-
-
-
-
- ,
- color: "facebook",
- },
- {
- link: "https://twitter.com/creativetim",
- icon: ,
- color: "twitter",
- },
- {
- link: "https://www.instagram.com/creativetimofficial/",
- icon: ,
- color: "instagram",
- },
- ]}
- action={{ route: "", tooltip: "Edit Profile" }}
- shadow={false}
- />
-
-
-
-
-
-
-
-
-
- Projects
-
-
-
- Architects design houses
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
-
-export default Overview;
diff --git a/src/layouts/sale-form/SaleForm.jsx b/src/layouts/sale-form/SaleForm.jsx
new file mode 100644
index 000000000..a2673a914
--- /dev/null
+++ b/src/layouts/sale-form/SaleForm.jsx
@@ -0,0 +1,109 @@
+import "./styles.css";
+import "../../shared/styles/GeneralStyles.css";
+
+function SaleForm({ saleSelected, formFieldChange, fetchClients, clientsList }) {
+
+ const handleChange = (event) => {
+ const name = event.target.name;
+ const value = event.target.value;
+ formFieldChange(value, name);
+ switch (name) {
+ case 'taxIdSearch':
+ fetchClients({ tax_id: value });
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ const foundClientsList = () => {
+ return (
+ <>
+ {/* {
+ clientsList?.map(client => {
+
+ })
+ } */}
+ >
+ );
+ }
+
+ return (
+ <>
+
+ >
+ )
+}
+
+export default SaleForm
\ No newline at end of file
diff --git a/src/layouts/sale-form/index.js b/src/layouts/sale-form/index.js
new file mode 100644
index 000000000..f9d8d36cf
--- /dev/null
+++ b/src/layouts/sale-form/index.js
@@ -0,0 +1,7 @@
+import SaleForm from "./SaleForm";
+
+const ConnectedSaleForm = (props) => {
+ return ()
+}
+
+export default ConnectedSaleForm;
\ No newline at end of file
diff --git a/src/layouts/sale-form/styles.css b/src/layouts/sale-form/styles.css
new file mode 100644
index 000000000..b013e48a7
--- /dev/null
+++ b/src/layouts/sale-form/styles.css
@@ -0,0 +1,5 @@
+.divForm {
+ display: flex;
+ width: 100%;
+ justify-content: center;
+}
\ No newline at end of file
diff --git a/src/layouts/profile/components/Header/index.js b/src/layouts/sales/components/Header/index.js
similarity index 69%
rename from src/layouts/profile/components/Header/index.js
rename to src/layouts/sales/components/Header/index.js
index e11541efc..34188cbf3 100644
--- a/src/layouts/profile/components/Header/index.js
+++ b/src/layouts/sales/components/Header/index.js
@@ -21,10 +21,6 @@ import PropTypes from "prop-types";
// @mui material components
import Card from "@mui/material/Card";
import Grid from "@mui/material/Grid";
-import AppBar from "@mui/material/AppBar";
-import Tabs from "@mui/material/Tabs";
-import Tab from "@mui/material/Tab";
-import Icon from "@mui/material/Icon";
// Material Dashboard 2 React components
import MDBox from "components/MDBox";
@@ -35,12 +31,11 @@ import MDAvatar from "components/MDAvatar";
import breakpoints from "assets/theme/base/breakpoints";
// Images
-import burceMars from "assets/images/bruce-mars.jpg";
+import smallStore from "assets/images/small-store.jpeg";
import backgroundImage from "assets/images/bg-profile.jpeg";
function Header({ children }) {
const [tabsOrientation, setTabsOrientation] = useState("horizontal");
- const [tabValue, setTabValue] = useState(0);
useEffect(() => {
// A function that sets the orientation state of the tabs.
@@ -62,8 +57,6 @@ function Header({ children }) {
return () => window.removeEventListener("resize", handleTabsOrientation);
}, [tabsOrientation]);
- const handleSetTabValue = (event, newValue) => setTabValue(newValue);
-
return (
-
+
- Richard Davis
+ Ingresa una nueva venta
- CEO / Co-Founder
+ Selecciona artículos y una cantidad
-
-
-
-
- home
-
- }
- />
-
- email
-
- }
- />
-
- settings
-
- }
- />
-
-
-
{children}
diff --git a/src/layouts/sales/index.js b/src/layouts/sales/index.js
new file mode 100644
index 000000000..daa6eb88b
--- /dev/null
+++ b/src/layouts/sales/index.js
@@ -0,0 +1,48 @@
+/**
+=========================================================
+* Material Dashboard 2 React - v2.2.0
+=========================================================
+
+* Product Page: https://www.creative-tim.com/product/material-dashboard-react
+* Copyright 2023 Creative Tim (https://www.creative-tim.com)
+
+Coded by www.creative-tim.com
+
+ =========================================================
+
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+*/
+
+// @mui material components
+import Grid from "@mui/material/Grid";
+
+// Material Dashboard 2 React components
+import MDBox from "components/MDBox";
+
+// Material Dashboard 2 React example components
+import DashboardLayout from "examples/LayoutContainers/DashboardLayout";
+import DashboardNavbar from "examples/Navbars/DashboardNavbar";
+
+// Overview page components
+import Header from "layouts/sales/components/Header";
+import Footer from "examples/Footer";
+import CreateSale from "layouts/create-sale";
+
+function Overview() {
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default Overview;
diff --git a/src/routes.js b/src/routes.js
index a17b439ad..d2f984bd6 100644
--- a/src/routes.js
+++ b/src/routes.js
@@ -38,16 +38,17 @@ Coded by www.creative-tim.com
// Material Dashboard 2 React layouts
import Dashboard from "layouts/dashboard";
import Tables from "layouts/tables";
-import Billing from "layouts/billing";
+import Sales from "layouts/sales";
+/* import Billing from "layouts/billing";
import RTL from "layouts/rtl";
import Notifications from "layouts/notifications";
-import Profile from "layouts/profile";
import SignIn from "layouts/authentication/sign-in";
-import SignUp from "layouts/authentication/sign-up";
+import SignUp from "layouts/authentication/sign-up"; */
// @mui icons
import Icon from "@mui/material/Icon";
+//! CHECK THIS OUT
const routes = [
{
type: "collapse",
@@ -65,7 +66,7 @@ const routes = [
route: "/tables",
component: ,
},
- {
+ /* {
type: "collapse",
name: "Billing",
key: "billing",
@@ -88,16 +89,16 @@ const routes = [
icon: notifications,
route: "/notifications",
component: ,
- },
+ }, */
{
type: "collapse",
- name: "Profile",
- key: "profile",
- icon: person,
- route: "/profile",
- component: ,
+ name: "Sales",
+ key: "sales",
+ icon: store,
+ route: "/sales",
+ component: ,
},
- {
+ /* {
type: "collapse",
name: "Sign In",
key: "sign-in",
@@ -112,7 +113,7 @@ const routes = [
icon: assignment,
route: "/authentication/sign-up",
component: ,
- },
+ }, */
];
export default routes;
diff --git a/src/services/clients.js b/src/services/clients.js
new file mode 100644
index 000000000..efb846ff5
--- /dev/null
+++ b/src/services/clients.js
@@ -0,0 +1,93 @@
+import axios from 'axios';
+
+let clientsList = [
+ {
+ id: '4578C26',
+ img: '',
+ title: 'Constantine',
+ language: 'Inglés',
+ costPerNight: 25,
+ costToBuy: 115,
+ },
+ {
+ id: '9975F28',
+ img: '',
+ title: '50 First Dates',
+ language: 'Inglés',
+ costPerNight: 20,
+ costToBuy: 125,
+ },
+ {
+ id: '5671FMF1',
+ img: '',
+ title: 'Fantastic Mr. Fox',
+ language: 'Inglés',
+ costPerNight: 35,
+ costToBuy: 150,
+ },
+];
+
+const getClients = async (filter = undefined) => {
+ let url = 'http://localhost:3000/api/clients';
+ if (filter) {
+ url += `?${encodeToQueryString(filter)}`
+ }
+ const data = await axios.get(url);
+ return { data: clientsList, data };
+}
+
+const deleteClient = async (id) => {
+ //return await axios.delete('http://localhost:3000/movies/' + id);
+ const filteredClients = clientsList.filter(client => client.id !== id);
+ clientsList = filteredClients;
+ return true;
+}
+
+const updateClients = async (id, data) => {
+ //return await axios.patch('http://localhost:3000/movies/' + id, data);
+ const clientIndex = clientsList.findIndex(client => client.id === id);
+ const clientsListToEdit = [...clientsList];
+ clientsListToEdit[clientIndex] = {
+ ...clientsList[clientIndex],
+ ...data,
+ };
+ clientsList = clientsListToEdit;
+ return true;
+}
+
+const addClient = async (data) => {
+ //return await axios.post('http://localhost:3000/movies/', data);
+ const clientsListToAdd = [...clientsList];
+ clientsListToAdd.push({
+ id: clientsList.length + 1,
+ ...data,
+ });
+ clientsList = clientsListToAdd;
+ return true;
+}
+
+const getClientById = async (id) => {
+ //return await axios.get('http://localhost:3000/movies/' + id);
+ const clientIndex = clientsList.findIndex(client => client.id === id);
+ return { data: clientsList[clientIndex] };
+}
+
+const encodeToQueryString = (params) => {
+ return Object.entries(params)
+ .map(([key, value]) => {
+ if (Array.isArray(value)) {
+ return value.map(val => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`).join('&');
+ } else {
+ return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
+ }
+ })
+ .join('&');
+};
+
+export default {
+ getClients,
+ deleteClient,
+ updateClients,
+ addClient,
+ getClientById,
+}
\ No newline at end of file
diff --git a/src/services/index.js b/src/services/index.js
new file mode 100644
index 000000000..0726cc84b
--- /dev/null
+++ b/src/services/index.js
@@ -0,0 +1,7 @@
+import Sales from './sales';
+import Clients from './clients';
+
+export default {
+ Sales,
+ Clients
+}
\ No newline at end of file
diff --git a/src/services/sales.js b/src/services/sales.js
new file mode 100644
index 000000000..ac95f4e53
--- /dev/null
+++ b/src/services/sales.js
@@ -0,0 +1,77 @@
+import axios from 'axios';
+
+let salesList = [
+ {
+ id: '4578C26',
+ img: '',
+ title: 'Constantine',
+ language: 'Inglés',
+ costPerNight: 25,
+ costToBuy: 115,
+ },
+ {
+ id: '9975F28',
+ img: '',
+ title: '50 First Dates',
+ language: 'Inglés',
+ costPerNight: 20,
+ costToBuy: 125,
+ },
+ {
+ id: '5671FMF1',
+ img: '',
+ title: 'Fantastic Mr. Fox',
+ language: 'Inglés',
+ costPerNight: 35,
+ costToBuy: 150,
+ },
+];
+
+const getSales = async () => {
+ //return await axios.get('http://localhost:3001/movies');
+ return { data: salesList };
+}
+
+const deleteSale = async (id) => {
+ //return await axios.delete('http://localhost:3001/movies/' + id);
+ const filteredSales = salesList.filter(sale => sale.id !== id);
+ salesList = filteredSales;
+ return true;
+}
+
+const updateSales = async (id, data) => {
+ //return await axios.patch('http://localhost:3001/movies/' + id, data);
+ const saleIndex = salesList.findIndex(sale => sale.id === id);
+ const salesListToEdit = [...salesList];
+ salesListToEdit[saleIndex] = {
+ ...salesList[saleIndex],
+ ...data,
+ };
+ salesList = salesListToEdit;
+ return true;
+}
+
+const addSale = async (data) => {
+ //return await axios.post('http://localhost:3001/movies/', data);
+ const salesListToAdd = [...salesList];
+ salesListToAdd.push({
+ id: salesList.length + 1,
+ ...data,
+ });
+ salesList = salesListToAdd;
+ return true;
+}
+
+const getSaleById = async (id) => {
+ //return await axios.get('http://localhost:3001/movies/' + id);
+ const saleIndex = salesList.findIndex(sale => sale.id === id);
+ return { data: salesList[saleIndex] };
+}
+
+export default {
+ getSales,
+ deleteSale,
+ updateSales,
+ addSale,
+ getSaleById,
+}
\ No newline at end of file
diff --git a/src/shared/components/button/Button.jsx b/src/shared/components/button/Button.jsx
new file mode 100644
index 000000000..097601916
--- /dev/null
+++ b/src/shared/components/button/Button.jsx
@@ -0,0 +1,24 @@
+import btnStyles from "./styles.module.css";
+import cx from "classnames";
+
+function GeneralButton({ buttonText, actionOnSubmit, data, keysArray, buttonClasses, primary }) {
+
+ const handleOnClick = (e) => {
+ e.preventDefault();
+ const paramsArr = keysArray.map(key => data[key]);
+ actionOnSubmit(...paramsArr);
+ }
+
+ const actualBtnClasses = [btnStyles.btn];
+ buttonClasses && actualBtnClasses.push(buttonClasses);
+
+ return (
+ <>
+
+ >
+ )
+}
+
+export default GeneralButton
\ No newline at end of file
diff --git a/src/shared/components/button/index.js b/src/shared/components/button/index.js
new file mode 100644
index 000000000..45ecb68bc
--- /dev/null
+++ b/src/shared/components/button/index.js
@@ -0,0 +1,7 @@
+import GeneralButton from "./Button";
+
+const ConnectedGeneralButton = (props) => {
+ return ()
+}
+
+export default ConnectedGeneralButton;
\ No newline at end of file
diff --git a/src/shared/components/button/styles.module.css b/src/shared/components/button/styles.module.css
new file mode 100644
index 000000000..ca842f86c
--- /dev/null
+++ b/src/shared/components/button/styles.module.css
@@ -0,0 +1,13 @@
+.btn {
+ border: none;
+ padding: 10px;
+ padding-inline: 20px;
+ border-radius: 8px;
+ font-weight: 600;
+ cursor: pointer;
+}
+
+.primary {
+ background: #6495ed;
+ color: #fff;
+}
\ No newline at end of file
diff --git a/src/shared/styles/GeneralStyles.css b/src/shared/styles/GeneralStyles.css
new file mode 100644
index 000000000..c4cd243ee
--- /dev/null
+++ b/src/shared/styles/GeneralStyles.css
@@ -0,0 +1,36 @@
+.mb-15 {
+ margin-bottom: 15px !important;
+}
+
+.mr-10 {
+ margin-right: 10px !important;
+}
+
+.mb-10 {
+ margin-bottom: 10px !important;
+}
+
+.btn-primary {
+ background: #6495ed;
+ color: #fff;
+}
+
+.btn-secondary {
+ background: #f5a207;
+ color: #fff;
+}
+
+.btn-accent {
+ background: #20b00d;
+ color: #fff;
+}
+
+.btn-danger {
+ background: #c40a0a;
+ color: #fff;
+}
+
+.btn-basic-danger {
+ background: #fff;
+ color: #c40a0a;
+}
\ No newline at end of file
diff --git a/src/store/clients/actions/actionType.js b/src/store/clients/actions/actionType.js
new file mode 100644
index 000000000..fcd5b8690
--- /dev/null
+++ b/src/store/clients/actions/actionType.js
@@ -0,0 +1,15 @@
+const ADD_CLIENT = 'ADD_CLIENT';
+const DELETE_CLIENT = 'DELETE_CLIENT';
+const GET_CLIENTS = 'GET_CLIENTS';
+const GET_CLIENT_BY_ID = 'GET_ONE_CLIENT';
+const UPDATE_FIELD = 'UPDATE_FIELD';
+const SELECT_CLIENT = 'SELECT_CLIENT';
+
+export default {
+ ADD_CLIENT,
+ DELETE_CLIENT,
+ GET_CLIENTS,
+ GET_CLIENT_BY_ID,
+ UPDATE_FIELD,
+ SELECT_CLIENT,
+}
\ No newline at end of file
diff --git a/src/store/clients/actions/index.js b/src/store/clients/actions/index.js
new file mode 100644
index 000000000..0725ff745
--- /dev/null
+++ b/src/store/clients/actions/index.js
@@ -0,0 +1,18 @@
+import { createAction } from "@reduxjs/toolkit";
+import actionType from "./actionType";
+
+const addClient = createAction(actionType.ADD_CLIENT);
+const deleteClient = createAction(actionType.DELETE_CLIENT);
+const getClients = createAction(actionType.GET_CLIENTS);
+const getClientById = createAction(actionType.GET_CLIENT_BY_ID);
+const updateField = createAction(actionType.UPDATE_FIELD);
+const selectClient = createAction(actionType.SELECT_CLIENT);
+
+export default {
+ addClient,
+ deleteClient,
+ getClients,
+ getClientById,
+ updateField,
+ selectClient,
+}
\ No newline at end of file
diff --git a/src/store/clients/commands/index.js b/src/store/clients/commands/index.js
new file mode 100644
index 000000000..f47d41863
--- /dev/null
+++ b/src/store/clients/commands/index.js
@@ -0,0 +1,56 @@
+import ClientActions from '../actions';
+import api from '../../../services';
+
+const getClients = (filter) => (dispatch, getState) => {
+ api.Clients.getClients(filter).then(response => {
+ dispatch(ClientActions.getClients(response.data));
+ });
+}
+
+const getClientById = (id) => (dispatch, getState) => {
+ api.Clients.getClientById(id).then(response => {
+ dispatch(ClientActions.getClientById(response.data));
+ })
+}
+
+const addClient = data => (dispatch, getState) => {
+ api.Clients.addClient(data).then(response => {
+ dispatch(getClients());
+ })
+}
+
+const deleteClient = id => (dispatch, getState) => {
+ api.Clients.deleteClient(id).then(response => {
+ dispatch(getClients());
+ });
+}
+
+const updateClient = (id, data) => (dispatch, getState) => {
+ api.Clients.updateClient(id, data).then(response => {
+ dispatch(getClients());
+ })
+}
+
+const selectClient = (id) => (dispatch, getState) => {
+ dispatch(ClientActions.getClientById(id));
+}
+
+const clearSelectedClient = () => (dispatch, getState) => {
+ dispatch(ClientActions.getClientById({}));
+}
+
+const updateField = (value, field) => (dispatch) => {
+ const data = { value, field };
+ dispatch(ClientActions.updateField(data));
+}
+
+export default {
+ addClient,
+ deleteClient,
+ getClients,
+ updateClient,
+ getClientById,
+ updateField,
+ selectClient,
+ clearSelectedClient,
+}
\ No newline at end of file
diff --git a/src/store/clients/reducers/index.js b/src/store/clients/reducers/index.js
new file mode 100644
index 000000000..512d70369
--- /dev/null
+++ b/src/store/clients/reducers/index.js
@@ -0,0 +1,29 @@
+import { createReducer } from "@reduxjs/toolkit";
+import actionType from "../actions";
+
+const initialState = {
+ list: [],
+ clientSelected: {},
+};
+
+const reducer = createReducer(initialState, (builder) => {
+ builder
+ .addCase(actionType.getClients, (state, action) => {
+ state.list = action.payload;
+ })
+ .addCase(actionType.addClient, (state, action) => {
+ state.list = action.payload;
+ })
+ .addCase(actionType.deleteClient, (state, action) => {
+ state.list = action.payload;
+ })
+ .addCase(actionType.getClientById, (state, action) => {
+ state.clientSelected = action.payload;
+ })
+ .addCase(actionType.updateField, (state, action) => {
+ const { value, field } = action.payload
+ state.clientSelected[field] = value;
+ })
+});
+
+export default reducer;
\ No newline at end of file
diff --git a/src/store/clients/selectors/index.js b/src/store/clients/selectors/index.js
new file mode 100644
index 000000000..785a34f76
--- /dev/null
+++ b/src/store/clients/selectors/index.js
@@ -0,0 +1,11 @@
+import { createSelector } from "@reduxjs/toolkit";
+
+const selectSelf = (state) => state.clients;
+
+const currentClients = createSelector(selectSelf, (state) => state.list);
+const currentClientSelected = createSelector(selectSelf, (state)=> state.clientSelected);
+
+export default {
+ currentClients,
+ currentClientSelected,
+}
\ No newline at end of file
diff --git a/src/store/index.js b/src/store/index.js
new file mode 100644
index 000000000..335abc8cf
--- /dev/null
+++ b/src/store/index.js
@@ -0,0 +1,8 @@
+import { configureStore } from "@reduxjs/toolkit";
+import rootReducer from "./reducers";
+
+const store = configureStore({
+ reducer: rootReducer
+});
+
+export default store;
\ No newline at end of file
diff --git a/src/store/reducers.js b/src/store/reducers.js
new file mode 100644
index 000000000..71835f992
--- /dev/null
+++ b/src/store/reducers.js
@@ -0,0 +1,9 @@
+import { combineReducers } from "redux";
+import salesReducer from './sales/reducers'
+import clientsReducer from './clients/reducers'
+
+const combinedReducers = combineReducers({
+ sales: salesReducer,
+ clients: clientsReducer
+ });
+export default combinedReducers;
\ No newline at end of file
diff --git a/src/store/sales/actions/actionType.js b/src/store/sales/actions/actionType.js
new file mode 100644
index 000000000..5fc5b85cf
--- /dev/null
+++ b/src/store/sales/actions/actionType.js
@@ -0,0 +1,15 @@
+const ADD_SALE = 'ADD_SALE';
+const DELETE_SALE = 'DELETE_SALE';
+const GET_SALES = 'GET_SALES';
+const GET_SALE_BY_ID = 'GET_ONE_SALE';
+const UPDATE_FIELD = 'UPDATE_FIELD';
+const SELECT_SALE = 'SELECT_SALE';
+
+export default {
+ ADD_SALE,
+ DELETE_SALE,
+ GET_SALES,
+ GET_SALE_BY_ID,
+ UPDATE_FIELD,
+ SELECT_SALE,
+}
\ No newline at end of file
diff --git a/src/store/sales/actions/index.js b/src/store/sales/actions/index.js
new file mode 100644
index 000000000..b3bb6d596
--- /dev/null
+++ b/src/store/sales/actions/index.js
@@ -0,0 +1,18 @@
+import { createAction } from "@reduxjs/toolkit";
+import actionType from "./actionType";
+
+const addSale = createAction(actionType.ADD_SALE);
+const deleteSale = createAction(actionType.DELETE_SALE);
+const getSales = createAction(actionType.GET_SALES);
+const getSaleById = createAction(actionType.GET_SALE_BY_ID);
+const updateField = createAction(actionType.UPDATE_FIELD);
+const selectSale = createAction(actionType.SELECT_SALE);
+
+export default {
+ addSale,
+ deleteSale,
+ getSales,
+ getSaleById,
+ updateField,
+ selectSale,
+}
\ No newline at end of file
diff --git a/src/store/sales/commands/index.js b/src/store/sales/commands/index.js
new file mode 100644
index 000000000..45b463bcc
--- /dev/null
+++ b/src/store/sales/commands/index.js
@@ -0,0 +1,56 @@
+import SaleActions from '../actions';
+import api from '../../../services';
+
+const getSales = () => (dispatch, getState) => {
+ api.Sales.getSales().then(response => {
+ dispatch(SaleActions.getSales(response.data));
+ });
+}
+
+const getSaleById = (id) => (dispatch, getState) => {
+ api.Sales.getSaleById(id).then(response => {
+ dispatch(SaleActions.getSaleById(response.data));
+ })
+}
+
+const addSale = data => (dispatch, getState) => {
+ api.Sales.addSale(data).then(response => {
+ dispatch(getSales());
+ })
+}
+
+const deleteSale = id => (dispatch, getState) => {
+ api.Sales.deleteSale(id).then(response => {
+ dispatch(getSales());
+ });
+}
+
+const updateSale = (id, data) => (dispatch, getState) => {
+ api.Sales.updateSale(id, data).then(response => {
+ dispatch(getSales());
+ })
+}
+
+const selectSale = (id) => (dispatch, getState) => {
+ dispatch(SaleActions.getSaleById(id));
+}
+
+const clearSelectedSale = () => (dispatch, getState) => {
+ dispatch(SaleActions.getSaleById({}));
+}
+
+const updateField = (value, field) => (dispatch) => {
+ const data = { value, field };
+ dispatch(SaleActions.updateField(data));
+}
+
+export default {
+ addSale,
+ deleteSale,
+ getSales,
+ updateSale,
+ getSaleById,
+ updateField,
+ selectSale,
+ clearSelectedSale,
+}
\ No newline at end of file
diff --git a/src/store/sales/reducers/index.js b/src/store/sales/reducers/index.js
new file mode 100644
index 000000000..b44dd38df
--- /dev/null
+++ b/src/store/sales/reducers/index.js
@@ -0,0 +1,29 @@
+import { createReducer } from "@reduxjs/toolkit";
+import actionType from "../actions";
+
+const initialState = {
+ list: [],
+ saleSelected: {},
+};
+
+const reducer = createReducer(initialState, (builder) => {
+ builder
+ .addCase(actionType.getSales, (state, action) => {
+ state.list = action.payload;
+ })
+ .addCase(actionType.addSale, (state, action) => {
+ state.list = action.payload;
+ })
+ .addCase(actionType.deleteSale, (state, action) => {
+ state.list = action.payload;
+ })
+ .addCase(actionType.getSaleById, (state, action) => {
+ state.saleSelected = action.payload;
+ })
+ .addCase(actionType.updateField, (state, action) => {
+ const { value, field } = action.payload
+ state.saleSelected[field] = value;
+ })
+});
+
+export default reducer;
\ No newline at end of file
diff --git a/src/store/sales/selectors/index.js b/src/store/sales/selectors/index.js
new file mode 100644
index 000000000..1bfa5aed1
--- /dev/null
+++ b/src/store/sales/selectors/index.js
@@ -0,0 +1,11 @@
+import { createSelector } from "@reduxjs/toolkit";
+
+const selectSelf = (state) => state.sales;
+
+const currentSales = createSelector(selectSelf, (state) => state.list);
+const currentSaleSelected = createSelector(selectSelf, (state)=> state.saleSelected);
+
+export default {
+ currentSales,
+ currentSaleSelected,
+}
\ No newline at end of file
diff --git a/src/utils/encode-to-query-string.util.ts b/src/utils/encode-to-query-string.util.ts
new file mode 100644
index 000000000..ae81b9bc2
--- /dev/null
+++ b/src/utils/encode-to-query-string.util.ts
@@ -0,0 +1,11 @@
+export const encodeToQueryString = (params: Record): string => {
+ return Object.entries(params)
+ .map(([key, value]) => {
+ if (Array.isArray(value)) {
+ return value.map(val => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`).join('&');
+ } else {
+ return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
+ }
+ })
+ .join('&');
+};
\ No newline at end of file