reset password request authentication and route to the login page
This commit is contained in:
parent
89d5b17dc1
commit
fc73ddefca
15826
package-lock.json
generated
15826
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,7 @@
|
|||||||
"proxy": "http://localhost:5000",
|
"proxy": "http://localhost:5000",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^5.3.7",
|
"@ant-design/icons": "^5.3.7",
|
||||||
|
"@craco/craco": "^7.1.0",
|
||||||
"@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",
|
||||||
@ -30,14 +31,14 @@
|
|||||||
"@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": "^10.4.19",
|
"autoprefixer": "^9.8.8",
|
||||||
"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",
|
||||||
"json-server": "^1.0.0-beta.1",
|
"json-server": "^1.0.0-beta.1",
|
||||||
"postcss": "^8.4.39",
|
"postcss": "^7.0.39",
|
||||||
"tailwindcss": "^3.4.6",
|
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.17",
|
||||||
"vite": "^5.2.0"
|
"vite": "^5.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import React, { useContext } from 'react';
|
|||||||
import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom';
|
import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom';
|
||||||
import { Layout } from 'antd';
|
import { Layout } from 'antd';
|
||||||
import LoginPage from './components/Auth/LoginPage';
|
import LoginPage from './components/Auth/LoginPage';
|
||||||
|
import ResetPasswordRequest from './components/Auth/ResetPasswordRequest';
|
||||||
import AdminDashboard from './components/admin/AdminDashboard';
|
import AdminDashboard from './components/admin/AdminDashboard';
|
||||||
import EmployeeDashboard from './components/employee/EmployeeDashboard';
|
import EmployeeDashboard from './components/employee/EmployeeDashboard';
|
||||||
import CustomerList from './components/customer/CustomerList';
|
import CustomerList from './components/customer/CustomerList';
|
||||||
@ -25,6 +26,7 @@ const App = () => {
|
|||||||
<Router>
|
<Router>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route exact path="/" element={<LoginPage />} />
|
<Route exact path="/" element={<LoginPage />} />
|
||||||
|
<Route path="/reset-password" element={<ResetPasswordRequest />} />
|
||||||
<Route path="/employee/home" element={<EmployeeDashboard />} /> {/* Add HomePage route */}
|
<Route path="/employee/home" element={<EmployeeDashboard />} /> {/* Add HomePage route */}
|
||||||
<Route path="/admin" element={<PrivateRoute><AdminDashboard /></PrivateRoute>} />
|
<Route path="/admin" element={<PrivateRoute><AdminDashboard /></PrivateRoute>} />
|
||||||
<Route path="/employee" element={<PrivateRoute><EmployeeDashboard /></PrivateRoute>} />
|
<Route path="/employee" element={<PrivateRoute><EmployeeDashboard /></PrivateRoute>} />
|
||||||
|
@ -8,6 +8,7 @@ body, html {
|
|||||||
/* color: #fff; */
|
/* color: #fff; */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.login-page {
|
.login-page {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -39,6 +40,12 @@ body, html {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto 20px;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
color: #0e355b;
|
color: #0e355b;
|
||||||
|
@ -2,6 +2,7 @@ import React, { useState } from 'react';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import axiosInstance from '../../api/axiosConfig';
|
import axiosInstance from '../../api/axiosConfig';
|
||||||
import './LoginPage.css';
|
import './LoginPage.css';
|
||||||
|
import BrookslogoIcon from '../../assets/thob-data/BrookslogoIcon.svg';
|
||||||
|
|
||||||
const LoginPage = () => {
|
const LoginPage = () => {
|
||||||
const [email, setEmail] = useState('');
|
const [email, setEmail] = useState('');
|
||||||
@ -12,7 +13,7 @@ const LoginPage = () => {
|
|||||||
const handleLogin = async (e) => {
|
const handleLogin = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setError('');
|
setError('');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axiosInstance.get('http://localhost:5000/authlogin');
|
const response = await axiosInstance.get('http://localhost:5000/authlogin');
|
||||||
const user = response.data.find(user => user.email === email && user.password === password);
|
const user = response.data.find(user => user.email === email && user.password === password);
|
||||||
@ -39,11 +40,12 @@ const LoginPage = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-row min-h-screen justify-center items-center">
|
<div className="flex flex-row min-h-screen justify-center items-center">
|
||||||
<div className="login-page flex items-center justify-center min-h-screen w-full md:w-1/2 lg:w-1/3 p-4">
|
<div className="login-page flex items-center justify-center min-h-screen w-full md:w-1/2 lg:w-1/3 p-4">
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
|
<img src={BrookslogoIcon} alt="Logo" className="logo" />
|
||||||
<h1>welcome back</h1>
|
<h1>welcome back</h1>
|
||||||
<p>be among the first to experience 3D magic! register for private alpha.</p>
|
<p>be among the first to experience 3D magic! register for private alpha.</p>
|
||||||
{error && <p className="error-message">{error}</p>}
|
{error && <p className="error-message">{error}</p>}
|
||||||
@ -71,7 +73,7 @@ const LoginPage = () => {
|
|||||||
className="input-field"
|
className="input-field"
|
||||||
/>
|
/>
|
||||||
<div className="forgot-password-container">
|
<div className="forgot-password-container">
|
||||||
<a href="#">Forgot password?</a>
|
<a href="/reset-password">Forgot password?</a>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" className="login-button">
|
<button type="submit" className="login-button">
|
||||||
login
|
login
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
import axiosInstance from '../../api/axiosConfig';
|
import axiosInstance from '../../api/axiosConfig';
|
||||||
import './ResetPasswordRequest.css';
|
|
||||||
|
|
||||||
const ResetPasswordRequest = () => {
|
const ResetPasswordRequest = () => {
|
||||||
const [email, setEmail] = useState('');
|
const [email, setEmail] = useState('');
|
||||||
|
@ -4,9 +4,9 @@ import Sidebar from '../sidebar/Sidebar';
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faChevronLeft } from '@fortawesome/free-solid-svg-icons';
|
import { faChevronLeft } from '@fortawesome/free-solid-svg-icons';
|
||||||
import axiosInstance from '../../api/axiosConfig';
|
import axiosInstance from '../../api/axiosConfig';
|
||||||
|
import { styles } from '../../styles/classNames';
|
||||||
import '../../styles/AddEmployee.css';
|
import '../../styles/AddEmployee.css';
|
||||||
|
|
||||||
|
|
||||||
const AddEmployee = () => {
|
const AddEmployee = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [employeeData, setEmployeeData] = useState({
|
const [employeeData, setEmployeeData] = useState({
|
||||||
@ -15,11 +15,13 @@ const AddEmployee = () => {
|
|||||||
age: '',
|
age: '',
|
||||||
gender: '',
|
gender: '',
|
||||||
email: '',
|
email: '',
|
||||||
address_line_1: '',
|
address: {
|
||||||
address_line_2: '',
|
address_line_1: '',
|
||||||
nearby_landmark: '',
|
address_line_2: '',
|
||||||
pincode: '',
|
nearby_landmark: '',
|
||||||
city_id: '',
|
pincode: '',
|
||||||
|
city_id: '',
|
||||||
|
},
|
||||||
mobile: '',
|
mobile: '',
|
||||||
image: null,
|
image: null,
|
||||||
});
|
});
|
||||||
@ -83,31 +85,31 @@ const AddEmployee = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-row">
|
<div className={styles.container}>
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<div className="w-full flex flex-col min-h-screen text-black">
|
<div className={styles.content}>
|
||||||
<div className="min-h-screen text-secondary p-6 bg-light">
|
<div className={styles.header}>
|
||||||
<div className="flex items-center ">
|
<div className="flex items-center ">
|
||||||
<Link to="/employees" className="text-primary text-xl ">
|
<Link to="/employees" className={styles.backButton}>
|
||||||
<FontAwesomeIcon icon={faChevronLeft} />
|
<FontAwesomeIcon icon={faChevronLeft} />
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="text-2xl font-semibold text-primary">
|
<h1 className={styles.title}>
|
||||||
create employee account
|
create employee account
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="space-y-6 w-full max-w-4xl">
|
<div className={`${styles.centerText} space-y-6 w-full max-w-4xl`}>
|
||||||
<div className="text-center">
|
<div className={styles.centerText}>
|
||||||
<div className="inline-block relative">
|
<div className="inline-block relative">
|
||||||
<div className="bg-gray-300 w-24 h-24 rounded-full mx-auto overflow-hidden">
|
<div className={styles.imageWrapper}>
|
||||||
{imagePreview ? (
|
{imagePreview ? (
|
||||||
<img
|
<img
|
||||||
src={imagePreview}
|
src={imagePreview}
|
||||||
alt="Employee"
|
alt="Employee"
|
||||||
className="w-full h-full object-cover"
|
className={styles.imagePreview}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="w-full h-full flex items-center justify-center text-gray-500">
|
<div className={styles.noImageText}>
|
||||||
No image
|
No image
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -122,14 +124,14 @@ const AddEmployee = () => {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => document.getElementById('imageUpload').click()}
|
onClick={() => document.getElementById('imageUpload').click()}
|
||||||
className="image-upload-btn"
|
className={styles.imageUploadButton}
|
||||||
>
|
>
|
||||||
Upload
|
Upload
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form onSubmit={handleAddEmployeeSubmit} className="space-y-4">
|
<form onSubmit={handleAddEmployeeSubmit} className={styles.form}>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
<div className={styles.formGroup}>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-secondary font-medium">
|
<label className="block text-secondary font-medium">
|
||||||
employee firstname:
|
employee firstname:
|
||||||
@ -139,7 +141,7 @@ const AddEmployee = () => {
|
|||||||
name="firstname"
|
name="firstname"
|
||||||
value={employeeData.firstname}
|
value={employeeData.firstname}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="input-underline w-full p-2 focus-border"
|
className={styles.input}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -151,7 +153,7 @@ const AddEmployee = () => {
|
|||||||
name="lastname"
|
name="lastname"
|
||||||
value={employeeData.lastname}
|
value={employeeData.lastname}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="input-underline w-full p-2 focus-border"
|
className={styles.input}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -163,7 +165,7 @@ const AddEmployee = () => {
|
|||||||
name="age"
|
name="age"
|
||||||
value={employeeData.age}
|
value={employeeData.age}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="input-underline w-full p-2 focus-border"
|
className={styles.input}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -174,7 +176,7 @@ const AddEmployee = () => {
|
|||||||
name="gender"
|
name="gender"
|
||||||
value={employeeData.gender}
|
value={employeeData.gender}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="input-underline w-full p-2 focus-border"
|
className={styles.input}
|
||||||
>
|
>
|
||||||
<option value="" disabled>
|
<option value="" disabled>
|
||||||
select gender
|
select gender
|
||||||
@ -193,7 +195,7 @@ const AddEmployee = () => {
|
|||||||
name="mobile"
|
name="mobile"
|
||||||
value={employeeData.mobile}
|
value={employeeData.mobile}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="input-underline w-full p-2 focus-border"
|
className={styles.input}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="md:col-span-2 lg:col-span-3">
|
<div className="md:col-span-2 lg:col-span-3">
|
||||||
@ -205,7 +207,7 @@ const AddEmployee = () => {
|
|||||||
name="address_line_1"
|
name="address_line_1"
|
||||||
value={employeeData.address_line_1}
|
value={employeeData.address_line_1}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="input-underline w-full p-2 focus-border"
|
className={styles.input}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="md:col-span-2 lg:col-span-3">
|
<div className="md:col-span-2 lg:col-span-3">
|
||||||
@ -217,7 +219,7 @@ const AddEmployee = () => {
|
|||||||
name="address_line_2"
|
name="address_line_2"
|
||||||
value={employeeData.address_line_2}
|
value={employeeData.address_line_2}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="input-underline w-full p-2 focus-border"
|
className={styles.input}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="md:col-span-2 lg:col-span-3">
|
<div className="md:col-span-2 lg:col-span-3">
|
||||||
@ -229,7 +231,7 @@ const AddEmployee = () => {
|
|||||||
name="nearby_landmark"
|
name="nearby_landmark"
|
||||||
value={employeeData.nearby_landmark}
|
value={employeeData.nearby_landmark}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="input-underline w-full p-2 focus-border"
|
className={styles.input}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="md:col-span-2 lg:col-span-3">
|
<div className="md:col-span-2 lg:col-span-3">
|
||||||
@ -241,7 +243,7 @@ const AddEmployee = () => {
|
|||||||
name="pincode"
|
name="pincode"
|
||||||
value={employeeData.pincode}
|
value={employeeData.pincode}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="input-underline w-full p-2 focus-border"
|
className={styles.input}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="md:col-span-2 lg:col-span-3">
|
<div className="md:col-span-2 lg:col-span-3">
|
||||||
@ -252,7 +254,7 @@ const AddEmployee = () => {
|
|||||||
name="city_id"
|
name="city_id"
|
||||||
value={employeeData.city_id}
|
value={employeeData.city_id}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="input-underline w-full p-2 focus-border"
|
className={styles.input}
|
||||||
>
|
>
|
||||||
<option value="" disabled>
|
<option value="" disabled>
|
||||||
select city
|
select city
|
||||||
@ -274,14 +276,14 @@ const AddEmployee = () => {
|
|||||||
name="email"
|
name="email"
|
||||||
value={employeeData.email}
|
value={employeeData.email}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="input-underline w-full p-2 focus-border"
|
className={styles.input}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-center mt-6">
|
<div className={`${styles.centerText} mt-6`}>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="btn-primary"
|
className={styles.button}
|
||||||
>
|
>
|
||||||
create account
|
create account
|
||||||
</button>
|
</button>
|
||||||
|
@ -5,6 +5,32 @@ import { faChevronLeft } from '@fortawesome/free-solid-svg-icons';
|
|||||||
import Sidebar from '../sidebar/Sidebar';
|
import Sidebar from '../sidebar/Sidebar';
|
||||||
import axiosInstance from '../../api/axiosConfig';
|
import axiosInstance from '../../api/axiosConfig';
|
||||||
|
|
||||||
|
const CLASSES = {
|
||||||
|
container: 'flex flex-row',
|
||||||
|
mainContent: 'w-full flex flex-col min-h-screen text-black',
|
||||||
|
innerContent: 'min-h-screen text-gray-800 p-6',
|
||||||
|
header: 'flex justify-between items-center',
|
||||||
|
headerTitle: 'flex items-center',
|
||||||
|
backButton: 'text-[#0e355b] text-xl',
|
||||||
|
title: 'text-2xl font-semibold text-[#0e355b]',
|
||||||
|
skipLink: 'text-blue-900',
|
||||||
|
formGrid: 'grid grid-cols-1 md:grid-cols-3 gap-6',
|
||||||
|
imageSection: 'space-y-6',
|
||||||
|
imageWrapper: 'text-center',
|
||||||
|
imageContainer: 'inline-block relative',
|
||||||
|
imagePreview: 'bg-gray-300 w-24 h-24 rounded-full mx-auto overflow-hidden',
|
||||||
|
noImage: 'w-full h-full flex items-center justify-center text-gray-500',
|
||||||
|
hiddenInput: 'hidden',
|
||||||
|
uploadButton:
|
||||||
|
'absolute bottom-0 left-1/2 transform -translate-x-1/2 bg-gray-700 text-white text-xs px-2 py-1 rounded-full',
|
||||||
|
linkTitle: 'text-lg font-semibold',
|
||||||
|
formSection: 'md:col-span-2 space-y-4',
|
||||||
|
formGroup: 'block text-gray-800 font-medium',
|
||||||
|
formInput: 'w-full p-2 border-b border-gray-400 focus:border-gray-700',
|
||||||
|
formSelect: 'w-full p-2 border-b border-gray-400 focus:border-gray-700',
|
||||||
|
submitButton: 'bg-[#0e355b] text-white py-2 px-4 rounded-md',
|
||||||
|
};
|
||||||
|
|
||||||
const AddCustomer = () => {
|
const AddCustomer = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [customerData, setCustomerData] = useState({
|
const [customerData, setCustomerData] = useState({
|
||||||
@ -13,14 +39,17 @@ const AddCustomer = () => {
|
|||||||
age: '',
|
age: '',
|
||||||
gender: '',
|
gender: '',
|
||||||
email: '',
|
email: '',
|
||||||
address_line_1: '',
|
|
||||||
address_line_2: '',
|
|
||||||
nearby_landmark: '',
|
|
||||||
pincode: '',
|
|
||||||
city_id: '',
|
|
||||||
mobile: '',
|
mobile: '',
|
||||||
image: null,
|
image: null,
|
||||||
|
address: {
|
||||||
|
address_line_1: '',
|
||||||
|
address_line_2: '',
|
||||||
|
nearby_landmark: '',
|
||||||
|
pincode: '',
|
||||||
|
city_id: '',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const [cities, setCities] = useState([]);
|
const [cities, setCities] = useState([]);
|
||||||
const [imagePreview, setImagePreview] = useState(null);
|
const [imagePreview, setImagePreview] = useState(null);
|
||||||
|
|
||||||
@ -43,10 +72,21 @@ const AddCustomer = () => {
|
|||||||
|
|
||||||
const handleInputChange = (e) => {
|
const handleInputChange = (e) => {
|
||||||
const { name, value } = e.target;
|
const { name, value } = e.target;
|
||||||
setCustomerData({
|
setCustomerData((prevData) => ({
|
||||||
...customerData,
|
...prevData,
|
||||||
[name]: value,
|
[name]: value,
|
||||||
});
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddressChange = (e) => {
|
||||||
|
const { name, value } = e.target;
|
||||||
|
setCustomerData((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
address: {
|
||||||
|
...prevData.address,
|
||||||
|
[name]: value,
|
||||||
|
},
|
||||||
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleImageChange = (e) => {
|
const handleImageChange = (e) => {
|
||||||
@ -64,16 +104,26 @@ const AddCustomer = () => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
Object.keys(customerData).forEach((key) => {
|
Object.keys(customerData).forEach((key) => {
|
||||||
formData.append(key, customerData[key]);
|
if (key === 'address') {
|
||||||
|
Object.keys(customerData.address).forEach((addrKey) => {
|
||||||
|
formData.append(`address[${addrKey}]`, customerData.address[addrKey]);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
formData.append(key, customerData[key]);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axiosInstance.post('http://localhost:5000/customers', formData, {
|
const response = await axiosInstance.post(
|
||||||
headers: {
|
'http://localhost:5000/customers',
|
||||||
'Content-Type': 'multipart/form-data',
|
formData,
|
||||||
},
|
{
|
||||||
});
|
headers: {
|
||||||
console.log('Raw response:', response);
|
'Content-Type': 'multipart/form-data',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
console.log('Raw response:', response);
|
||||||
console.log('Customer added successfully:', response.data);
|
console.log('Customer added successfully:', response.data);
|
||||||
navigate('/customers');
|
navigate('/customers');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -82,26 +132,26 @@ const AddCustomer = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-row">
|
<div className={CLASSES.container}>
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<div className="w-full flex flex-col min-h-screen text-black">
|
<div className={CLASSES.mainContent}>
|
||||||
<div className="min-h-screen text-gray-800 p-6">
|
<div className={CLASSES.innerContent}>
|
||||||
<div className="flex justify-between items-center">
|
<div className={CLASSES.header}>
|
||||||
<div className="flex items-center">
|
<div className={CLASSES.headerTitle}>
|
||||||
<Link to="/customers" className="text-[#0e355b] text-xl">
|
<Link to="/customers" className={CLASSES.backButton}>
|
||||||
<FontAwesomeIcon icon={faChevronLeft} />
|
<FontAwesomeIcon icon={faChevronLeft} />
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="text-2xl font-semibold text-[#0e355b]">
|
<h1 className={CLASSES.title}>Add Customer</h1>
|
||||||
Add Customer
|
|
||||||
</h1>
|
|
||||||
</div>
|
</div>
|
||||||
<Link to="/CategoryList" className="text-blue-900">Skip for now</Link>
|
<Link to="/CategoryList" className={CLASSES.skipLink}>
|
||||||
|
Skip for now
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
<div className={CLASSES.formGrid}>
|
||||||
<div className="space-y-6">
|
<div className={CLASSES.imageSection}>
|
||||||
<div className="text-center">
|
<div className={CLASSES.imageWrapper}>
|
||||||
<div className="inline-block relative">
|
<div className={CLASSES.imageContainer}>
|
||||||
<div className="bg-gray-300 w-24 h-24 rounded-full mx-auto overflow-hidden">
|
<div className={CLASSES.imagePreview}>
|
||||||
{imagePreview ? (
|
{imagePreview ? (
|
||||||
<img
|
<img
|
||||||
src={imagePreview}
|
src={imagePreview}
|
||||||
@ -109,22 +159,22 @@ const AddCustomer = () => {
|
|||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="w-full h-full flex items-center justify-center text-gray-500">
|
<div className={CLASSES.noImage}>No Image</div>
|
||||||
No Image
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
className="hidden"
|
className={CLASSES.hiddenInput}
|
||||||
id="imageUpload"
|
id="imageUpload"
|
||||||
onChange={handleImageChange}
|
onChange={handleImageChange}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => document.getElementById('imageUpload').click()}
|
onClick={() =>
|
||||||
className="absolute bottom-0 left-1/2 transform -translate-x-1/2 bg-gray-700 text-white text-xs px-2 py-1 rounded-full"
|
document.getElementById('imageUpload').click()
|
||||||
|
}
|
||||||
|
className={CLASSES.uploadButton}
|
||||||
>
|
>
|
||||||
Upload
|
Upload
|
||||||
</button>
|
</button>
|
||||||
@ -132,60 +182,52 @@ const AddCustomer = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Link to="/add-customer">
|
<Link to="/add-customer">
|
||||||
<h2 className="text-lg font-semibold">Customer Information</h2>
|
<h2 className={CLASSES.linkTitle}>Customer Information</h2>
|
||||||
</Link>
|
</Link>
|
||||||
<Link to="/measurements">
|
<Link to="/measurements">
|
||||||
<h2 className="text-lg font-semibold">Measurements</h2>
|
<h2 className={CLASSES.linkTitle}>Measurements</h2>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="md:col-span-2 space-y-4">
|
<div className={CLASSES.formSection}>
|
||||||
<form onSubmit={handleAddCustomerSubmit}>
|
<form onSubmit={handleAddCustomerSubmit}>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">
|
<label className={CLASSES.formGroup}>First Name:</label>
|
||||||
First Name:
|
|
||||||
</label>
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="firstname"
|
name="firstname"
|
||||||
value={customerData.firstname}
|
value={customerData.firstname}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="w-full p-2 border-b border-gray-400 focus:border-gray-700"
|
className={CLASSES.formInput}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">
|
<label className={CLASSES.formGroup}>Last Name:</label>
|
||||||
Last Name:
|
|
||||||
</label>
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="lastname"
|
name="lastname"
|
||||||
value={customerData.lastname}
|
value={customerData.lastname}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="w-full p-2 border-b border-gray-400 focus:border-gray-700"
|
className={CLASSES.formInput}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">
|
<label className={CLASSES.formGroup}>Age:</label>
|
||||||
Age:
|
|
||||||
</label>
|
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
name="age"
|
name="age"
|
||||||
value={customerData.age}
|
value={customerData.age}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="w-full p-2 border-b border-gray-400 focus:border-gray-700"
|
className={CLASSES.formInput}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">
|
<label className={CLASSES.formGroup}>Gender:</label>
|
||||||
Gender:
|
|
||||||
</label>
|
|
||||||
<select
|
<select
|
||||||
name="gender"
|
name="gender"
|
||||||
value={customerData.gender}
|
value={customerData.gender}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="w-full p-2 border-b border-gray-400 focus:border-gray-700"
|
className={CLASSES.formSelect}
|
||||||
>
|
>
|
||||||
<option value="" disabled>
|
<option value="" disabled>
|
||||||
Select Gender
|
Select Gender
|
||||||
@ -196,74 +238,62 @@ const AddCustomer = () => {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">
|
<label className={CLASSES.formGroup}>Email:</label>
|
||||||
Email:
|
|
||||||
</label>
|
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
name="email"
|
name="email"
|
||||||
value={customerData.email}
|
value={customerData.email}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="w-full p-2 border-b border-gray-400 focus:border-gray-700"
|
className={CLASSES.formInput}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">
|
<label className={CLASSES.formGroup}>Address Line 1:</label>
|
||||||
Address Line 1:
|
|
||||||
</label>
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="address_line_1"
|
name="address_line_1"
|
||||||
value={customerData.address_line_1}
|
value={customerData.address.address_line_1}
|
||||||
onChange={handleInputChange}
|
onChange={handleAddressChange}
|
||||||
className="w-full p-2 border-b border-gray-400 focus:border-gray-700"
|
className={CLASSES.formInput}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">
|
<label className={CLASSES.formGroup}>Address Line 2:</label>
|
||||||
Address Line 2:
|
|
||||||
</label>
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="address_line_2"
|
name="address_line_2"
|
||||||
value={customerData.address_line_2}
|
value={customerData.address.address_line_2}
|
||||||
onChange={handleInputChange}
|
onChange={handleAddressChange}
|
||||||
className="w-full p-2 border-b border-gray-400 focus:border-gray-700"
|
className={CLASSES.formInput}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">
|
<label className={CLASSES.formGroup}>Nearby Landmark:</label>
|
||||||
Nearby Landmark:
|
|
||||||
</label>
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="nearby_landmark"
|
name="nearby_landmark"
|
||||||
value={customerData.nearby_landmark}
|
value={customerData.address.nearby_landmark}
|
||||||
onChange={handleInputChange}
|
onChange={handleAddressChange}
|
||||||
className="w-full p-2 border-b border-gray-400 focus:border-gray-700"
|
className={CLASSES.formInput}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">
|
<label className={CLASSES.formGroup}>Pincode:</label>
|
||||||
Pincode:
|
|
||||||
</label>
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="pincode"
|
name="pincode"
|
||||||
value={customerData.pincode}
|
value={customerData.address.pincode}
|
||||||
onChange={handleInputChange}
|
onChange={handleAddressChange}
|
||||||
className="w-full p-2 border-b border-gray-400 focus:border-gray-700"
|
className={CLASSES.formInput}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">
|
<label className={CLASSES.formGroup}>City:</label>
|
||||||
City:
|
|
||||||
</label>
|
|
||||||
<select
|
<select
|
||||||
name="city_id"
|
name="city_id"
|
||||||
value={customerData.city_id}
|
value={customerData.address.city_id}
|
||||||
onChange={handleInputChange}
|
onChange={handleAddressChange}
|
||||||
className="w-full p-2 border-b border-gray-400 focus:border-gray-700"
|
className={CLASSES.formSelect}
|
||||||
>
|
>
|
||||||
<option value="" disabled>
|
<option value="" disabled>
|
||||||
Select City
|
Select City
|
||||||
@ -277,22 +307,17 @@ const AddCustomer = () => {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-gray-800 font-medium">
|
<label className={CLASSES.formGroup}>Mobile:</label>
|
||||||
Mobile:
|
|
||||||
</label>
|
|
||||||
<input
|
<input
|
||||||
type="tel"
|
type="tel"
|
||||||
name="mobile"
|
name="mobile"
|
||||||
value={customerData.mobile}
|
value={customerData.mobile}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="w-full p-2 border-b border-gray-400 focus:border-gray-700"
|
className={CLASSES.formInput}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<button
|
<button type="submit" className={CLASSES.submitButton}>
|
||||||
type="submit"
|
|
||||||
className="bg-[#0e355b] text-white py-2 px-4 rounded-md"
|
|
||||||
>
|
|
||||||
Add Customer
|
Add Customer
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,14 +9,14 @@ const CustomerList = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Fetch the customers data from the JSON file
|
|
||||||
getCustomers();
|
getCustomers();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getCustomers = async () => {
|
const getCustomers = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axiosInstance.get('http://localhost:5000/customers');
|
const response = await axiosInstance.get('http://localhost:5000/customers');
|
||||||
let customers_data = response.data; // List of customers
|
let customers_data = response.data;
|
||||||
setCustomers(customers_data);
|
setCustomers(customers_data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
@ -32,7 +32,7 @@ const CustomerList = () => {
|
|||||||
<Sidebar />
|
<Sidebar />
|
||||||
<div className="flex-grow p-6 bg-gray-100">
|
<div className="flex-grow p-6 bg-gray-100">
|
||||||
<div className="bg-white p-6 rounded-lg shadow">
|
<div className="bg-white p-6 rounded-lg shadow">
|
||||||
<div className="flex justify-between items-center mb-6">
|
<div className="flex justify-between items-center ">
|
||||||
<h1 className="text-2xl font-semibold text-gray-800">customers list</h1>
|
<h1 className="text-2xl font-semibold text-gray-800">customers list</h1>
|
||||||
<button
|
<button
|
||||||
className="bg-#0e355b text-#d1d5db px-4 py-2 rounded-md text-sm"
|
className="bg-#0e355b text-#d1d5db px-4 py-2 rounded-md text-sm"
|
||||||
@ -41,9 +41,9 @@ const CustomerList = () => {
|
|||||||
add new customer
|
add new customer
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center mb-4">
|
<div className="flex items-center ">
|
||||||
<svg
|
<svg
|
||||||
className="w-5 h-5 mr-2 text-gray-500"
|
className="w-5 h-5 text-gray-500"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@ -58,7 +58,7 @@ const CustomerList = () => {
|
|||||||
</svg>
|
</svg>
|
||||||
<span className="text-sm text-gray-600">filter</span>
|
<span className="text-sm text-gray-600">filter</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-gray-600 mb-4">total customers ({customers.length})</p>
|
<p className="text-sm text-gray-600 ">total customers ({customers.length})</p>
|
||||||
<table className="w-full bg-white">
|
<table className="w-full bg-white">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="text-left text-xs uppercase text-gray-600 border-b">
|
<tr className="text-left text-xs uppercase text-gray-600 border-b">
|
||||||
|
@ -1,77 +1,97 @@
|
|||||||
|
/* AddCustomer.css */
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-content {
|
.main-content {
|
||||||
flex: 1;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
color: #e8e8e8;
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-content {
|
||||||
|
min-height: 100vh;
|
||||||
|
color: #4a5568; /* text-gray-800 */
|
||||||
|
padding: 1.5rem; /* p-6 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-title {
|
.header-title {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-link {
|
.back-button {
|
||||||
color: #0e355b;
|
color: #0e355b;
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem; /* text-xl */
|
||||||
margin-right: 1rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-title {
|
.title {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem; /* text-2xl */
|
||||||
font-weight: 600;
|
font-weight: 600; /* font-semibold */
|
||||||
color: #0e355b;
|
color: #0e355b;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skip-link {
|
.skip-link {
|
||||||
color: #0e355b;
|
color: #1e3a8a; /* text-blue-900 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-content {
|
.form-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(1, 1fr);
|
||||||
|
gap: 1.5rem; /* gap-6 */
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.form-grid {
|
||||||
|
grid-template-columns: repeat(3, 1fr); /* md:grid-cols-3 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1.5rem;
|
gap: 1.5rem; /* space-y-6 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-upload-container {
|
.image-wrapper {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-container {
|
||||||
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 6rem;
|
|
||||||
height: 6rem;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-preview {
|
.image-preview {
|
||||||
background-color: #d1d5db;
|
background-color: #d1d5db; /* bg-gray-300 */
|
||||||
width: 100%;
|
width: 6rem; /* w-24 */
|
||||||
height: 100%;
|
height: 6rem; /* h-24 */
|
||||||
border-radius: 9999px;
|
border-radius: 50%;
|
||||||
|
margin: 0 auto; /* mx-auto */
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-preview img {
|
.no-image {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-image {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
color: #6b7280;
|
color: #6b7280; /* text-gray-500 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-input {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-button {
|
.upload-button {
|
||||||
@ -79,57 +99,50 @@
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
background-color: #0e355b;
|
background-color: #4b5563; /* bg-gray-700 */
|
||||||
color: #fff;
|
color: white;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem; /* text-xs */
|
||||||
padding: 0.5rem;
|
padding: 0.25rem 0.5rem;
|
||||||
border-radius: 9999px;
|
border-radius: 9999px; /* rounded-full */
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-title {
|
.link-title {
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem; /* text-lg */
|
||||||
font-weight: 600;
|
font-weight: 600; /* font-semibold */
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem; /* space-y-4 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group {
|
.form-group {
|
||||||
margin-bottom: 1rem;
|
color: #4a5568; /* text-gray-800 */
|
||||||
display: flex;
|
font-weight: 500; /* font-medium */
|
||||||
flex-direction: column;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-label {
|
.form-input {
|
||||||
display: underline;
|
width: 100%;
|
||||||
color: #4b5563;
|
padding: 0.5rem;
|
||||||
font-weight: 500;
|
border-bottom: 1px solid #cbd5e0; /* border-gray-400 */
|
||||||
|
&:focus {
|
||||||
|
border-color: #2d3748; /* border-gray-700 */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-input,
|
|
||||||
.form-select {
|
.form-select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
border: 1px solid #d1d5db;
|
border-bottom: 1px solid #cbd5e0; /* border-gray-400 */
|
||||||
border-radius: 0.375rem;
|
&:focus {
|
||||||
}
|
border-color: #2d3748; /* border-gray-700 */
|
||||||
|
}
|
||||||
.form-input:focus,
|
|
||||||
.form-select:focus {
|
|
||||||
border-color: #e8e8e8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.submit-button {
|
.submit-button {
|
||||||
background-color: #0e355b;
|
background-color: #0e355b;
|
||||||
color: #d1d5db;
|
color: white;
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
border-radius: 0.375rem;
|
border-radius: 0.375rem; /* rounded-md */
|
||||||
align-self: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-row {
|
|
||||||
display: flex;
|
|
||||||
gap: 1rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-row .form-group {
|
|
||||||
flex: 1;
|
|
||||||
}
|
}
|
||||||
|
20
src/styles/classNames.js
Normal file
20
src/styles/classNames.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
export const styles = {
|
||||||
|
container: 'flex flex-row',
|
||||||
|
content: 'w-full flex flex-col min-h-screen text-black',
|
||||||
|
header: 'min-h-screen text-secondary p-6 bg-light',
|
||||||
|
backButton: 'text-primary text-xl',
|
||||||
|
title: 'text-2xl font-semibold text-primary',
|
||||||
|
imageWrapper: 'bg-gray-300 w-24 h-24 rounded-full mx-auto overflow-hidden',
|
||||||
|
imagePreview: 'w-full h-full object-cover',
|
||||||
|
noImageText: 'w-full h-full flex items-center justify-center text-gray-500',
|
||||||
|
imageUploadButton: 'image-upload-btn',
|
||||||
|
form: 'space-y-4',
|
||||||
|
input: 'input-underline w-full p-2 focus-border',
|
||||||
|
button: 'btn-primary',
|
||||||
|
formGroup: 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4',
|
||||||
|
centerText: 'text-center',
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user