Added new files for API services and common components.
This commit is contained in:
parent
caf8d4abc0
commit
261cf4cfbd
216
db.json
216
db.json
@ -11,6 +11,12 @@
|
|||||||
"email": "employee@gmail.com",
|
"email": "employee@gmail.com",
|
||||||
"password": "123",
|
"password": "123",
|
||||||
"role": "employee"
|
"role": "employee"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "de4c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5996"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"health-check": {
|
"health-check": {
|
||||||
@ -19,57 +25,61 @@
|
|||||||
"admin": [
|
"admin": [
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "1",
|
||||||
"name": "Admin User",
|
"firstname": "Admin User",
|
||||||
|
"lastname": "last ",
|
||||||
"email": "adminuser@example.com"
|
"email": "adminuser@example.com"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"employees": [
|
"employees": [
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "1",
|
||||||
"name": "Employee User",
|
"firstname": "Employee User",
|
||||||
|
"lastname": "last ",
|
||||||
"email": "employeeuser@example.com"
|
"email": "employeeuser@example.com"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "8d54",
|
"id": "6b21",
|
||||||
"firstname": "first",
|
"firstname": "suraj",
|
||||||
"lastname": "last",
|
"lastname": "birewar",
|
||||||
"age": "12",
|
"email": "surajbirewar001@gmail.com"
|
||||||
"gender": "male",
|
|
||||||
"email": "firstlast001@gmail.com",
|
|
||||||
"address_line_1": " Bavdhan, Pune",
|
|
||||||
"address_line_2": "LOCAL :,Bavdhan",
|
|
||||||
"nearby_landmark": "sbi bank",
|
|
||||||
"pincode": "411021",
|
|
||||||
"city_id": "",
|
|
||||||
"mobile": "07559393995"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "0828",
|
"id": "d010",
|
||||||
"firstname": "rahul",
|
"firstname": "gajanan",
|
||||||
"lastname": "patil",
|
"lastname": "bodke",
|
||||||
"age": "22",
|
"email": "gajanan001@gmail.com"
|
||||||
"gender": "male",
|
|
||||||
"email": "rahul@gmail.com",
|
|
||||||
"address_line_1": " Bavdhan, Pune",
|
|
||||||
"address_line_2": "LOCAL :,Bavdhan",
|
|
||||||
"nearby_landmark": "sbi bank",
|
|
||||||
"pincode": "411021",
|
|
||||||
"city_id": "",
|
|
||||||
"mobile": "07559393995"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"products": [
|
"products": [
|
||||||
{
|
{
|
||||||
"id": "1",
|
"ID": "1",
|
||||||
"name": "Product 1",
|
"name": "Men's T-Shirt",
|
||||||
"category": "Category 1",
|
"sku": "TS-MEN-001-BL-XL",
|
||||||
"price": 100
|
"short_description": "A comfortable men's clothing fibers",
|
||||||
|
"long_description": "This men's shirt is made from 100% cotton, providing a soft and comfortable feel. Perfect for casual wear.",
|
||||||
|
"thumbnail_url": "https://example.com/men-tshirt.jpg",
|
||||||
|
"category_id": "101",
|
||||||
|
"id": "d6ce"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "2",
|
"ID": "2",
|
||||||
"name": "Product 2",
|
"name": "Women's Jacket",
|
||||||
"category": "Category 2",
|
"sku": "JK-WOM-001-RE-M",
|
||||||
"price": 200
|
"short_description": "Stylish women's jacket",
|
||||||
|
"long_description": "A trendy women's jacket, perfect for chilly weather. Made with high-quality materials to ensure warmth and comfort.",
|
||||||
|
"thumbnail_url": "https://example.com/women-jacket.jpg",
|
||||||
|
"category_id": "102",
|
||||||
|
"id": "60db"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "3",
|
||||||
|
"name": "Unisex Sneakers",
|
||||||
|
"sku": "SN-UNI-001-WH-42",
|
||||||
|
"short_description": "Comfortable unisex tuxiods",
|
||||||
|
"long_description": "These unisex tuxidos are designed for comfort and style. Ideal for everyday wear.",
|
||||||
|
"thumbnail_url": "https://example.com/tuxidos.jpg",
|
||||||
|
"category_id": "103",
|
||||||
|
"id": "7228"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"categories": [
|
"categories": [
|
||||||
@ -85,85 +95,17 @@
|
|||||||
"customers": [
|
"customers": [
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "1",
|
||||||
"name": "Customer 1",
|
"firstname": "vitthal",
|
||||||
|
"lastname": "patil",
|
||||||
"email": "customer1@example.com",
|
"email": "customer1@example.com",
|
||||||
"phone": "1234567890"
|
"phone": "1234567890"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "2",
|
"id": "2",
|
||||||
"name": "Customer 2",
|
"firstname": "rushi",
|
||||||
|
"lastname": "shelke",
|
||||||
"email": "customer2@example.com",
|
"email": "customer2@example.com",
|
||||||
"phone": "0987654321"
|
"phone": "0987654321"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Suraj Birewar",
|
|
||||||
"age": "24",
|
|
||||||
"gender": "Male",
|
|
||||||
"email": "surajbirewar001@gmail.com",
|
|
||||||
"address": "Bavdhan, Pune",
|
|
||||||
"mobile": "07559393995",
|
|
||||||
"id": "3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "rahul",
|
|
||||||
"age": "21",
|
|
||||||
"gender": "male",
|
|
||||||
"email": "rahul001@gmail.com",
|
|
||||||
"address": "Bavdhan, Pune",
|
|
||||||
"mobile": "7559393995",
|
|
||||||
"id": "4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "atharv",
|
|
||||||
"age": "19",
|
|
||||||
"gender": "male",
|
|
||||||
"email": "atharv@gmail.com",
|
|
||||||
"address": "baner pune ",
|
|
||||||
"mobile": "784365873",
|
|
||||||
"id": "5"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "3682",
|
|
||||||
"name": "dikshant",
|
|
||||||
"age": "23",
|
|
||||||
"gender": "male",
|
|
||||||
"email": "dikshant001@gmail.com",
|
|
||||||
"address": "Bavdhan, Pune",
|
|
||||||
"mobile": "45654665645"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "377d",
|
|
||||||
"firstname": "tejas",
|
|
||||||
"lastname": "chari",
|
|
||||||
"age": "28",
|
|
||||||
"gender": "male",
|
|
||||||
"email": "tejas001@gmail.com",
|
|
||||||
"address": " Baner, Pune",
|
|
||||||
"mobile": "8675493099"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "e539",
|
|
||||||
"firstname": "aaaa",
|
|
||||||
"lastname": "bbbb",
|
|
||||||
"age": "25",
|
|
||||||
"gender": "male",
|
|
||||||
"email": "aaaa@gmail.com",
|
|
||||||
"address": "pune",
|
|
||||||
"mobile": "7559393995"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "88a4",
|
|
||||||
"firstname": "first",
|
|
||||||
"lastname": "last",
|
|
||||||
"age": "8",
|
|
||||||
"gender": "male",
|
|
||||||
"email": "firstlast001@gmail.com",
|
|
||||||
"address_line_1": "Bavdhan, Pune",
|
|
||||||
"address_line_2": "LOCAL :,Bavdhan",
|
|
||||||
"nearby_landmark": "sbi bank",
|
|
||||||
"pincode": "411021",
|
|
||||||
"city_id": "",
|
|
||||||
"mobile": "07559393995"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"cities": [
|
"cities": [
|
||||||
@ -186,6 +128,66 @@
|
|||||||
{
|
{
|
||||||
"id": "5",
|
"id": "5",
|
||||||
"name": "Phoenix"
|
"name": "Phoenix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "333e",
|
||||||
|
"name": "las vegas"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"ID": "1",
|
||||||
|
"Email": "adminuser@example.com",
|
||||||
|
"Roles": [
|
||||||
|
"admin"
|
||||||
|
],
|
||||||
|
"Profile": {
|
||||||
|
"ID": "p1",
|
||||||
|
"FirstName": "Admin",
|
||||||
|
"LastName": "User",
|
||||||
|
"Phone": "1234567890",
|
||||||
|
"Age": 35,
|
||||||
|
"Gender": "MALE"
|
||||||
|
},
|
||||||
|
"CreatedAt": "2023-01-01T10:00:00Z",
|
||||||
|
"UpdatedAt": "2023-01-01T12:00:00Z",
|
||||||
|
"id": "2506"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "2",
|
||||||
|
"Email": "employeeuser@example.com",
|
||||||
|
"Roles": [
|
||||||
|
"employee"
|
||||||
|
],
|
||||||
|
"Profile": {
|
||||||
|
"ID": "p2",
|
||||||
|
"FirstName": "Employee",
|
||||||
|
"LastName": "User",
|
||||||
|
"Phone": "0987654321",
|
||||||
|
"Age": 28,
|
||||||
|
"Gender": "MALE"
|
||||||
|
},
|
||||||
|
"CreatedAt": "2023-01-02T10:00:00Z",
|
||||||
|
"UpdatedAt": "2023-01-02T12:00:00Z",
|
||||||
|
"id": "bd52"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "3",
|
||||||
|
"Email": "newuser@example.com",
|
||||||
|
"Roles": [
|
||||||
|
"customer"
|
||||||
|
],
|
||||||
|
"Profile": {
|
||||||
|
"ID": "p3",
|
||||||
|
"FirstName": "New",
|
||||||
|
"LastName": "User",
|
||||||
|
"Phone": "1122334455",
|
||||||
|
"Age": 22,
|
||||||
|
"Gender": "FEMALE"
|
||||||
|
},
|
||||||
|
"CreatedAt": "2023-01-03T10:00:00Z",
|
||||||
|
"UpdatedAt": "2023-01-03T12:00:00Z",
|
||||||
|
"id": "eefd"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
3918
package-lock.json
generated
3918
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@ -20,6 +20,7 @@
|
|||||||
"@fortawesome/fontawesome-svg-core": "^6.6.0",
|
"@fortawesome/fontawesome-svg-core": "^6.6.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
||||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||||
|
"@pankod/refine-simple-rest": "^3.39.0",
|
||||||
"@refinedev/core": "^4.53.0",
|
"@refinedev/core": "^4.53.0",
|
||||||
"@refinedev/kbar": "^1.3.12",
|
"@refinedev/kbar": "^1.3.12",
|
||||||
"@refinedev/mui": "^5.19.0",
|
"@refinedev/mui": "^5.19.0",
|
||||||
@ -33,17 +34,27 @@
|
|||||||
"react-toastify": "^10.0.5"
|
"react-toastify": "^10.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@testing-library/jest-dom": "^6.4.8",
|
||||||
|
"@testing-library/react": "^16.0.0",
|
||||||
"@types/react": "^18.2.66",
|
"@types/react": "^18.2.66",
|
||||||
"@types/react-dom": "^18.2.22",
|
"@types/react-dom": "^18.2.22",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"autoprefixer": "^9.8.8",
|
"autoprefixer": "^9.8.8",
|
||||||
|
"axios-mock-adapter": "^1.22.0",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-react": "^7.34.1",
|
"eslint-plugin-react": "^7.34.1",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.6",
|
"eslint-plugin-react-refresh": "^0.4.6",
|
||||||
|
"jest": "^27.5.1",
|
||||||
"json-server": "^1.0.0-beta.1",
|
"json-server": "^1.0.0-beta.1",
|
||||||
"postcss": "^7.0.39",
|
"postcss": "^7.0.39",
|
||||||
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.17",
|
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.17",
|
||||||
"vite": "^5.3.4"
|
"vite": "^5.3.4"
|
||||||
|
},
|
||||||
|
"jest": {
|
||||||
|
"testEnvironment": "jsdom",
|
||||||
|
"moduleNameMapper": {
|
||||||
|
"\\.(css|less|scss|sass)$": "identity-obj-proxy"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import { RefineKbarProvider } from "@refinedev/kbar";
|
|||||||
import { ToastContainer, toast } from "react-toastify";
|
import { ToastContainer, toast } from "react-toastify";
|
||||||
import 'react-toastify/dist/ReactToastify.css';
|
import 'react-toastify/dist/ReactToastify.css';
|
||||||
|
|
||||||
|
|
||||||
const { Content } = Layout;
|
const { Content } = Layout;
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
const axiosInstance = axios.create({
|
const axiosInstance = axios.create({
|
||||||
baseURL: '/api',
|
baseURL: 'http://localhost:5000',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
axiosInstance.interceptors.request.use((config) => {
|
axiosInstance.interceptors.request.use((config) => {
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
if (token) {
|
if (token) {
|
||||||
config.headers.Authorization = `Bearer ${token}`;
|
config.headers['Authorization'] = `Bearer ${token}`;
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
}, (error) => {
|
|
||||||
return Promise.reject(error);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default axiosInstance;
|
export default axiosInstance;
|
||||||
|
34
src/api/employeeServices.js
Normal file
34
src/api/employeeServices.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import axiosInstance from './axiosConfig';
|
||||||
|
|
||||||
|
|
||||||
|
export const getEmployees = async () => {
|
||||||
|
const response = await axiosInstance.get('http://localhost:5000/employees');
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const getEmployeeById = async (id) => {
|
||||||
|
const response = await axiosInstance.get(`http://localhost:5000/employees/${id}`);
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const createEmployee = async (employeeData) => {
|
||||||
|
const response = await axiosInstance.post('http://localhost:5000/employees', employeeData, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const updateEmployee = async (id, updatedData) => {
|
||||||
|
const response = await axiosInstance.patch(`http://localhost:5000/employees/${id}`, updatedData);
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const deleteEmployee = async (id) => {
|
||||||
|
await axiosInstance.delete(`http://localhost:5000/employees/${id}`);
|
||||||
|
};
|
71
src/api/userService.test.js
Normal file
71
src/api/userService.test.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import axiosMock from 'axios';
|
||||||
|
import axiosInstance from './api/axiosConfig';
|
||||||
|
import {
|
||||||
|
getUsers,
|
||||||
|
getUserById,
|
||||||
|
createUser,
|
||||||
|
updateUser,
|
||||||
|
deleteUser,
|
||||||
|
} from './api/userService';
|
||||||
|
import MockAdapter from 'axios-mock-adapter';
|
||||||
|
|
||||||
|
|
||||||
|
const mock = new MockAdapter(axiosInstance);
|
||||||
|
|
||||||
|
describe('userService', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
|
||||||
|
mock.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fetch all users', async () => {
|
||||||
|
const users = [{ id: 1, name: 'John Doe' }, { id: 2, name: 'Jane Doe' }];
|
||||||
|
mock.onGet('http://localhost:5000/user').reply(200, users);
|
||||||
|
|
||||||
|
const result = await getUsers();
|
||||||
|
expect(result).toEqual(users);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fetch a user by ID', async () => {
|
||||||
|
const user = { id: 1, name: 'John Doe' };
|
||||||
|
mock.onGet('http://localhost:5000/user/1').reply(200, user);
|
||||||
|
|
||||||
|
const result = await getUserById(1);
|
||||||
|
expect(result).toEqual(user);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a new user', async () => {
|
||||||
|
const newUser = { name: 'John Doe' };
|
||||||
|
const createdUser = { id: 1, ...newUser };
|
||||||
|
mock.onPost('http://localhost:5000/user').reply(201, createdUser);
|
||||||
|
|
||||||
|
const result = await createUser(newUser);
|
||||||
|
expect(result).toEqual(createdUser);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update a user by ID', async () => {
|
||||||
|
const updatedData = { name: 'John Smith' };
|
||||||
|
const updatedUser = { id: 1, ...updatedData };
|
||||||
|
mock.onPatch('http://localhost:5000/user/1').reply(200, updatedUser);
|
||||||
|
|
||||||
|
const result = await updateUser(1, updatedData);
|
||||||
|
expect(result).toEqual(updatedUser);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete a user by ID', async () => {
|
||||||
|
mock.onDelete('http://localhost:5000/user/1').reply(200);
|
||||||
|
|
||||||
|
const result = await deleteUser(1);
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle errors correctly', async () => {
|
||||||
|
mock.onGet('http://localhost:5000/user').reply(500);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await getUsers();
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeTruthy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
52
src/api/userServices.js
Normal file
52
src/api/userServices.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import axiosInstance from '../api/axiosConfig';
|
||||||
|
|
||||||
|
export const getUsers = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.get('http://localhost:5000/user');
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching users:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getUserById = async (id) => {
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.get(`http://localhost:5000/user/${id}`);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error fetching user with ID ${id}:`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createUser = async (userData) => {
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.post('http://localhost:5000/user', userData);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating user:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateUser = async (id, updatedData) => {
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.patch(`http://localhost:5000/user/${id}`, updatedData);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error updating user with ID ${id}:`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteUser = async (id) => {
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.delete(`http://localhost:5000/user/${id}`);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error deleting user with ID ${id}:`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
@ -1,29 +1,87 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import axiosInstance from '../api/axiosInstance';
|
import { getUsers, createUser, updateUser, deleteUser } from '../api/userService';
|
||||||
|
|
||||||
const UsersList = () => {
|
const UserList = () => {
|
||||||
const [users, setUsers] = useState([]);
|
const [users, setUsers] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState(null);
|
||||||
|
const [newUser, setNewUser] = useState({ email: '', roles: '' });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
axiosInstance.get('/users')
|
const fetchUsers = async () => {
|
||||||
.then(response => {
|
try {
|
||||||
setUsers(response.data);
|
const userData = await getUsers();
|
||||||
})
|
setUsers(userData);
|
||||||
.catch(error => {
|
} catch (error) {
|
||||||
console.error('There was an error fetching the users!', error);
|
setError(error);
|
||||||
});
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchUsers();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleCreateUser = async () => {
|
||||||
|
try {
|
||||||
|
const createdUser = await createUser(newUser);
|
||||||
|
setUsers([...users, createdUser]);
|
||||||
|
setNewUser({ email: '', roles: '' });
|
||||||
|
} catch (error) {
|
||||||
|
setError(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUpdateUser = async (userId, updatedData) => {
|
||||||
|
try {
|
||||||
|
const updatedUser = await updateUser(userId, updatedData);
|
||||||
|
setUsers(users.map((user) => (user.ID === userId ? updatedUser : user)));
|
||||||
|
} catch (error) {
|
||||||
|
setError(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDeleteUser = async (userId) => {
|
||||||
|
try {
|
||||||
|
await deleteUser(userId);
|
||||||
|
setUsers(users.filter((user) => user.ID !== userId));
|
||||||
|
} catch (error) {
|
||||||
|
setError(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading) return <p>Loading...</p>;
|
||||||
|
if (error) return <p>Error loading users: {error.message}</p>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Users List</h1>
|
<h2>User List</h2>
|
||||||
<ul>
|
<ul>
|
||||||
{users.map(user => (
|
{users.map((user) => (
|
||||||
<li key={user.id}>{user.name}</li>
|
<li key={user.ID}>
|
||||||
|
{user.Email} - {user.Roles.join(', ')}
|
||||||
|
<button onClick={() => handleUpdateUser(user.ID, {/* Updated data */})}>Update</button>
|
||||||
|
<button onClick={() => handleDeleteUser(user.ID)}>Delete</button>
|
||||||
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<h3>Add New User</h3>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
placeholder="Email"
|
||||||
|
value={newUser.email}
|
||||||
|
onChange={(e) => setNewUser({ ...newUser, email: e.target.value })}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Roles (comma-separated)"
|
||||||
|
value={newUser.roles}
|
||||||
|
onChange={(e) => setNewUser({ ...newUser, roles: e.target.value.split(',') })}
|
||||||
|
/>
|
||||||
|
<button onClick={handleCreateUser}>Create User</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UsersList;
|
export default UserList;
|
||||||
|
@ -93,7 +93,7 @@ const AddEmployee = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await axiosInstance.post('/employees', formData, {
|
await axiosInstance.get('http://localhost:5000/employees', formData, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'multipart/form-data',
|
'Content-Type': 'multipart/form-data',
|
||||||
},
|
},
|
||||||
@ -144,7 +144,7 @@ const AddEmployee = () => {
|
|||||||
onClick={() => document.getElementById('imageUpload').click()}
|
onClick={() => document.getElementById('imageUpload').click()}
|
||||||
className={CLASSES.uploadButton}
|
className={CLASSES.uploadButton}
|
||||||
>
|
>
|
||||||
upload
|
add employee image
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,124 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import ProductRow from "./ProductRow";
|
|
||||||
import PropTypes from "prop-types";
|
|
||||||
|
|
||||||
const CategoryList = ({ className = "" }) => {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const handleNavigation = (path) => {
|
|
||||||
navigate(path);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={`w-full bg-primary overflow-y-auto flex flex-row items-start justify-start gap-[3px] leading-[normal] tracking-[normal] text-center text-29xl text-primary1 font-button mq1100:flex-wrap ${className}`}
|
|
||||||
>
|
|
||||||
<div className="flex flex-col items-start justify-start py-0 pr-[33px] pl-0">
|
|
||||||
<div className="overflow-hidden flex flex-col items-start justify-start pt-4 px-5 pb-[50px] gap-[235.5px] mq450:pb-[21px] mq450:box-border mq1025:pt-5 mq1025:pb-8 mq1025:box-border">
|
|
||||||
<div className="flex flex-col items-start justify-start gap-[146.5px]">
|
|
||||||
<div className="w-10 h-[147px] relative">
|
|
||||||
<img
|
|
||||||
className="absolute h-[27.21%] w-full top-[0%] right-[0%] bottom-[72.79%] left-[0%] max-w-full overflow-hidden max-h-full"
|
|
||||||
loading="lazy"
|
|
||||||
alt=""
|
|
||||||
src="/brooks-logo.svg"
|
|
||||||
/>
|
|
||||||
<div className="absolute top-[70px] left-[calc(50%_-_20px)] w-10 h-[77px] hidden">
|
|
||||||
<div className="absolute top-[0px] left-[0px] w-full h-full hidden">
|
|
||||||
<div className="absolute top-[0px] left-[0px] rounded-[50px] box-border w-full h-full border-[1px] border-solid border-secondary-accent" />
|
|
||||||
<div className="absolute top-[40px] left-[3px] rounded-[50%] bg-secondary-accent w-[34px] h-[34px]" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-row items-start justify-start py-0 pr-2 pl-[7px]">
|
|
||||||
<div className="flex flex-col items-start justify-start gap-[70px]">
|
|
||||||
<img
|
|
||||||
className="w-[25px] h-[25px] relative overflow-hidden shrink-0 cursor-pointer"
|
|
||||||
loading="lazy"
|
|
||||||
alt="Home"
|
|
||||||
src="/home-icon.svg"
|
|
||||||
onClick={() => handleNavigation('/home')}
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
className="w-[25px] h-[25px] relative overflow-hidden shrink-0 cursor-pointer"
|
|
||||||
loading="lazy"
|
|
||||||
alt="Categories"
|
|
||||||
src="/category-icon.svg"
|
|
||||||
onClick={() => handleNavigation('/categories')}
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
className="w-[25px] h-[25px] relative overflow-hidden shrink-0 cursor-pointer"
|
|
||||||
loading="lazy"
|
|
||||||
alt="Customer List"
|
|
||||||
src="/customer-list-icon.svg"
|
|
||||||
onClick={() => handleNavigation('/customers')}
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
className="w-[25px] h-[25px] relative overflow-hidden shrink-0 cursor-pointer"
|
|
||||||
loading="lazy"
|
|
||||||
alt="Orders"
|
|
||||||
src="/orders-icon.svg"
|
|
||||||
onClick={() => handleNavigation('/employee/create-order')}
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
className="w-[25px] h-[25px] relative overflow-hidden shrink-0 cursor-pointer"
|
|
||||||
loading="lazy"
|
|
||||||
alt="Account"
|
|
||||||
src="/account-icon.svg"
|
|
||||||
onClick={() => handleNavigation('/account')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-row items-start justify-start py-0 px-2">
|
|
||||||
<div className="flex flex-col items-start justify-start">
|
|
||||||
<img
|
|
||||||
className="w-6 h-6 relative overflow-hidden shrink-0 cursor-pointer"
|
|
||||||
loading="lazy"
|
|
||||||
alt="Logout"
|
|
||||||
src="/materialsymbolslogout.svg"
|
|
||||||
onClick={() => handleNavigation('/logout')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col items-start justify-start pt-[46px] px-0 pb-0">
|
|
||||||
<div className="relative leading-[53px] lowercase font-semibold mq450:text-10xl mq450:leading-[32px] mq1025:text-19xl mq1025:leading-[42px]">
|
|
||||||
categories
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-[820px] flex flex-col items-start justify-start pt-[135px] px-0 pb-0 box-border max-w-full mq750:pt-[57px] mq750:box-border mq1025:pt-[88px] mq1025:box-border">
|
|
||||||
<div className="self-stretch h-[820px] overflow-y-auto shrink-0 flex flex-row flex-wrap items-start justify-start p-5 box-border relative gap-[80px_76px]">
|
|
||||||
<ProductRow image17="/image-17@2x.png" shirts="Shirts" />
|
|
||||||
<ProductRow
|
|
||||||
image17="/image-18@2x.png"
|
|
||||||
shirts="Suits"
|
|
||||||
propLeft="450px"
|
|
||||||
propTop="20px"
|
|
||||||
/>
|
|
||||||
<ProductRow
|
|
||||||
image17="/image-6@2x.png"
|
|
||||||
shirts="Tuxedos"
|
|
||||||
propLeft="20px"
|
|
||||||
propTop="450px"
|
|
||||||
/>
|
|
||||||
<ProductRow
|
|
||||||
image17="/image-28@2x.png"
|
|
||||||
shirts="jackets"
|
|
||||||
propLeft="450px"
|
|
||||||
propTop="450px"
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
CategoryList.propTypes = {
|
|
||||||
className: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CategoryList;
|
|
39
src/components/common/someCompoent.js
Normal file
39
src/components/common/someCompoent.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import axiosInstance from '../../api/axiosConfig';
|
||||||
|
|
||||||
|
const SomeComponent = () => {
|
||||||
|
const [data, setData] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.get('/your-endpoint');
|
||||||
|
setData(response.data);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (err) {
|
||||||
|
setError(err);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (loading) return <p>Loading...</p>;
|
||||||
|
if (error) return <p>Error loading data</p>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Data from API</h1>
|
||||||
|
<ul>
|
||||||
|
{data.map(item => (
|
||||||
|
<li key={item.id}>{item.name}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SomeComponent;
|
0
src/components/common/submitForm.js
Normal file
0
src/components/common/submitForm.js
Normal file
@ -69,12 +69,25 @@ const AddCustomer = () => {
|
|||||||
fetchCities();
|
fetchCities();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Updated handleInputChange function
|
||||||
const handleInputChange = (e) => {
|
const handleInputChange = (e) => {
|
||||||
const { name, value } = e.target;
|
const { name, value } = e.target;
|
||||||
setCustomerData((prevData) => ({
|
|
||||||
...prevData,
|
if (name.startsWith('address.')) {
|
||||||
[name]: value,
|
const addressField = name.split('.')[1];
|
||||||
}));
|
setCustomerData((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
address: {
|
||||||
|
...prevData.address,
|
||||||
|
[addressField]: value,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
setCustomerData((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
[name]: value,
|
||||||
|
}));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleImageChange = (e) => {
|
const handleImageChange = (e) => {
|
||||||
@ -88,23 +101,34 @@ const AddCustomer = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Updated handleAddCustomerSubmit function
|
||||||
const handleAddCustomerSubmit = async (e) => {
|
const handleAddCustomerSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
||||||
|
// Append flat fields
|
||||||
Object.keys(customerData).forEach((key) => {
|
Object.keys(customerData).forEach((key) => {
|
||||||
formData.append(key, customerData[key]);
|
if (key !== 'address' && key !== 'image') {
|
||||||
|
formData.append(key, customerData[key]);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Append address fields
|
||||||
|
Object.keys(customerData.address).forEach((key) => {
|
||||||
|
formData.append(`address[${key}]`, customerData.address[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Append image file
|
||||||
|
if (customerData.image) {
|
||||||
|
formData.append('image', customerData.image);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axiosInstance.post(
|
const response = await axiosInstance.post('/customers', formData, {
|
||||||
'/customers',
|
headers: {
|
||||||
formData,
|
'Content-Type': 'multipart/form-data',
|
||||||
{
|
},
|
||||||
headers: {
|
});
|
||||||
'Content-Type': 'multipart/form-data',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
console.log('Customer added successfully:', response.data);
|
console.log('Customer added successfully:', response.data);
|
||||||
navigate('/customers');
|
navigate('/customers');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -157,7 +181,7 @@ const AddCustomer = () => {
|
|||||||
}
|
}
|
||||||
className={CLASSES.uploadButton}
|
className={CLASSES.uploadButton}
|
||||||
>
|
>
|
||||||
upload
|
add customer image
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -171,110 +195,131 @@ const AddCustomer = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={CLASSES.formSection}>
|
<div className={CLASSES.formSection}>
|
||||||
<form onSubmit={handleAddCustomerSubmit}>
|
<form onSubmit={handleAddCustomerSubmit} className="space-y-4">
|
||||||
<div>
|
<div className={CLASSES.formGroup}>
|
||||||
<label className={CLASSES.formGroup}>first name:</label>
|
<label htmlFor="firstname">First Name</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
id="firstname"
|
||||||
name="firstname"
|
name="firstname"
|
||||||
|
className={CLASSES.formInput}
|
||||||
value={customerData.firstname}
|
value={customerData.firstname}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className={CLASSES.formInput}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className={CLASSES.formGroup}>
|
||||||
<label className={CLASSES.formGroup}>last name:</label>
|
<label htmlFor="lastname">Last Name</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
id="lastname"
|
||||||
name="lastname"
|
name="lastname"
|
||||||
|
className={CLASSES.formInput}
|
||||||
value={customerData.lastname}
|
value={customerData.lastname}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className={CLASSES.formInput}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className={CLASSES.formGroup}>
|
||||||
<label className={CLASSES.formGroup}>age:</label>
|
<label htmlFor="age">Age</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
|
id="age"
|
||||||
name="age"
|
name="age"
|
||||||
|
className={CLASSES.formInput}
|
||||||
value={customerData.age}
|
value={customerData.age}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className={CLASSES.formInput}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className={CLASSES.formGroup}>
|
||||||
<label className={CLASSES.formGroup}>gender:</label>
|
<label htmlFor="gender">Gender</label>
|
||||||
<select
|
<select
|
||||||
|
id="gender"
|
||||||
name="gender"
|
name="gender"
|
||||||
|
className={CLASSES.formSelect}
|
||||||
value={customerData.gender}
|
value={customerData.gender}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className={CLASSES.formSelect}
|
|
||||||
>
|
>
|
||||||
<option value="" disabled>select gender</option>
|
<option value="">Select gender</option>
|
||||||
<option value="male">male</option>
|
<option value="male">Male</option>
|
||||||
<option value="female">female</option>
|
<option value="female">Female</option>
|
||||||
<option value="other">other</option>
|
<option value="other">Other</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className={CLASSES.formGroup}>
|
||||||
<label className={CLASSES.formGroup}>email:</label>
|
<label htmlFor="email">Email</label>
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
|
id="email"
|
||||||
name="email"
|
name="email"
|
||||||
|
className={CLASSES.formInput}
|
||||||
value={customerData.email}
|
value={customerData.email}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className={CLASSES.formInput}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className={CLASSES.formGroup}>
|
||||||
<label className={CLASSES.formGroup}>address line 1:</label>
|
<label htmlFor="mobile">Mobile Number</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="address_line_1"
|
id="mobile"
|
||||||
value={customerData.address_line_1}
|
name="mobile"
|
||||||
onChange={handleInputChange}
|
|
||||||
className={CLASSES.formInput}
|
className={CLASSES.formInput}
|
||||||
|
value={customerData.mobile}
|
||||||
|
onChange={handleInputChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className={CLASSES.formGroup}>
|
||||||
<label className={CLASSES.formGroup}>address line 2:</label>
|
<label htmlFor="address_line_1">Address Line 1</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="address_line_2"
|
id="address_line_1"
|
||||||
value={customerData.address_line_2}
|
name="address.address_line_1"
|
||||||
onChange={handleInputChange}
|
|
||||||
className={CLASSES.formInput}
|
className={CLASSES.formInput}
|
||||||
|
value={customerData.address.address_line_1}
|
||||||
|
onChange={handleInputChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className={CLASSES.formGroup}>
|
||||||
<label className={CLASSES.formGroup}>nearby landmark:</label>
|
<label htmlFor="address_line_2">Address Line 2</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="nearby_landmark"
|
id="address_line_2"
|
||||||
value={customerData.nearby_landmark}
|
name="address.address_line_2"
|
||||||
onChange={handleInputChange}
|
|
||||||
className={CLASSES.formInput}
|
className={CLASSES.formInput}
|
||||||
|
value={customerData.address.address_line_2}
|
||||||
|
onChange={handleInputChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className={CLASSES.formGroup}>
|
||||||
<label className={CLASSES.formGroup}>pincode:</label>
|
<label htmlFor="nearby_landmark">Nearby Landmark</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="pincode"
|
id="nearby_landmark"
|
||||||
value={customerData.pincode}
|
name="address.nearby_landmark"
|
||||||
onChange={handleInputChange}
|
|
||||||
className={CLASSES.formInput}
|
className={CLASSES.formInput}
|
||||||
|
value={customerData.address.nearby_landmark}
|
||||||
|
onChange={handleInputChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className={CLASSES.formGroup}>
|
||||||
<label className={CLASSES.formGroup}>city:</label>
|
<label htmlFor="pincode">Pincode</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="pincode"
|
||||||
|
name="address.pincode"
|
||||||
|
className={CLASSES.formInput}
|
||||||
|
value={customerData.address.pincode}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={CLASSES.formGroup}>
|
||||||
|
<label htmlFor="city_id">City</label>
|
||||||
<select
|
<select
|
||||||
name="city_id"
|
id="city_id"
|
||||||
value={customerData.city_id}
|
name="address.city_id"
|
||||||
onChange={handleInputChange}
|
|
||||||
className={CLASSES.formSelect}
|
className={CLASSES.formSelect}
|
||||||
|
value={customerData.address.city_id}
|
||||||
|
onChange={handleInputChange}
|
||||||
>
|
>
|
||||||
<option value="" disabled>select city</option>
|
<option value="">Select City</option>
|
||||||
{cities.map((city) => (
|
{cities.map((city) => (
|
||||||
<option key={city.id} value={city.id}>
|
<option key={city.id} value={city.id}>
|
||||||
{city.name}
|
{city.name}
|
||||||
@ -282,19 +327,11 @@ const AddCustomer = () => {
|
|||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className={CLASSES.formGroup}>
|
||||||
<label className={CLASSES.formGroup}>mobile:</label>
|
<button type="submit" className={CLASSES.submitButton}>
|
||||||
<input
|
save customer
|
||||||
type="text"
|
</button>
|
||||||
name="mobile"
|
|
||||||
value={customerData.mobile}
|
|
||||||
onChange={handleInputChange}
|
|
||||||
className={CLASSES.formInput}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" className={CLASSES.submitButton}>
|
|
||||||
add customer
|
|
||||||
</button>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,7 +5,6 @@ import axios from 'axios';
|
|||||||
import Sidebar from '../sidebar/Sidebar';
|
import Sidebar from '../sidebar/Sidebar';
|
||||||
import '../../styles/CustomerMeasurements.css';
|
import '../../styles/CustomerMeasurements.css';
|
||||||
|
|
||||||
|
|
||||||
const CustomerMeasurements = () => {
|
const CustomerMeasurements = () => {
|
||||||
const onFinish = async (values) => {
|
const onFinish = async (values) => {
|
||||||
const token = localStorage.getItem('token'); // Assuming the token is stored in localStorage
|
const token = localStorage.getItem('token'); // Assuming the token is stored in localStorage
|
||||||
@ -24,54 +23,54 @@ const CustomerMeasurements = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container">
|
<div className="container flex">
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<div className="content">
|
<div className="content flex-1">
|
||||||
<div className="form-container">
|
<div className="form-container max-w-2xl mx-auto p-6">
|
||||||
<div className="header">
|
<div className="header flex justify-between items-center mb-4">
|
||||||
<h1 className="text-2xl font-semibold text-[#0e355b]">Customer Measurements</h1>
|
<h1 className="text-2xl font-semibold text-[#0e355b]">Customer Measurements</h1>
|
||||||
<Link to="/CategoryList" className="skip-link">Skip for now</Link>
|
<Link to="/CategoryList" className="skip-link ">Skip for now</Link>
|
||||||
</div>
|
</div>
|
||||||
<Form onFinish={onFinish} className="form">
|
<Form onFinish={onFinish} className="form space-y-4">
|
||||||
<h2 className="section-title">Upper Body Measurements</h2>
|
<h2 className="section-title text-lg font-medium">Upper Body Measurements</h2>
|
||||||
<Form.Item name="neck" label="Neck Circumference (in inch)">
|
<Form.Item name="neck" label="Neck Circumference (in inch)">
|
||||||
<Input className="input" />
|
<Input className="input focus:outline-none focus:ring-0 border-b border-gray-400" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="chest" label="Chest Circumference (in inch)">
|
<Form.Item name="chest" label="Chest Circumference (in inch)">
|
||||||
<Input className="input" />
|
<Input className="input focus:outline-none focus:ring-0 border-b border-gray-400" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="waist" label="Waist Circumference (in inch)">
|
<Form.Item name="waist" label="Waist Circumference (in inch)">
|
||||||
<Input className="input" />
|
<Input className="input focus:outline-none focus:ring-0 border-b border-gray-400" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="shoulder" label="Shoulder Width (in inch)">
|
<Form.Item name="shoulder" label="Shoulder Width (in inch)">
|
||||||
<Input className="input" />
|
<Input className="input focus:outline-none focus:ring-0 border-b border-gray-400" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="arm" label="Arm Length (in inch)">
|
<Form.Item name="arm" label="Arm Length (in inch)">
|
||||||
<Input className="input" />
|
<Input className="input focus:outline-none focus:ring-0 border-b border-gray-400" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="sleeve" label="Sleeve Length (in inch)">
|
<Form.Item name="sleeve" label="Sleeve Length (in inch)">
|
||||||
<Input className="input" />
|
<Input className="input focus:outline-none focus:ring-0 border-b border-gray-400" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<h2 className="section-title">Lower Body Measurements</h2>
|
<h2 className="section-title text-lg font-medium">Lower Body Measurements</h2>
|
||||||
<Form.Item name="hip" label="Hip Circumference (in inch)">
|
<Form.Item name="hip" label="Hip Circumference (in inch)">
|
||||||
<Input className="input" />
|
<Input className="input focus:outline-none focus:ring-0 border-b border-gray-400" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="inseam" label="Inseam (in inch)">
|
<Form.Item name="inseam" label="Inseam (in inch)">
|
||||||
<Input className="input" />
|
<Input className="input focus:outline-none focus:ring-0 border-b border-gray-400" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="outseam" label="Outseam (in inch)">
|
<Form.Item name="outseam" label="Outseam (in inch)">
|
||||||
<Input className="input" />
|
<Input className="input focus:outline-none focus:ring-0 border-b border-gray-400" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="thigh" label="Thigh Circumference (in inch)">
|
<Form.Item name="thigh" label="Thigh Circumference (in inch)">
|
||||||
<Input className="input" />
|
<Input className="input focus:outline-none focus:ring-0 border-b border-gray-400" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="ankle" label="Ankle Circumference (in inch)">
|
<Form.Item name="ankle" label="Ankle Circumference (in inch)">
|
||||||
<Input className="input" />
|
<Input className="input focus:outline-none focus:ring-0 border-b border-gray-400" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item>
|
<Form.Item>
|
||||||
<div className="button-container">
|
<div className="button-container flex justify-end">
|
||||||
<Button type="primary" htmlType="submit" className="submit-button">
|
<Button type="primary" htmlType="submit" className="submit-button bg-[#0e355b] text-white py-2 px-4 rounded-md">
|
||||||
Save Measurements
|
Save Measurements
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,7 +14,7 @@ const { Sider } = Layout;
|
|||||||
|
|
||||||
const classNames = {
|
const classNames = {
|
||||||
sider: 'desktop-sidebar',
|
sider: 'desktop-sidebar',
|
||||||
container: 'flex flex-col items-center mt-4',
|
container: 'flex flex-col items-center mt-4 h-full justify-between',
|
||||||
logoContainer: 'flex items-center justify-center h-16 w-16 mb-5 bg-white',
|
logoContainer: 'flex items-center justify-center h-16 w-16 mb-5 bg-white',
|
||||||
iconContainer: 'flex flex-col items-center flex-grow',
|
iconContainer: 'flex flex-col items-center flex-grow',
|
||||||
iconLink: 'my-6',
|
iconLink: 'my-6',
|
||||||
|
@ -56,4 +56,7 @@
|
|||||||
.menu-item {
|
.menu-item {
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,79 +1,74 @@
|
|||||||
/* Container styles */
|
/* CustomerMeasurements.css */
|
||||||
|
|
||||||
|
/* Container styling */
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
}
|
||||||
}
|
|
||||||
|
/* Content styling */
|
||||||
/* Content styles */
|
.content {
|
||||||
.content {
|
flex: 1;
|
||||||
width: 100%;
|
}
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
/* Form container styling */
|
||||||
min-height: 100vh;
|
.form-container {
|
||||||
color: #ffffff;
|
max-width: 40rem; /* 640px */
|
||||||
}
|
margin: 0 auto;
|
||||||
|
padding: 1.5rem; /* 24px */
|
||||||
/* Form container styles */
|
}
|
||||||
.form-container {
|
|
||||||
min-height: 100vh;
|
/* Header styling */
|
||||||
color: #4b5563;
|
.header {
|
||||||
padding: 1.5rem;
|
display: flex;
|
||||||
}
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
/* Header styles */
|
margin-bottom: 1rem; /* 16px */
|
||||||
.header {
|
}
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
/* Skip link styling */
|
||||||
align-items: center;
|
.skip-link {
|
||||||
margin-bottom: 1.5rem;
|
color: #0e355b; /* Tailwind's blue-600 */
|
||||||
}
|
text-decoration: none;
|
||||||
|
}
|
||||||
.title {
|
|
||||||
font-size: 2rem;
|
/* Section title styling */
|
||||||
font-weight: 600;
|
.section-title {
|
||||||
color: #0e355b;
|
font-size: 1.125rem; /* 18px */
|
||||||
}
|
font-weight: 500;
|
||||||
|
margin-bottom: 0.5rem; /* 8px */
|
||||||
.skip-link {
|
}
|
||||||
color: #0e355b;
|
|
||||||
}
|
/* Input field styling */
|
||||||
|
.input {
|
||||||
/* Form styles */
|
width: 100%;
|
||||||
.form {
|
border: none;
|
||||||
display: flex;
|
/* Tailwind's gray-400 */
|
||||||
flex-direction: column;
|
outline: none;
|
||||||
gap: 1rem;
|
padding: 0.5rem 0; /* 8px top and bottom */
|
||||||
}
|
transition: border-color 0.3s ease;
|
||||||
|
}
|
||||||
.section-title {
|
|
||||||
font-size: 1.125rem;
|
.input:focus {
|
||||||
font-weight: 600;
|
border-bottom-color: #0e355b; /* Custom blue color for focus */
|
||||||
color: #0e355b;
|
}
|
||||||
}
|
|
||||||
|
/* Button container styling */
|
||||||
/* Input styles */
|
.button-container {
|
||||||
.input {
|
display: flex;
|
||||||
width: 100%;
|
justify-content: flex-end;
|
||||||
border: 0;
|
}
|
||||||
border-bottom: 1px solid #d1d5db;
|
|
||||||
}
|
/* Submit button styling */
|
||||||
|
.submit-button {
|
||||||
.input:focus {
|
background-color: #0e355b;
|
||||||
border-color: #4b5563;
|
color: white;
|
||||||
box-shadow: none;
|
padding: 0.5rem 1rem; /* 8px top and bottom, 16px left and right */
|
||||||
}
|
border-radius: 0.375rem; /* 6px */
|
||||||
|
border: none;
|
||||||
/* Button container styles */
|
cursor: pointer;
|
||||||
.button-container {
|
transition: background-color 0.3s ease;
|
||||||
text-align: center;
|
}
|
||||||
}
|
|
||||||
|
.submit-button:hover {
|
||||||
/* Submit button styles */
|
background-color: #0e355b; /* Darker shade for hover */
|
||||||
.submit-button {
|
}
|
||||||
background-color: #0e355b;
|
|
||||||
color: #d1d5db;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
border-radius: 0.375rem;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import axiosInstance from '../utils/axiosInstance';
|
||||||
|
|
||||||
|
const SubmitForm = () => {
|
||||||
|
const [formData, setFormData] = useState({ name: '', email: '' });
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState(null);
|
||||||
|
const [success, setSuccess] = useState(false);
|
||||||
|
|
||||||
|
const handleChange = (e) => {
|
||||||
|
setFormData({
|
||||||
|
...formData,
|
||||||
|
[e.target.name]: e.target.value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.post('/submit-endpoint', formData);
|
||||||
|
console.log(response.data);
|
||||||
|
setSuccess(true);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (err) {
|
||||||
|
setError(err);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
value={formData.name}
|
||||||
|
onChange={handleChange}
|
||||||
|
placeholder="Name"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
value={formData.email}
|
||||||
|
onChange={handleChange}
|
||||||
|
placeholder="Email"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<button type="submit" disabled={loading}>
|
||||||
|
{loading ? 'Submitting...' : 'Submit'}
|
||||||
|
</button>
|
||||||
|
{success && <p>Form submitted successfully!</p>}
|
||||||
|
{error && <p>Error submitting form</p>}
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SubmitForm;
|
@ -6,7 +6,7 @@ export default defineConfig({
|
|||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': '/src',
|
'@api': '/src/api',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user