-
-
-
Product Details
- Full details of a product
-
-
- {/* /add */}
-
-
-
-
-
-
-
- -
-
Product
- Macbook pro
-
- -
-
Category
- Computers
-
- -
-
Sub Category
- None
-
- -
-
Brand
- None
-
- -
-
Unit
- Piece
-
- -
-
SKU
- PT0001
-
- -
-
Minimum Qty
- 5
-
- -
-
Quantity
- 50
-
- -
-
Tax
- 0.00 %
-
- -
-
Discount Type
- Percentage
-
- -
-
Price
- 1500.00
-
- -
-
Status
- Active
-
- -
-
Description
-
- Lorem Ipsum is simply dummy text of the printing and
- typesetting industry. Lorem Ipsum has been the industrys
- standard dummy text ever since the 1500s,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
macbookpro.jpg
- 581kb
-
-
-
-
-
-
-
-
- {/* /add */}
+ const { id } = useParams();
+
+ const [currentProduct, setCurrentProduct] = useState({});
+
+ useEffect(() => {
+ const fetchProduct = async () => {
+ try {
+ const response = await productsApi.getProductById(id);
+ setCurrentProduct(response.data);
+ } catch (error) {
+ console.error("Error fetching product:", error);
+ }
+ };
+
+ if (id) {
+ fetchProduct();
+ }
+ }, [id]);
+
+ return (
+
+
+
+
+
+
Product Details
+ Full details of a product
+
+
+ {/* /add */}
+
+
+
+
+
+
+
+ -
+
Product
+ {currentProduct?.name}
+
+ -
+
Category
+ {currentProduct?.category ?? "-"}
+
+ -
+
Business
+ {currentProduct?.business_type ?? "-"}
+
+ -
+
Unit
+ Piece
+
+ -
+
SKU
+ {currentProduct?.sku ?? "-"}
+
+ -
+
Price
+ {formatRupiah(Number(currentProduct?.price))}
+
+ -
+
Status
+
+ {currentProduct?.is_active ? (
+
+ Active
+
+ ) : (
+ "Inactive"
+ )}
+
+
+ -
+
Description
+ {currentProduct?.description ?? "-"}
+
+
+
+
+
+ {Array.isArray(currentProduct?.variants) && (
+
+
+
Variant Product Details
+ Full details of a variant product
+
+
+ )}
+
+ {Array.isArray(currentProduct?.variants) &&
+ currentProduct.variants.map((variant, index) => (
+
+
+
+
+ -
+
Variant
+ {variant?.name}
+
+ -
+
Price
+
+ {formatRupiah(Number(variant.price_modifier))}
+
+
+ -
+
Cost
+ {formatRupiah(Number(variant.cost))}
+
+
+
+
+
+ ))}
-
+
+
+
+
+
+
+
+
{currentProduct?.name}
+ 581kb
+
+
+
+
+
+
+
+ {/* /add */}
- )
-}
+
+
+ );
+};
-export default ProductDetail
+export default ProductDetail;
diff --git a/src/feature-module/inventory/productlist.jsx b/src/feature-module/inventory/productlist.jsx
index 155b087..e290ea0 100644
--- a/src/feature-module/inventory/productlist.jsx
+++ b/src/feature-module/inventory/productlist.jsx
@@ -1,36 +1,33 @@
+import { Select, Space } from "antd";
import {
- Box,
ChevronUp,
Edit,
Eye,
- Filter,
- GitMerge,
PlusCircle,
RotateCcw,
- Sliders,
- StopCircle,
Trash2,
} from "feather-icons-react/build/IconComponents";
-import React, { useState, useEffect } from "react";
+import { useEffect, useState } from "react";
+import { OverlayTrigger, Tooltip } from "react-bootstrap";
+import { Download } from "react-feather";
import { useDispatch, useSelector } from "react-redux";
import { Link } from "react-router-dom";
-import Select from "react-select";
+import Swal from "sweetalert2";
+import withReactContent from "sweetalert2-react-content";
+import CustomPagination from "../../components/CustomPagination";
import ImageWithBasePath from "../../core/img/imagewithbasebath";
import Brand from "../../core/modals/inventory/brand";
-import withReactContent from "sweetalert2-react-content";
-import Swal from "sweetalert2";
-import { all_routes } from "../../Router/all_routes";
-import { OverlayTrigger, Tooltip } from "react-bootstrap";
import Table from "../../core/pagination/datatable";
import { setToogleHeader } from "../../core/redux/action";
-import { Download } from "react-feather";
import {
- fetchProducts,
- fetchProduct,
+ clearProductError,
deleteProduct,
- clearProductError
+ fetchProduct,
+ fetchProducts,
} from "../../core/redux/actions/productActions";
-import CustomPagination from '../../components/CustomPagination';
+import { all_routes } from "../../Router/all_routes";
+import categoriesApi from "../../services/categoriesApi";
+import { formatRupiah } from "../../utils/currency";
// Add CSS animations for beautiful UI
const shimmerKeyframes = `
@@ -62,11 +59,16 @@ const shimmerKeyframes = `
`;
// Inject CSS into head if not already present
-if (typeof document !== 'undefined' && !document.getElementById('beautiful-pagination-styles')) {
- const styleSheet = document.createElement('style');
- styleSheet.id = 'beautiful-pagination-styles';
- styleSheet.type = 'text/css';
- styleSheet.innerText = shimmerKeyframes + `
+if (
+ typeof document !== "undefined" &&
+ !document.getElementById("beautiful-pagination-styles")
+) {
+ const styleSheet = document.createElement("style");
+ styleSheet.id = "beautiful-pagination-styles";
+ styleSheet.type = "text/css";
+ styleSheet.innerText =
+ shimmerKeyframes +
+ `
/* Hide all Ant Design pagination elements */
.ant-pagination,
.ant-pagination-item,
@@ -433,40 +435,24 @@ const ProductList = () => {
totalProducts,
totalPages,
pageSize: reduxPageSize,
- currentPage: reduxCurrentPage
+ currentPage: reduxCurrentPage,
} = useSelector((state) => state.products);
- // Fallback to legacy data if API data is not available
- const legacyProducts = useSelector((state) => state.legacy?.product_list || []);
- const dataSource = apiProducts.length > 0 ? apiProducts : legacyProducts;
+ const dataSource = apiProducts?.length > 0 ? apiProducts : [];
const dispatch = useDispatch();
const data = useSelector((state) => state.legacy?.toggle_header || false);
- const [isFilterVisible, setIsFilterVisible] = useState(false);
- const [searchTerm, setSearchTerm] = useState("");
-
-
-
// State for pagination - sync with Redux
const [currentPage, setCurrentPage] = useState(reduxCurrentPage || 1);
- const [pageSize, setPageSize] = useState(reduxPageSize || 20);
-
- // State for filter values
- const [filterValues, setFilterValues] = useState({
- product: '',
- category: '',
- subCategory: '',
- brand: '',
- priceRange: ''
- });
+ const [pageSize, setPageSize] = useState(reduxPageSize || 10);
+ const [searchTerm, setSearchTerm] = useState("");
+ const [category, setCategory] = useState(null);
// Debounced search term
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState("");
- const toggleFilterVisibility = () => {
- setIsFilterVisible((prevVisibility) => !prevVisibility);
- };
+ const [categoryOptions, setCategoryOptions] = useState([]);
const route = all_routes;
@@ -479,29 +465,51 @@ const ProductList = () => {
return () => clearTimeout(timer);
}, [searchTerm]);
+ useEffect(() => {
+ const loadCategories = async () => {
+ try {
+ const response = await categoriesApi.getAllCategories();
+ const categories = response?.data?.categories;
+ const formattedCategory = categories.map((item) => ({
+ value: item.id,
+ label: item.name,
+ }));
+
+ formattedCategory.unshift({ value: "", label: "All" });
+
+ setCategoryOptions(formattedCategory);
+ } catch (error) {
+ console.error("Failed to fetch categories", error);
+ }
+ };
+
+ loadCategories();
+ }, []);
+
// Fetch products when debounced search term or pagination changes
useEffect(() => {
const loadProducts = async () => {
try {
const searchParams = {
- Page: currentPage,
- PageSize: pageSize,
- SearchTerm: debouncedSearchTerm || ''
+ page: currentPage,
+ limit: pageSize,
+ search: debouncedSearchTerm || "",
+ category_id: category,
};
// Remove empty parameters
const cleanParams = Object.fromEntries(
- Object.entries(searchParams).filter(([, value]) => value !== '')
+ Object.entries(searchParams).filter(([, value]) => value !== "")
);
await dispatch(fetchProducts(cleanParams));
} catch (error) {
- console.error('Failed to load products:', error);
+ console.error("Failed to load products:", error);
}
};
loadProducts();
- }, [dispatch, currentPage, pageSize, debouncedSearchTerm]);
+ }, [dispatch, currentPage, pageSize, debouncedSearchTerm, category]);
// Handle product deletion
const handleDeleteProduct = async (productId) => {
@@ -518,7 +526,7 @@ const ProductList = () => {
},
});
} catch (error) {
- console.error('Failed to delete product:', error);
+ console.error("Failed to delete product:", error);
MySwal.fire({
title: "Error!",
text: "Failed to delete product. Please try again.",
@@ -542,74 +550,12 @@ const ProductList = () => {
// Handle pagination
const handlePageChange = (page) => {
setCurrentPage(page);
-
- // Dispatch action to fetch products for the new page
- const searchParams = {
- Page: page,
- PageSize: pageSize,
- SearchTerm: debouncedSearchTerm || ''
- };
-
- // Remove empty parameters
- const cleanParams = Object.fromEntries(
- Object.entries(searchParams).filter(([, value]) => value !== '')
- );
-
- dispatch(fetchProducts(cleanParams));
};
// Handle page size change
const handlePageSizeChange = (newPageSize) => {
setPageSize(newPageSize);
setCurrentPage(1); // Reset to first page when changing page size
-
- // Dispatch action to fetch products with new page size
- const searchParams = {
- Page: 1,
- PageSize: newPageSize,
- SearchTerm: debouncedSearchTerm || ''
- };
-
- // Remove empty parameters
- const cleanParams = Object.fromEntries(
- Object.entries(searchParams).filter(([, value]) => value !== '')
- );
-
- dispatch(fetchProducts(cleanParams));
- };
-
- // Handle filter value changes
- const handleFilterChange = (filterType, value) => {
- setFilterValues(prev => ({
- ...prev,
- [filterType]: value
- }));
- };
-
- // Handle search with filters
- const handleSearchWithFilters = () => {
- setCurrentPage(1); // Reset to first page when searching
-
- // Combine search term with filter values
- const searchParams = {
- Page: 1,
- PageSize: pageSize,
- SearchTerm: debouncedSearchTerm || '',
- // Map filter values to API expected parameters
- ProductName: filterValues.product || '',
- Category: filterValues.category || '',
- SubCategory: filterValues.subCategory || '',
- Brand: filterValues.brand || '',
- PriceRange: filterValues.priceRange || ''
- };
-
- // Remove empty parameters to clean up API call
- const cleanParams = Object.fromEntries(
- Object.entries(searchParams).filter(([, value]) => value !== '')
- );
-
- console.log('Search with filters (clean params):', cleanParams);
- dispatch(fetchProducts(cleanParams));
};
// Calculate pagination info
@@ -617,85 +563,73 @@ const ProductList = () => {
const calculatedTotalPages = Math.ceil(totalRecords / pageSize);
const actualTotalPages = totalPages || calculatedTotalPages;
- // Debug logs removed for production
-
// Clear error when component unmounts
useEffect(() => {
return () => {
dispatch(clearProductError());
};
}, [dispatch]);
+
const options = [
- { value: "sortByDate", label: "Sort by Date" },
- { value: "140923", label: "14 09 23" },
- { value: "110923", label: "11 09 23" },
+ { label: "Sort By: Last 7 Days", value: "last7days" },
+ { label: "Sort By: Last Month", value: "lastmonth" },
+ { label: "Sort By: Ascending", value: "ascending" },
+ { label: "Sort By: Descending", value: "descending" },
];
- // Removed unused select option arrays since we're using simple inputs now
const columns = [
{
- title: "Sản phẩm",
- dataIndex: "product",
- render: (text, record) => (
-
-
-
-
- {text}
-
- ),
- sorter: (a, b) => a.product.length - b.product.length,
- },
- {
- title: "Mã",
+ title: "SKU",
dataIndex: "sku",
render: (_, record) => {
- const sku = record.sku || record.code || record.productCode || '-';
+ const sku = record.sku || record.code || record.productCode || "-";
return
{sku};
},
sorter: (a, b) => {
- const skuA = a.sku || a.code || a.productCode || '';
- const skuB = b.sku || b.code || b.productCode || '';
+ const skuA = a.sku || a.code || a.productCode || "";
+ const skuB = b.sku || b.code || b.productCode || "";
return skuA.length - skuB.length;
},
},
-
{
- title: "Danh mục",
+ title: "Product",
+ dataIndex: "product",
+ render: (text, record) =>
{record.name},
+ sorter: (a, b) => a.product.length - b.product.length,
+ },
+ {
+ title: "Category",
dataIndex: "category",
render: (_, record) => {
- const category = record.category || record.categoryName || '-';
+ const category = record.category || record.categoryName || "-";
return
{category};
},
sorter: (a, b) => {
- const catA = a.category || a.categoryName || '';
- const catB = b.category || b.categoryName || '';
+ const catA = a.category || a.categoryName || "";
+ const catB = b.category || b.categoryName || "";
return catA.length - catB.length;
},
},
{
- title: "Thương hiệu",
- dataIndex: "brand",
+ title: "Business",
+ dataIndex: "business",
render: (_, record) => {
- const brand = record.brand || record.brandName || '-';
+ const brand = record.business_type || record.brandName || "-";
return
{brand};
},
sorter: (a, b) => {
- const brandA = a.brand || a.brandName || '';
- const brandB = b.brand || b.brandName || '';
+ const brandA = a.brand || a.brandName || "";
+ const brandB = b.brand || b.brandName || "";
return brandA.length - brandB.length;
},
},
{
- title: "Giá",
+ title: "Price",
dataIndex: "price",
render: (_, record) => {
const price = record.price || record.salePrice || record.unitPrice || 0;
- return
${Number(price).toFixed(2)};
+ return
{formatRupiah(Number(price))};
},
sorter: (a, b) => {
const priceA = Number(a.price || a.salePrice || a.unitPrice || 0);
@@ -704,15 +638,15 @@ const ProductList = () => {
},
},
{
- title: "Đơn vị",
+ title: "Unit",
dataIndex: "unit",
render: (_, record) => {
- const unit = record.unit || record.unitOfMeasure || '-';
+ const unit = record.unit || record.unitOfMeasure || "-";
return
{unit};
},
sorter: (a, b) => {
- const unitA = a.unit || a.unitOfMeasure || '';
- const unitB = b.unit || b.unitOfMeasure || '';
+ const unitA = a.unit || a.unitOfMeasure || "";
+ const unitB = b.unit || b.unitOfMeasure || "";
return unitA.length - unitB.length;
},
},
@@ -721,7 +655,12 @@ const ProductList = () => {
dataIndex: "qty",
render: (_, record) => {
// Try multiple possible field names for quantity
- const quantity = record.qty || record.quantity || record.stock || record.stockQuantity || 0;
+ const quantity =
+ record.qty ||
+ record.quantity ||
+ record.stock ||
+ record.stockQuantity ||
+ 0;
return
{quantity};
},
sorter: (a, b) => {
@@ -732,11 +671,14 @@ const ProductList = () => {
},
{
- title: "Người tạo",
+ title: "Created By",
dataIndex: "createdby",
render: (text, record) => (
-
+
{record.createdBy || text || "Admin"}
@@ -744,14 +686,17 @@ const ProductList = () => {
sorter: (a, b) => a.createdby.length - b.createdby.length,
},
{
- title: "Thao tác",
+ title: "Action",
dataIndex: "action",
render: (text, record) => (
-
-
+
+
{
];
const MySwal = withReactContent(Swal);
- // Removed showConfirmationAlert as we handle confirmation inline
-
const renderTooltip = (props) => (
Pdf
@@ -822,14 +765,15 @@ const ProductList = () => {
Collapse
);
+
return (
- Danh sách sản phẩm
- Quản lý sản phẩm
+ Product List
+ Manage your products
@@ -884,18 +828,17 @@ const ProductList = () => {
- Thêm mới
+ Add New Product
-
- Nhập sản phẩm
+
+ Import Product
@@ -917,291 +860,28 @@ const ProductList = () => {
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
- {/* /Filter */}
-
- {/* /Filter */}
+
{loading ? (
diff --git a/src/feature-module/pages/login/signin.jsx b/src/feature-module/pages/login/signin.jsx
index e15d235..930436b 100644
--- a/src/feature-module/pages/login/signin.jsx
+++ b/src/feature-module/pages/login/signin.jsx
@@ -1,16 +1,47 @@
-import React from "react";
+import React, { useState } from "react";
+import { useSelector } from "react-redux";
+import { Link, useNavigate } from "react-router-dom";
import ImageWithBasePath from "../../../core/img/imagewithbasebath";
-import { Link } from "react-router-dom";
import { all_routes } from "../../../Router/all_routes";
+import authApi from "../../../services/authApi";
const Signin = () => {
const route = all_routes;
+ const navigate = useNavigate();
+ // const dispatch = useDispatch();
+ const authState = useSelector((state) => state.auth);
+
+ const [formData, setFormData] = useState({
+ email: '',
+ password: ''
+ });
+ const [error, setError] = useState('');
+
+ const handleInputChange = (e) => {
+ setFormData({
+ ...formData,
+ [e.target.name]: e.target.value
+ });
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ setError('');
+
+ try {
+ await authApi.login(formData);
+ navigate(route.dashboard);
+ } catch (error) {
+ setError(error.message || 'Login failed');
+ }
+ };
+
return (
@@ -100,10 +106,10 @@ const Profile = () => {
-
+
Submit
-
+
Cancel
diff --git a/src/feature-module/sales/saleslist.jsx b/src/feature-module/sales/saleslist.jsx
index 76864ce..a002998 100644
--- a/src/feature-module/sales/saleslist.jsx
+++ b/src/feature-module/sales/saleslist.jsx
@@ -1,2386 +1,1522 @@
-import React, { useState } from 'react'
-import { OverlayTrigger, Tooltip } from 'react-bootstrap';
-import { Link } from 'react-router-dom'
-import ImageWithBasePath from '../../core/img/imagewithbasebath';
-import { ChevronUp, FileText, PlusCircle, RotateCcw, Sliders, StopCircle, User } from 'feather-icons-react/build/IconComponents';
-import { setToogleHeader } from '../../core/redux/action';
-import { useDispatch, useSelector } from 'react-redux';
-import { Filter } from 'react-feather';
-import Select from 'react-select';
-import { DatePicker } from 'antd';
+import { DatePicker, Space, Select as AntSelect } from "antd";
+import {
+ ChevronUp,
+ PlusCircle,
+ RotateCcw,
+} from "feather-icons-react/build/IconComponents";
+import { useEffect, useState } from "react";
+import { OverlayTrigger, Tooltip } from "react-bootstrap";
+import { useDispatch, useSelector } from "react-redux";
+import { Link } from "react-router-dom";
+import Select from "react-select";
+import CustomPagination from "../../components/CustomPagination";
+import ImageWithBasePath from "../../core/img/imagewithbasebath";
+import { setToogleHeader } from "../../core/redux/action";
+import {
+ clearOrderError,
+ fetchOrders,
+} from "../../core/redux/actions/orderActions";
+import { formatRupiah } from "../../utils/currency";
+import { formatDate } from "../../utils/date";
const SalesList = () => {
- const dispatch = useDispatch();
- const data = useSelector((state) => state.toggle_header);
- const [isFilterVisible, setIsFilterVisible] = useState(false);
+ const {
+ orders: apiOrders,
+ loading,
+ error,
+ totalOrders,
+ totalPages,
+ pageSize: reduxPageSize,
+ currentPage: reduxCurrentPage,
+ } = useSelector((state) => state.orders);
- const toggleFilterVisibility = () => {
- setIsFilterVisible((prevVisibility) => !prevVisibility);
- };
- const oldandlatestvalue = [
- { value: 'Sort by Date', label: 'Sort by Date' },
- { value: '07 09 23', label: '07 09 23' },
- { value: '21 09 23', label: '21 09 23' },
- ];
- const customername = [
- { value: 'Choose Customer Name', label: 'Choose Customer Name' },
- { value: 'Macbook pro', label: 'Macbook pro' },
- { value: 'Orange', label: 'Orange' },
- ];
- const status = [
- { value: 'Choose Status', label: 'Choose Status' },
- { value: 'Computers', label: 'Computers' },
- { value: 'Fruits', label: 'Fruits' },
- ];
- const paymentstatus = [
- { value: 'Choose Payment Status', label: 'Choose Payment Status' },
- { value: 'Computers', label: 'Computers' },
- { value: 'Fruits', label: 'Fruits' },
- ];
- const customer = [
- { value: 'Choose Customer', label: 'Choose Customer' },
- { value: 'Customer Name', label: 'Customer Name' },
- ];
- const suppliername = [
- { value: 'Supplier', label: 'Supplier' },
- { value: 'Supplier Name', label: 'Supplier Name' },
- ];
- const statusupdate = [
- { value: 'Supplier', label: 'Choose' },
- { value: 'Completed', label: 'Completed' },
- { value: 'InProgress', label: 'InProgress' },
- ];
- const paymenttype = [
- { value: 'Choose', label: 'Choose' },
- { value: 'Cash', label: 'Cash' },
- { value: 'Online', label: 'Online' },
- ];
- const [selectedDate, setSelectedDate] = useState(new Date());
- const handleDateChange = (date) => {
- setSelectedDate(date);
+ const dispatch = useDispatch();
+ const data = useSelector((state) => state.toggle_header);
+
+ const dataSource = apiOrders?.length > 0 ? apiOrders : [];
+
+ const [currentPage, setCurrentPage] = useState(reduxCurrentPage || 1);
+ const [pageSize, setPageSize] = useState(reduxPageSize || 10);
+ const [searchTerm, setSearchTerm] = useState("");
+ const [debouncedSearchTerm, setDebouncedSearchTerm] = useState("");
+ const [orderStatus, setOrderStatus] = useState(null);
+
+ useEffect(() => {
+ const loadOrders = async () => {
+ try {
+ const searchParams = {
+ page: currentPage,
+ limit: pageSize,
+ search: debouncedSearchTerm || "",
+ status: orderStatus,
+ };
+
+ // Remove empty parameters
+ const cleanParams = Object.fromEntries(
+ Object.entries(searchParams).filter(([, value]) => value !== "")
+ );
+
+ await dispatch(fetchOrders(cleanParams));
+ } catch (error) {
+ console.error("Failed to fetch orders", error);
+ }
};
+ loadOrders();
+ }, [dispatch, currentPage, pageSize, debouncedSearchTerm, orderStatus]);
- const renderTooltip = (props) => (
-
- Pdf
-
- );
- const renderExcelTooltip = (props) => (
-
- Excel
-
- );
- const renderPrinterTooltip = (props) => (
-
- Printer
-
- );
- const renderRefreshTooltip = (props) => (
-
- Refresh
-
- );
- const renderCollapseTooltip = (props) => (
-
- Collapse
-
- )
- return (
-
-
-
-
-
-
- Sales List
- Manage Your Sales
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ setDebouncedSearchTerm(searchTerm);
+ }, 500); // 500ms delay
-
-
-
-
-
- -
-
+ return () => clearTimeout(timer);
+ }, [searchTerm]);
-
-
-
-
-
- -
-
+ // Handle search
+ const handleSearch = (e) => {
+ const value = e.target.value;
+ setSearchTerm(value);
+ // Reset to first page when searching
+ setCurrentPage(1);
+ };
- { dispatch(setToogleHeader(!data)) }}
- >
-
-
-
-
-
-
-
+ const handleFilterStatus = (e) => {
+ const value = e.target.value;
+ setOrderStatus(value);
-
- Add New Sales
-
-
-
- {/* /product list */}
-
-
-
- {/* /Filter */}
-
- {/* /Filter */}
-
-
-
- {/* /product list */}
-
+ const paymentStatus = [
+ { value: "", label: "All" },
+ { value: "pending", label: "Pending" },
+ { value: "completed", label: "Completed" },
+ { value: "cancelled", label: "Cancelled" },
+ ];
+ const customer = [
+ { value: "Choose Customer", label: "Choose Customer" },
+ { value: "Customer Name", label: "Customer Name" },
+ ];
+ const suppliername = [
+ { value: "Supplier", label: "Supplier" },
+ { value: "Supplier Name", label: "Supplier Name" },
+ ];
+ const statusupdate = [
+ { value: "Supplier", label: "Choose" },
+ { value: "Completed", label: "Completed" },
+ { value: "InProgress", label: "InProgress" },
+ ];
+ const paymenttype = [
+ { value: "Choose", label: "Choose" },
+ { value: "Cash", label: "Cash" },
+ { value: "Online", label: "Online" },
+ ];
+ const badgeColors = {
+ pending: "primary",
+ completed: "success",
+ cancelled: "danger",
+ };
+
+ const options = [
+ { label: "Sort By: Last 7 Days", value: "last7days" },
+ { label: "Sort By: Last Month", value: "lastmonth" },
+ { label: "Sort By: Ascending", value: "ascending" },
+ { label: "Sort By: Descending", value: "descending" },
+ ];
+
+ const [selectedDate, setSelectedDate] = useState(new Date());
+ const handleDateChange = (date) => {
+ setSelectedDate(date);
+ };
+
+ const renderTooltip = (props) => (
+
+ Pdf
+
+ );
+ const renderExcelTooltip = (props) => (
+
+ Excel
+
+ );
+ const renderPrinterTooltip = (props) => (
+
+ Printer
+
+ );
+ const renderRefreshTooltip = (props) => (
+
+ Refresh
+
+ );
+ const renderCollapseTooltip = (props) => (
+
+ Collapse
+
+ );
+
+ return (
+
+
+
+
+
+
+ Sales List
+ Manage Your Sales
+
- <>
- {/*add popup */}
-
-
-
-
-
-
-
- Add Sales
-
-
-
-
-
-
-
-
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+ {
+ dispatch(setToogleHeader(!data));
+ }}
+ >
+
+
+
+
+
+
+
+ {/* /product list */}
+
+
+
+
- {/* /add popup */}
- {/* details popup */}
-
-
-
-
-
-
-
-
- Sales Detail : SL0101
-
-
-
-
- Add New
- Sales
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- {/* /details popup */}
- {/* edit popup */}
-
-
-
-
-
-
-
-
- Edit Sales
-
-
-
-
-
-
-
-
+
+ option.value === orderStatus
+ ) || null
+ }
+ onChange={handleFilterStatus}
+ />
+
+
+
+
+
+
+ {loading ? (
+
- {/* /edit popup */}
- {/* show payment Modal */}
-
-
-
-
-
-
-
- Show Payments
-
-
-
-
-
-
-
-
-
-
-
- | Date |
- Reference |
- Amount |
- Paid By |
- Action |
-
-
-
-
- | 19 Jan 2023 |
- INV/SL0101 |
- $1500 |
- Cash |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* show payment Modal */}
- {/* Create payment Modal */}
-
-
-
-
-
- Create Payments
-
-
+ ) : error ? (
+
+ Error: {error}
+
+
+ ) : (
+ <>
+
+
+
+ |
+
+ |
+ Customer Name |
+ Reference |
+ Date |
+ Status |
+ Total Amount |
+ Discount Amount |
+ Table Number |
+ Action |
+
+
+
+ {dataSource &&
+ dataSource.map((item, index) => (
+
+ |
+
+ |
+ {item.metadata?.customer_name} |
+ {item.order_number} |
+ {formatDate(item.created_at)} |
+
+
- ×
-
-
-
-
-
-
-
-
- {/* Create payment Modal */}
- {/* edit payment Modal */}
- |
+ {formatRupiah(item.total_amount)} |
+ {formatRupiah(item.discount_amount)} |
+ {item.table_number ?? 0} |
+
+
- ×
-
-
-
-
-
-
-
-
- {/* edit payment Modal */}
-
- >
+
+
+
+ -
+
+
+ Sale Detail
+
+
+ -
+
+
+ Edit Sale
+
+
+ -
+
+
+ Show Payments
+
+
+ -
+
+
+ Create Payment
+
+
+ -
+
+
+ Download pdf
+
+
+ -
+
+
+ Delete Sale
+
+
+
+ |
+
+ ))}
+
+
+
+ >
+ )}
+
+
+
+ {/* /product list */}
- )
-}
+
+ <>
+ {/*add popup */}
+
+
+
+
+
+
+
+ Add Sales
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* /add popup */}
+ {/* details popup */}
+
+
+
+
+
+
+ Sales Detail
+
+
+
+
+
+ Customer Info
+ Carl Evans
+
+ 3103 Trainer Avenue Peoria, IL 61602
+
+
+ Email: carlevans241@example.com
+
+
+ Phone: +1 987 471 6589
+
+
+
+ Company Info
+ DGT
+
+ 2077 Chicago Avenue Orosi, CA 93647
+
+
+ Email: admin@example.com
+
+
+ Phone: +1 893 174 0385
+
+
+
+ Invoice Info
+
+ Reference:{" "}
+
+ #SL0101
+
+
+ Date: Dec 24, 2024
+
+ Status:{" "}
+ Completed
+
+
+ Payment Status:{" "}
+
+ Paid
+
+
+
+
+
+ Order Summary
+
+
+
+
+
+ | Product |
+ Purchase Price($) |
+ Discount($) |
+ Tax(%) |
+ Tax Amount($) |
+ Unit Cost($) |
+ Total Cost(%) |
+
+
+
+
+
+ {" "}
+ Nike Jordan
+ |
+ 2000 |
+ 500 |
+ 0.00 |
+ 0.00 |
+ 0.00 |
+ 1500 |
+
+
+
+ {" "}
+ Apple Series 5 Watch
+ |
+ 3000 |
+ 400 |
+ 0.00 |
+ 0.00 |
+ 0.00 |
+ 1700 |
+
+
+
+ {" "}
+ Lobar Handy
+ |
+ 2500 |
+ 500 |
+ 0.00 |
+ 0.00 |
+ 0.00 |
+ 2000 |
+
+
+
+
+
+
+
+
+
+
+ | Order Tax |
+ $ 0.00 |
+
+
+ | Discount |
+ $ 0.00 |
+
+
+ | Grand Total |
+ $ 5200.00 |
+
+
+ | Paid |
+ $ 5200.00 |
+
+
+ | Due |
+ $ 0.00 |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* /details popup */}
+ {/* edit popup */}
+
+
+
+
+
+
+
+
+ Edit Sales
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* /edit popup */}
+ {/* show payment Modal */}
+
+
+
+
+
+
+
+ Show Payments
+
+
+
+
+
+
+
+
+
+
+
+ | Date |
+ Reference |
+ Amount |
+ Paid By |
+ Action |
+
+
+
+
+ | 19 Jan 2023 |
+ INV/SL0101 |
+ $1500 |
+ Cash |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* show payment Modal */}
+ {/* Create payment Modal */}
+
+
+
+
+
+ Create Payments
+
+
+
+
+
+
+
+
+
+ {/* Create payment Modal */}
+ {/* edit payment Modal */}
+
+
+
+
+
+ Edit Payments
+
+
+
+
+
+
+
+
+
+ {/* edit payment Modal */}
+
+ >
+
+ );
+};
+
+export default SalesList;
diff --git a/src/feature-module/usermanagement/users.jsx b/src/feature-module/usermanagement/users.jsx
index 3867a82..14084d2 100644
--- a/src/feature-module/usermanagement/users.jsx
+++ b/src/feature-module/usermanagement/users.jsx
@@ -1,354 +1,396 @@
-import React, { useState } from 'react'
-import { OverlayTrigger, Tooltip } from 'react-bootstrap';
-import { Link } from 'react-router-dom';
-import ImageWithBasePath from '../../core/img/imagewithbasebath';
-import { ChevronUp, RotateCcw } from 'feather-icons-react/build/IconComponents';
-import { setToogleHeader } from '../../core/redux/action';
-import { useDispatch, useSelector } from 'react-redux';
-import { Filter, PlusCircle, Sliders, StopCircle, User, Zap } from 'react-feather';
-import Select from 'react-select';
-import withReactContent from 'sweetalert2-react-content';
-import Swal from 'sweetalert2';
-import Table from '../../core/pagination/datatable'
-import AddUsers from '../../core/modals/usermanagement/addusers';
-import EditUser from '../../core/modals/usermanagement/edituser';
-
+import React, { useEffect, useState } from "react";
+import { OverlayTrigger, Tooltip } from "react-bootstrap";
+import { Link } from "react-router-dom";
+import ImageWithBasePath from "../../core/img/imagewithbasebath";
+import { ChevronUp, RotateCcw } from "feather-icons-react/build/IconComponents";
+import { setToogleHeader } from "../../core/redux/action";
+import { useDispatch, useSelector } from "react-redux";
+import {
+ Filter,
+ PlusCircle,
+ Sliders,
+ StopCircle,
+ User,
+ Zap,
+} from "react-feather";
+import Select from "react-select";
+import withReactContent from "sweetalert2-react-content";
+import Swal from "sweetalert2";
+import Table from "../../core/pagination/datatable";
+import AddUsers from "../../core/modals/usermanagement/addusers";
+import EditUser from "../../core/modals/usermanagement/edituser";
+import usersApi from "../../services/usersApi";
const Users = () => {
+ const oldandlatestvalue = [
+ { value: "date", label: "Sort by Date" },
+ { value: "newest", label: "Newest" },
+ { value: "oldest", label: "Oldest" },
+ ];
+ const users = [
+ { value: "Choose Name", label: "Choose Name" },
+ { value: "Lilly", label: "Lilly" },
+ { value: "Benjamin", label: "Benjamin" },
+ ];
+ const status = [
+ { value: "Choose Name", label: "Choose Status" },
+ { value: "Active", label: "Active" },
+ { value: "InActive", label: "InActive" },
+ ];
+ const role = [
+ { value: "Choose Role", label: "Choose Role" },
+ { value: "AcStore Keeper", label: "Store Keeper" },
+ { value: "Salesman", label: "Salesman" },
+ ];
- const oldandlatestvalue = [
- { value: 'date', label: 'Sort by Date' },
- { value: 'newest', label: 'Newest' },
- { value: 'oldest', label: 'Oldest' },
- ];
- const users = [
- { value: 'Choose Name', label: 'Choose Name' },
- { value: 'Lilly', label: 'Lilly' },
- { value: 'Benjamin', label: 'Benjamin' },
- ];
- const status = [
- { value: 'Choose Name', label: 'Choose Status' },
- { value: 'Active', label: 'Active' },
- { value: 'InActive', label: 'InActive' },
- ];
- const role = [
- { value: 'Choose Role', label: 'Choose Role' },
- { value: 'AcStore Keeper', label: 'Store Keeper' },
- { value: 'Salesman', label: 'Salesman' },
- ];
+ const dispatch = useDispatch();
+ const data = useSelector((state) => state.toggle_header);
+ const [dataSource, setDataSource] = useState([])
+ const [isFilterVisible, setIsFilterVisible] = useState(false);
+ const toggleFilterVisibility = () => {
+ setIsFilterVisible((prevVisibility) => !prevVisibility);
+ };
+ useEffect(() => {
+ const loadUsers = async () => {
+ try {
+ const response = await usersApi.getAllUsers();
+ setDataSource(response)
- const dispatch = useDispatch();
- const data = useSelector((state) => state.toggle_header);
- const dataSource = useSelector((state) => state.userlist_data);
- const [isFilterVisible, setIsFilterVisible] = useState(false);
- const toggleFilterVisibility = () => {
- setIsFilterVisible((prevVisibility) => !prevVisibility);
+ console.log('response', response)
+ } catch (error) {
+ console.error("Failed to fetch users", error);
+ }
};
- const renderTooltip = (props) => (
-
- Pdf
-
- );
- const renderExcelTooltip = (props) => (
-
- Excel
-
- );
- const renderPrinterTooltip = (props) => (
-
- Printer
-
- );
- const renderRefreshTooltip = (props) => (
-
- Refresh
-
- );
- const renderCollapseTooltip = (props) => (
-
- Collapse
-
- )
+ loadUsers();
+ }, []);
- const columns = [
+ const renderTooltip = (props) => (
+
+ Pdf
+
+ );
+ const renderExcelTooltip = (props) => (
+
+ Excel
+
+ );
+ const renderPrinterTooltip = (props) => (
+
+ Printer
+
+ );
+ const renderRefreshTooltip = (props) => (
+
+ Refresh
+
+ );
+ const renderCollapseTooltip = (props) => (
+
+ Collapse
+
+ );
- {
- title: "User Name",
- dataIndex: "username",
- render: (text, record) => (
-
-
-
-
-
- {text}
-
-
- ),
- sorter: (a, b) => a.username.length - b.username.length,
- },
+ const columns = [
+ {
+ title: "User Name",
+ dataIndex: "username",
+ render: (text, record) => (
+
+
+
+
+
+ {text}
+
+
+ ),
+ sorter: (a, b) => a.username.length - b.username.length,
+ },
- {
- title: "Phone",
- dataIndex: "phone",
- sorter: (a, b) => a.phone.length - b.phone.length,
- },
- {
- title: "Email",
- dataIndex: "email",
- sorter: (a, b) => a.email.length - b.email.length,
- },
- {
- title: "Role",
- dataIndex: "role",
- sorter: (a, b) => a.role.length - b.role.length,
- },
- {
- title: "Created On",
- dataIndex: "createdon",
- sorter: (a, b) => a.createdon.length - b.createdon.length,
- },
- {
- title: "Status",
- dataIndex: "status",
- render: (text) => (
-
- {text === "Active" && (
- {text}
- )}
- {text === "Inactive" && (
- {text}
- )}
-
-
- ),
- sorter: (a, b) => a.status.length - b.status.length,
- },
- {
- title: 'Actions',
- dataIndex: 'actions',
- key: 'actions',
- render: () => (
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
- )
- },
- ]
- const MySwal = withReactContent(Swal);
-
- const showConfirmationAlert = () => {
- MySwal.fire({
- title: 'Are you sure?',
- text: 'You won\'t be able to revert this!',
- showCancelButton: true,
- confirmButtonColor: '#00ff00',
- confirmButtonText: 'Yes, delete it!',
- cancelButtonColor: '#ff0000',
- cancelButtonText: 'Cancel',
- }).then((result) => {
- if (result.isConfirmed) {
-
- MySwal.fire({
- title: 'Deleted!',
- text: 'Your file has been deleted.',
- className: "btn btn-success",
- confirmButtonText: 'OK',
- customClass: {
- confirmButton: 'btn btn-success',
- },
- });
- } else {
- MySwal.close();
- }
-
- });
- };
- return (
+ {
+ title: "Phone",
+ dataIndex: "phone",
+ sorter: (a, b) => a.phone.length - b.phone.length,
+ },
+ {
+ title: "Email",
+ dataIndex: "email",
+ sorter: (a, b) => a.email.length - b.email.length,
+ },
+ {
+ title: "Role",
+ dataIndex: "role",
+ sorter: (a, b) => a.role.length - b.role.length,
+ },
+ {
+ title: "Created On",
+ dataIndex: "createdon",
+ sorter: (a, b) => a.createdon.length - b.createdon.length,
+ },
+ {
+ title: "Status",
+ dataIndex: "status",
+ render: (text) => (
-
-
-
-
-
- User List
- Manage Your Users
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
- { dispatch(setToogleHeader(!data)) }}
- >
-
-
-
-
-
-
-
- {/* /product list */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* /Filter */}
-
- {/* /Filter */}
-
-
-
- {/* /product list */}
-
-
-
-
+ {text === "Active" && (
+ {text}
+ )}
+ {text === "Inactive" && (
+ {text}
+ )}
- )
-}
+ ),
+ sorter: (a, b) => a.status.length - b.status.length,
+ },
+ {
+ title: "Actions",
+ dataIndex: "actions",
+ key: "actions",
+ render: () => (
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+ ),
+ },
+ ];
+ const MySwal = withReactContent(Swal);
-export default Users
+ const showConfirmationAlert = () => {
+ MySwal.fire({
+ title: "Are you sure?",
+ text: "You won't be able to revert this!",
+ showCancelButton: true,
+ confirmButtonColor: "#00ff00",
+ confirmButtonText: "Yes, delete it!",
+ cancelButtonColor: "#ff0000",
+ cancelButtonText: "Cancel",
+ }).then((result) => {
+ if (result.isConfirmed) {
+ MySwal.fire({
+ title: "Deleted!",
+ text: "Your file has been deleted.",
+ className: "btn btn-success",
+ confirmButtonText: "OK",
+ customClass: {
+ confirmButton: "btn btn-success",
+ },
+ });
+ } else {
+ MySwal.close();
+ }
+ });
+ };
+ return (
+
+
+
+
+
+
+ User List
+ Manage Your Users
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+ {
+ dispatch(setToogleHeader(!data));
+ }}
+ >
+
+
+
+
+
+
+
+ {/* /product list */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* /Filter */}
+
+ {/* /Filter */}
+
+
+
+ {/* /product list */}
+
+
+
+
+
+ );
+};
+
+export default Users;
diff --git a/src/index.js b/src/index.js
index 26734a2..ff812cd 100644
--- a/src/index.js
+++ b/src/index.js
@@ -15,6 +15,7 @@ import '../src/style/icons/fontawesome/css/all.min.css'
import { Provider } from "react-redux";
import store from "./core/redux/store.jsx";
import AllRoutes from "./Router/router.jsx";
+import authApi from "./services/authApi";
const rootElement = document.getElementById('root');
@@ -49,6 +50,9 @@ const initializeTheme = () => {
// Initialize theme before rendering
initializeTheme();
+// Check authentication status on app startup
+authApi.checkAuthStatus();
+
if (rootElement) {
diff --git a/src/services/api.js b/src/services/api.js
index 9b939d0..f0e9150 100644
--- a/src/services/api.js
+++ b/src/services/api.js
@@ -41,6 +41,7 @@ api.interceptors.response.use(
// Unauthorized - redirect to login or refresh token
localStorage.removeItem('authToken');
// You can add redirect logic here
+ window.location.href = '/signin';
} else if (error.response?.status === 500) {
// Server error
console.error('Server Error:', error.response.data);
diff --git a/src/services/authApi.js b/src/services/authApi.js
new file mode 100644
index 0000000..08b7ffa
--- /dev/null
+++ b/src/services/authApi.js
@@ -0,0 +1,64 @@
+import { store } from '../core/redux/store';
+import { loginStart, loginSuccess, loginFailure, logout, checkAuth } from '../core/redux/reducers/authReducer';
+import api from './api';
+
+const ENDPOINTS = {
+ LOGIN: 'auth/login',
+ LOGOUT: 'auth/logout',
+};
+
+export const authApi = {
+ // Check if user is authenticated
+ isAuthenticated() {
+ const token = localStorage.getItem('authToken');
+ const user = localStorage.getItem('user');
+ return !!(token && user);
+ },
+
+ // Get current user
+ getCurrentUser() {
+ const user = localStorage.getItem('user');
+ return user ? JSON.parse(user) : null;
+ },
+
+ // Get auth token
+ getToken() {
+ return localStorage.getItem('authToken');
+ },
+
+ // Login function
+ async login(credentials) {
+ try {
+ store.dispatch(loginStart());
+
+ const response = await api.post(ENDPOINTS.LOGIN, credentials);
+
+ store.dispatch(loginSuccess(response.data));
+ return response.data;
+ } catch (error) {
+ store.dispatch(loginFailure(error.message));
+ throw error;
+ }
+ },
+
+ // Logout function
+ logout() {
+ store.dispatch(logout());
+ },
+
+ // Check authentication status on app start
+ checkAuthStatus() {
+ store.dispatch(checkAuth());
+ },
+
+ // Set auth headers for API requests
+ getAuthHeaders() {
+ const token = this.getToken();
+ return {
+ 'Authorization': `Bearer ${token}`,
+ 'Content-Type': 'application/json'
+ };
+ }
+}
+
+export default authApi
\ No newline at end of file
diff --git a/src/services/categoriesApi.js b/src/services/categoriesApi.js
new file mode 100644
index 0000000..4c292e8
--- /dev/null
+++ b/src/services/categoriesApi.js
@@ -0,0 +1,116 @@
+import api from './api';
+
+// Categories API endpoints
+const ENDPOINTS = {
+ CATEGORIES: 'categories',
+ CATEGORY_BY_ID: (id) => `categories/${id}`,
+ CATEGORY_PRODUCTS: (id) => `categories/${id}/products`,
+ SEARCH: 'categories/search',
+};
+
+// Categories API service
+export const categoriesApi = {
+ // Get all categories
+ getAllCategories: async (params = {}) => {
+ try {
+ const response = await api.get(ENDPOINTS.CATEGORIES, { params });
+ return response.data;
+ } catch (error) {
+ console.error('Error fetching categories:', error);
+ throw error;
+ }
+ },
+
+ // Get category by ID
+ getCategoryById: async (id) => {
+ try {
+ const response = await api.get(ENDPOINTS.CATEGORY_BY_ID(id));
+ return response.data;
+ } catch (error) {
+ console.error(`Error fetching category ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Create new category
+ createCategory: async (categoryData) => {
+ try {
+ const response = await api.post(ENDPOINTS.CATEGORIES, categoryData);
+ return response.data;
+ } catch (error) {
+ console.error('Error creating category:', error);
+ throw error;
+ }
+ },
+
+ // Update category
+ updateCategory: async (id, categoryData) => {
+ try {
+ const response = await api.put(ENDPOINTS.CATEGORY_BY_ID(id), categoryData);
+ return response.data;
+ } catch (error) {
+ console.error(`Error updating category ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Delete category
+ deleteCategory: async (id) => {
+ try {
+ const response = await api.delete(ENDPOINTS.CATEGORY_BY_ID(id));
+ return response.data;
+ } catch (error) {
+ console.error(`Error deleting category ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Search categories
+ searchCategories: async (query, params = {}) => {
+ try {
+ const response = await api.get(ENDPOINTS.SEARCH, {
+ params: { q: query, ...params }
+ });
+ return response.data;
+ } catch (error) {
+ console.error('Error searching categories:', error);
+ throw error;
+ }
+ },
+
+ // Get products by category
+ getCategoryProducts: async (id, params = {}) => {
+ try {
+ const response = await api.get(ENDPOINTS.CATEGORY_PRODUCTS(id), { params });
+ return response.data;
+ } catch (error) {
+ console.error(`Error fetching products for category ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Bulk operations
+ bulkUpdateCategories: async (categories) => {
+ try {
+ const response = await api.put(`${ENDPOINTS.CATEGORIES}/bulk`, { categories });
+ return response.data;
+ } catch (error) {
+ console.error('Error bulk updating categories:', error);
+ throw error;
+ }
+ },
+
+ bulkDeleteCategories: async (categoryIds) => {
+ try {
+ const response = await api.delete(`${ENDPOINTS.CATEGORIES}/bulk`, {
+ data: { ids: categoryIds }
+ });
+ return response.data;
+ } catch (error) {
+ console.error('Error bulk deleting categories:', error);
+ throw error;
+ }
+ },
+};
+
+export default categoriesApi;
diff --git a/src/services/ordersApi.js b/src/services/ordersApi.js
new file mode 100644
index 0000000..0541e50
--- /dev/null
+++ b/src/services/ordersApi.js
@@ -0,0 +1,104 @@
+import api from './api';
+
+// Orders API endpoints
+const ENDPOINTS = {
+ ORDERS: 'orders',
+ ORDER_BY_ID: (id) => `orders/${id}`,
+ SEARCH: 'orders/search',
+};
+
+// Orders API service
+export const ordersApi = {
+ // Get all orders
+ getAllOrders: async (params = {}) => {
+ try {
+ const response = await api.get(ENDPOINTS.ORDERS, { params });
+ return response.data;
+ } catch (error) {
+ console.error('Error fetching orders:', error);
+ throw error;
+ }
+ },
+
+ // Get order by ID
+ getOrderById: async (id) => {
+ try {
+ const response = await api.get(ENDPOINTS.ORDER_BY_ID(id));
+ return response.data;
+ } catch (error) {
+ console.error(`Error fetching order ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Create new order
+ createOrder: async (orderData) => {
+ try {
+ const response = await api.post(ENDPOINTS.ORDERS, orderData);
+ return response.data;
+ } catch (error) {
+ console.error('Error creating order:', error);
+ throw error;
+ }
+ },
+
+ // Update order
+ updateOrder: async (id, orderData) => {
+ try {
+ const response = await api.put(ENDPOINTS.ORDER_BY_ID(id), orderData);
+ return response.data;
+ } catch (error) {
+ console.error(`Error updating order ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Delete order
+ deleteOrder: async (id) => {
+ try {
+ const response = await api.delete(ENDPOINTS.ORDER_BY_ID(id));
+ return response.data;
+ } catch (error) {
+ console.error(`Error deleting order ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Search orders
+ searchOrders: async (query, params = {}) => {
+ try {
+ const response = await api.get(ENDPOINTS.SEARCH, {
+ params: { q: query, ...params }
+ });
+ return response.data;
+ } catch (error) {
+ console.error('Error searching orders:', error);
+ throw error;
+ }
+ },
+
+ // Bulk operations
+ bulkUpdateOrders: async (orders) => {
+ try {
+ const response = await api.put(`${ENDPOINTS.ORDERS}/bulk`, { orders });
+ return response.data;
+ } catch (error) {
+ console.error('Error bulk updating orders:', error);
+ throw error;
+ }
+ },
+
+ bulkDeleteOrders: async (orderIds) => {
+ try {
+ const response = await api.delete(`${ENDPOINTS.ORDERS}/bulk`, {
+ data: { ids: orderIds }
+ });
+ return response.data;
+ } catch (error) {
+ console.error('Error bulk deleting orders:', error);
+ throw error;
+ }
+ },
+};
+
+export default ordersApi;
diff --git a/src/services/productsApi.js b/src/services/productsApi.js
index fed26c3..cf572f6 100644
--- a/src/services/productsApi.js
+++ b/src/services/productsApi.js
@@ -2,11 +2,11 @@ import api from './api';
// Products API endpoints
const ENDPOINTS = {
- PRODUCTS: 'Products',
- PRODUCT_BY_ID: (id) => `Products/${id}`,
- CATEGORIES: 'Products/categories',
- BRANDS: 'Products/brands',
- SEARCH: 'Products/search',
+ PRODUCTS: 'products',
+ PRODUCT_BY_ID: (id) => `products/${id}`,
+ CATEGORIES: 'products/categories',
+ BRANDS: 'products/brands',
+ SEARCH: 'products/search',
};
// Products API service
diff --git a/src/services/usersApi.js b/src/services/usersApi.js
new file mode 100644
index 0000000..1a94e33
--- /dev/null
+++ b/src/services/usersApi.js
@@ -0,0 +1,228 @@
+import api from './api';
+
+// Users API endpoints
+const ENDPOINTS = {
+ USERS: 'users',
+ USER_BY_ID: (id) => `users/${id}`,
+ USER_PROFILE: 'users/profile',
+ USER_PERMISSIONS: (id) => `users/${id}/permissions`,
+ USER_ROLES: (id) => `users/${id}/roles`,
+ SEARCH: 'users/search',
+ BULK_OPERATIONS: 'users/bulk',
+};
+
+// Users API service
+export const usersApi = {
+ // Get all users
+ getAllUsers: async (params = {}) => {
+ try {
+ const response = await api.get(ENDPOINTS.USERS, { params });
+ return response.data;
+ } catch (error) {
+ console.error('Error fetching users:', error);
+ throw error;
+ }
+ },
+
+ // Get user by ID
+ getUserById: async (id) => {
+ try {
+ const response = await api.get(ENDPOINTS.USER_BY_ID(id));
+ return response.data;
+ } catch (error) {
+ console.error(`Error fetching user ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Create new user
+ createUser: async (userData) => {
+ try {
+ const response = await api.post(ENDPOINTS.USERS, userData);
+ return response.data;
+ } catch (error) {
+ console.error('Error creating user:', error);
+ throw error;
+ }
+ },
+
+ // Update user
+ updateUser: async (id, userData) => {
+ try {
+ const response = await api.put(ENDPOINTS.USER_BY_ID(id), userData);
+ return response.data;
+ } catch (error) {
+ console.error(`Error updating user ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Delete user
+ deleteUser: async (id) => {
+ try {
+ const response = await api.delete(ENDPOINTS.USER_BY_ID(id));
+ return response.data;
+ } catch (error) {
+ console.error(`Error deleting user ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Search users
+ searchUsers: async (query, params = {}) => {
+ try {
+ const response = await api.get(ENDPOINTS.SEARCH, {
+ params: { q: query, ...params }
+ });
+ return response.data;
+ } catch (error) {
+ console.error('Error searching users:', error);
+ throw error;
+ }
+ },
+
+ // Get user profile
+ getUserProfile: async () => {
+ try {
+ const response = await api.get(ENDPOINTS.USER_PROFILE);
+ return response.data;
+ } catch (error) {
+ console.error('Error fetching user profile:', error);
+ throw error;
+ }
+ },
+
+ // Update user profile
+ updateUserProfile: async (profileData) => {
+ try {
+ const response = await api.put(ENDPOINTS.USER_PROFILE, profileData);
+ return response.data;
+ } catch (error) {
+ console.error('Error updating user profile:', error);
+ throw error;
+ }
+ },
+
+ // Get user permissions
+ getUserPermissions: async (id) => {
+ try {
+ const response = await api.get(ENDPOINTS.USER_PERMISSIONS(id));
+ return response.data;
+ } catch (error) {
+ console.error(`Error fetching user permissions ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Update user permissions
+ updateUserPermissions: async (id, permissions) => {
+ try {
+ const response = await api.put(ENDPOINTS.USER_PERMISSIONS(id), { permissions });
+ return response.data;
+ } catch (error) {
+ console.error(`Error updating user permissions ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Get user roles
+ getUserRoles: async (id) => {
+ try {
+ const response = await api.get(ENDPOINTS.USER_ROLES(id));
+ return response.data;
+ } catch (error) {
+ console.error(`Error fetching user roles ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Update user roles
+ updateUserRoles: async (id, roles) => {
+ try {
+ const response = await api.put(ENDPOINTS.USER_ROLES(id), { roles });
+ return response.data;
+ } catch (error) {
+ console.error(`Error updating user roles ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Change user password
+ changeUserPassword: async (id, passwordData) => {
+ try {
+ const response = await api.put(`${ENDPOINTS.USER_BY_ID(id)}/password`, passwordData);
+ return response.data;
+ } catch (error) {
+ console.error(`Error changing user password ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Activate/Deactivate user
+ toggleUserStatus: async (id, status) => {
+ try {
+ const response = await api.put(`${ENDPOINTS.USER_BY_ID(id)}/status`, { status });
+ return response.data;
+ } catch (error) {
+ console.error(`Error toggling user status ${id}:`, error);
+ throw error;
+ }
+ },
+
+ // Bulk operations
+ bulkUpdateUsers: async (users) => {
+ try {
+ const response = await api.put(ENDPOINTS.BULK_OPERATIONS, { users });
+ return response.data;
+ } catch (error) {
+ console.error('Error bulk updating users:', error);
+ throw error;
+ }
+ },
+
+ bulkDeleteUsers: async (userIds) => {
+ try {
+ const response = await api.delete(ENDPOINTS.BULK_OPERATIONS, {
+ data: { ids: userIds }
+ });
+ return response.data;
+ } catch (error) {
+ console.error('Error bulk deleting users:', error);
+ throw error;
+ }
+ },
+
+ // Export users
+ exportUsers: async (params = {}) => {
+ try {
+ const response = await api.get(`${ENDPOINTS.USERS}/export`, {
+ params,
+ responseType: 'blob'
+ });
+ return response.data;
+ } catch (error) {
+ console.error('Error exporting users:', error);
+ throw error;
+ }
+ },
+
+ // Import users
+ importUsers: async (fileData) => {
+ try {
+ const formData = new FormData();
+ formData.append('file', fileData);
+
+ const response = await api.post(`${ENDPOINTS.USERS}/import`, formData, {
+ headers: {
+ 'Content-Type': 'multipart/form-data',
+ },
+ });
+ return response.data;
+ } catch (error) {
+ console.error('Error importing users:', error);
+ throw error;
+ }
+ },
+};
+
+export default usersApi;
\ No newline at end of file
diff --git a/src/style/scss/components/_button.scss b/src/style/scss/components/_button.scss
index a178936..8110442 100644
--- a/src/style/scss/components/_button.scss
+++ b/src/style/scss/components/_button.scss
@@ -708,4 +708,11 @@ button {
box-shadow: 0 3px 12px rgba($dark, .2);
border-color: $dark;
}
-}
\ No newline at end of file
+}
+
+.center-vertical {
+ position: absolute;
+ top: 50%;
+ right: 1%;
+ transform: translateY(-50%);
+}
diff --git a/src/style/scss/components/_icons.scss b/src/style/scss/components/_icons.scss
index 1042463..4a0c8d7 100644
--- a/src/style/scss/components/_icons.scss
+++ b/src/style/scss/components/_icons.scss
@@ -25,4 +25,9 @@
@include margin-padding(5px, null);
@include box-shadow(null, 0, 2px, 3px, null, rgb(215, 197, 255));
}
+}
+
+.icon-small {
+ width: 18px;
+ height: 18px;
}
\ No newline at end of file
diff --git a/src/style/scss/components/_pagination.scss b/src/style/scss/components/_pagination.scss
index 3501a59..9bd2d07 100644
--- a/src/style/scss/components/_pagination.scss
+++ b/src/style/scss/components/_pagination.scss
@@ -1,171 +1,192 @@
.page-link {
- color: $text-color;
- background-color: $white;
- border: 1px solid $border-color;
- &:focus {
- box-shadow: none;
- background-color: $light;
- }
- &:hover {
- color: $primary;
- background-color: $light;
- border-color: $border-color;
- }
+ color: $text-color;
+ background-color: $white;
+ border: 1px solid $border-color;
+ &:focus {
+ box-shadow: none;
+ background-color: $light;
+ }
+ &:hover {
+ color: $primary;
+ background-color: $light;
+ border-color: $border-color;
+ }
}
.page-item.active .page-link {
- color: $white;
- background-color: $primary;
- border-color: $primary;
+ color: $white;
+ background-color: $primary;
+ border-color: $primary;
}
-.disabled>.page-link, .page-link.disabled {
- color: $text-color;
- background-color: $white;
- border-color: $border-color;
- opacity: 0.7;
+.disabled > .page-link,
+.page-link.disabled {
+ color: $text-color;
+ background-color: $white;
+ border-color: $border-color;
+ opacity: 0.7;
}
-[dir="rtl"] {
- .pagination{
- .page-link{
- .bx-chevron-left::before{
- content: "\ea50";
- }
- .bx-chevron-right::before{
- content: "\ea4d";
- }
- .ri-arrow-right-s-line:before{
- content: "\ea64";
- }
- .ri-arrow-left-s-line:before{
- content: "\ea6e";
- }
- }
+[dir="rtl"] {
+ .pagination {
+ .page-link {
+ .bx-chevron-left::before {
+ content: "\ea50";
+ }
+ .bx-chevron-right::before {
+ content: "\ea4d";
+ }
+ .ri-arrow-right-s-line:before {
+ content: "\ea64";
+ }
+ .ri-arrow-left-s-line:before {
+ content: "\ea6e";
+ }
}
+ }
}
.pagination-style-1 .pagination {
- .page-item {
- margin: 0 0.25rem;
- .page-link {
- border: 0;
- border-radius: $border-radius;
- font-size: 0.8125rem;
- i {
- font-weight: $font-weight-semibold;
- }
- }
- &.active {
- .page-link {
- border-radius: $border-radius;
- background-color: $primary;
- color: $white;
- }
- &:hover {
- .page-link {
- border-radius: $border-radius;
- background-color: $primary;
- color: $white;
- }
- }
- }
- &:hover {
- .page-link {
- background-color: $light;
- color: $primary;
- }
- }
+ .page-item {
+ margin: 0 0.25rem;
+ .page-link {
+ border: 0;
+ border-radius: $border-radius;
+ font-size: 0.8125rem;
+ i {
+ font-weight: $font-weight-semibold;
+ }
}
+ &.active {
+ .page-link {
+ border-radius: $border-radius;
+ background-color: $primary;
+ color: $white;
+ }
+ &:hover {
+ .page-link {
+ border-radius: $border-radius;
+ background-color: $primary;
+ color: $white;
+ }
+ }
+ }
+ &:hover {
+ .page-link {
+ background-color: $light;
+ color: $primary;
+ }
+ }
+ }
}
.pagination-style-2 .pagination {
- border-radius: $border-radius;
- .page-item {
- margin: 0 0.25rem;
- .page-link {
- border: 0 !important;
- font-size: 0.8125rem;
- }
- &.active {
- .page-link {
- background-color: $white;
- color: $primary;
- position: relative;
- font-weight: bold;
- &:before {
- position: absolute;
- content: "";
- inset-block-end: 0;
- inset-inline-start: 0;
- width: 100%;
- height: 0.1rem;
- background-color: $primary;
- }
- }
- }
- &:hover {
- .page-link {
- background-color: transparent;
- }
- }
+ border-radius: $border-radius;
+ .page-item {
+ margin: 0 0.25rem;
+ .page-link {
+ border: 0 !important;
+ font-size: 0.8125rem;
}
+ &.active {
+ .page-link {
+ background-color: $white;
+ color: $primary;
+ position: relative;
+ font-weight: bold;
+ &:before {
+ position: absolute;
+ content: "";
+ inset-block-end: 0;
+ inset-inline-start: 0;
+ width: 100%;
+ height: 0.1rem;
+ background-color: $primary;
+ }
+ }
+ }
+ &:hover {
+ .page-link {
+ background-color: transparent;
+ }
+ }
+ }
}
.pagination-style-3 .pagination {
- border-radius: 50px;
- padding: 0.25rem;
- align-items: center;
- .page-item {
- margin: 0 0.25rem;
- .page-link {
- border: 0;
- border-radius: 50px;
- font-size: 0.8125rem;
- i {
- font-weight: $font-weight-semibold;
- }
- }
- &.active {
- .page-link {
- background-color: $primary;
- color: $white;
- }
- &:hover {
- .page-link {
- background-color: $primary;
- }
- }
- }
- &:hover {
- .page-link {
- background-color: $light;
- }
- }
+ border-radius: 50px;
+ padding: 0.25rem;
+ align-items: center;
+ .page-item {
+ margin: 0 0.25rem;
+ .page-link {
+ border: 0;
+ border-radius: 50px;
+ font-size: 0.8125rem;
+ i {
+ font-weight: $font-weight-semibold;
+ }
}
+ &.active {
+ .page-link {
+ background-color: $primary;
+ color: $white;
+ }
+ &:hover {
+ .page-link {
+ background-color: $primary;
+ }
+ }
+ }
+ &:hover {
+ .page-link {
+ background-color: $light;
+ }
+ }
+ }
}
.pagination-style-4 .pagination {
- .page-item {
- .page-link {
- border: 0 !important;
- font-size: 0.8125rem;
- border-radius: $border-radius;
- i {
- font-weight: $font-weight-semibold;
- }
- }
- &.active {
- .page-link {
- border: 0;
- border-radius: $border-radius;
- background-color: $primary;
- color: $white;
- }
- &:hover {
- .page-link {
- background-color: $primary;
- }
- }
- }
- &:hover {
- .page-link {
- background-color: transparent;
- }
- }
+ .page-item {
+ .page-link {
+ border: 0 !important;
+ font-size: 0.8125rem;
+ border-radius: $border-radius;
+ i {
+ font-weight: $font-weight-semibold;
+ }
}
-}
\ No newline at end of file
+ &.active {
+ .page-link {
+ border: 0;
+ border-radius: $border-radius;
+ background-color: $primary;
+ color: $white;
+ }
+ &:hover {
+ .page-link {
+ background-color: $primary;
+ }
+ }
+ }
+ &:hover {
+ .page-link {
+ background-color: transparent;
+ }
+ }
+ }
+}
+
+.custom-pagination .page-item .page-link {
+ border: none;
+ background: transparent;
+}
+
+.custom-pagination .page-item.active .page-link {
+ width: 36px;
+ height: 36px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-weight: bold;
+}
+
+.page-link.disabled {
+ pointer-events: none;
+ opacity: 0.5;
+ cursor: not-allowed;
+}
diff --git a/src/style/scss/components/_tables.scss b/src/style/scss/components/_tables.scss
index 8f1d51d..41b2e9e 100644
--- a/src/style/scss/components/_tables.scss
+++ b/src/style/scss/components/_tables.scss
@@ -317,7 +317,7 @@ caption {
}
}
a {
- color: $secondary;
+ color: $primary;
font-size: $font-size-14;
font-weight: $font-weight-normal;
line-height: normal;
@@ -533,10 +533,10 @@ caption {
padding: 0;
}
.table-top {
- padding: 24px 24px 0;
+ padding: 18px 18px 0;
}
.table-responsive {
- padding: 24px;
+ padding: 18px;
border-top: 1px solid $gray-400;
.dataTables_wrapper {
border: 0;
@@ -545,7 +545,7 @@ caption {
}
.tabs-set {
.nav-tabs {
- padding: 24px 24px 0;
+ padding: 18px 18px 0;
margin-bottom: 0;
}
}
@@ -674,3 +674,17 @@ table {
}
}
}
+
+.custom-table .ant-table-thead > tr > th {
+ padding-top: 12px;
+ padding-bottom: 12px;
+}
+
+.custom-table .ant-table-thead .ant-table-cell {
+ background-color: #fafbfe;
+}
+
+.custom-table .ant-table-tbody > tr > td {
+ padding-top: 1px;
+ padding-bottom: 1px;
+}
diff --git a/src/style/scss/layout/_common.scss b/src/style/scss/layout/_common.scss
index b8217f1..77ab773 100644
--- a/src/style/scss/layout/_common.scss
+++ b/src/style/scss/layout/_common.scss
@@ -112,7 +112,7 @@
}
h3{
font-weight: $font-weight-bold;
- color: $secondary;
+ color: $primary;
font-size: $font-size-18;
@include respond-below(custom991) {
font-size: $font-size-base;
@@ -120,7 +120,7 @@
}
h4 {
font-weight: $font-weight-bold;
- color: $secondary;
+ color: $primary;
font-size: $font-size-18;
margin-bottom: 5px;
@include respond-below(custom991) {
@@ -536,7 +536,7 @@ th,td {
h4 {
font-size: $font-size-base;
font-weight: $font-weight-medium;
- color: $secondary
+ color: $primary
}
}
&.image-upload-new{
@@ -652,7 +652,7 @@ th,td {
}
label{
margin-bottom: 8px;
- color: $secondary;
+ color: $primary;
font-weight: $font-weight-medium;
font-size: $font-size-base;
display: block;
diff --git a/src/style/scss/layout/_sidebar.scss b/src/style/scss/layout/_sidebar.scss
index 2c17c70..a8b3420 100644
--- a/src/style/scss/layout/_sidebar.scss
+++ b/src/style/scss/layout/_sidebar.scss
@@ -38,7 +38,7 @@
color: $white;
}
svg {
- color: #FE9F43
+ color: $primary
}
}
svg {
@@ -66,21 +66,21 @@
}
&:hover{
background: rgba(254, 159, 67, 0.08);
- color: #FE9F43;
+ color: $primary;
border-radius: 5px;
img {
filter: invert(72%) sepia(76%) saturate(1430%) hue-rotate(327deg) brightness(103%) contrast(101%);
}
span{
- color: #FE9F43;
+ color: $primary;
}
svg{
- color: #FE9F43;
+ color: $primary;
}
}
&.active{
background: rgba(254, 159, 67, 0.08);
- color: #FE9F43;
+ color: $primary;
border-radius: 5px;
svg{
color: $white;
@@ -89,12 +89,12 @@
filter: invert(72%) sepia(76%) saturate(1430%) hue-rotate(327deg) brightness(103%) contrast(101%);
}
span{
- color: #FE9F43;
+ color: $primary;
}
.menu-arrow{
background: #FFEDDC;
&::before{
- border-color: #FE9F43;
+ border-color: $primary;
}
}
}
@@ -112,7 +112,7 @@
filter: invert(72%) sepia(76%) saturate(1430%) hue-rotate(327deg) brightness(103%) contrast(101%);
}
span{
- color: #FE9F43;
+ color: $primary;
}
}
}
@@ -132,8 +132,8 @@
&.active{
color: $secondary;
&:after{
- background: #FE9F43;
- border: 2px solid #FDB;
+ background: $primary;
+ border: 2px solid $secondary;
}
}
&::after{
@@ -148,8 +148,8 @@
&:hover{
color:$primary;
&:after{
- background: #FE9F43;
- border: 2px solid #FDB;
+ background: $primary;
+ border: 2px solid $secondary;
}
}
}
@@ -188,15 +188,15 @@
}
}
&:after{
- background: #FE9F43;
- border: 2px solid #FDB;
+ background: $primary;
+ border: 2px solid $secondary;
}
}
&:hover{
color:$primary;
&:after{
- background: #FE9F43;
- border: 2px solid #FDB;
+ background: $primary;
+ border: 2px solid $secondary;
}
span {
color:$primary;
@@ -209,7 +209,7 @@
&.active a{
background: rgba(254, 159, 67, 0.08);
border-radius: 5px;
- color: #FE9F43;
+ color: $primary;
span {
color: $primary;
}
@@ -240,25 +240,25 @@
li {
&.active{
a{
- color: #FE9F43;
+ color: $primary;
}
svg {
- color: #FE9F43
+ color: $primary
}
}
.submenu > {
a {
&.active{
- background: rgba(254, 159, 67, 0.08);
- color: #FE9F43;
+ background: $secondary;
+ color: $primary;
border-radius: 5px;
span{
- color: #FE9F43;
+ color: $primary;
}
.menu-arrow{
- background: #FFEDDC;
+ // background: #FFEDDC;
&::before{
- border-color: #FE9F43;
+ border-color: $primary;
}
}
}
@@ -321,8 +321,8 @@
&:hover{
color:$primary;
&:after{
- background: #FE9F43;
- border: 2px solid #FDB;
+ background: $primary;
+ border: 2px solid $secondary;
}
}
}
diff --git a/src/style/scss/pages/_customisedstyle.scss b/src/style/scss/pages/_customisedstyle.scss
index ab120f9..0daf356 100644
--- a/src/style/scss/pages/_customisedstyle.scss
+++ b/src/style/scss/pages/_customisedstyle.scss
@@ -854,10 +854,10 @@ $__basecolor: #2c3038;
// Badge styling in options
.badge {
- display: inline-block;
- width: 8px;
- height: 8px;
- border-radius: 50%;
+ // display: inline-block;
+ // width: 8px;
+ // height: 8px;
+ // border-radius: 50%;
&.badge-blue { background: #007bff; }
&.badge-green { background: #28a745; }
diff --git a/src/style/scss/pages/_login.scss b/src/style/scss/pages/_login.scss
index 603c9a0..891ecb6 100644
--- a/src/style/scss/pages/_login.scss
+++ b/src/style/scss/pages/_login.scss
@@ -63,7 +63,7 @@
margin-top: 50px !important;
p {
font-size: $font-size-14;
- color: $secondary;
+ color: $primary;
margin-bottom: 0;
font-weight: $font-weight-normal;
}
@@ -120,7 +120,7 @@
h4 {
font-size: $font-size-15;
font-weight: $font-weight-normal;
- color: $secondary;
+ color: $primary;
line-height: 1.4;
}
.verfy-mail-content {
@@ -132,7 +132,7 @@
margin-bottom: 15px;
label {
width: 100%;
- color: $secondary;
+ color: $primary;
margin-bottom:10px;
font-size: $font-size-15;
font-weight: $font-weight-normal;
@@ -209,12 +209,12 @@
h4{
font-size: $font-size-15;
font-weight: $font-weight-normal;
- color: $secondary;
+ color: $primary;
@include respond-below(custom575) {
font-size: $font-size-base;
}
a{
- color: $secondary;
+ color: $primary;
font-weight: $font-weight-bold;
font-size: $font-size-14;
}
@@ -339,7 +339,7 @@
}
}
a {
- color: $secondary;
+ color: $primary;
width: 100%;
border: 1px solid rgba(145, 158, 171, 0.23);
background: $white;
diff --git a/src/style/scss/pages/_product.scss b/src/style/scss/pages/_product.scss
index 5ca7a0f..1b9c214 100644
--- a/src/style/scss/pages/_product.scss
+++ b/src/style/scss/pages/_product.scss
@@ -182,7 +182,7 @@
border: 0;
}
h4 {
- color: $secondary;
+ color: $primary;
font-size: $font-size-base;
font-weight: $font-weight-medium;
width: 30%;
@@ -246,14 +246,14 @@
h4 {
font-size: $font-size-base;
- color: $secondary;
+ color: $primary;
font-weight: $font-weight-medium;
}
h6 {
font-size: $font-size-13;
font-weight: $font-weight-normal;
- color: $secondary;
+ color: $primary;
}
}
@@ -409,7 +409,7 @@ span {
width: 40px;
height: 40px;
border: 1px solid var(--Stroke, rgba(145, 158, 171, 0.30));
- background: $secondary;
+ background: $primary;
@include rounded(8px);
@include respond-below(custom575) {
position: relative;
diff --git a/src/style/scss/utils/_variables.scss b/src/style/scss/utils/_variables.scss
index c987999..07c4c45 100644
--- a/src/style/scss/utils/_variables.scss
+++ b/src/style/scss/utils/_variables.scss
@@ -16,9 +16,9 @@ $font-family-secondary: "Poppins", sans-serif;
$font-awesome: "Fontawesome";
// Theme Colors Variables
-$primary: #FF9F43;
+$primary: #36175e;
$primary-hover: darken($primary, 10%);
-$secondary: #092C4C;
+$secondary: #f1eaf9;
$secondary-hover: darken($secondary, 10%);
$success: #28C76F;
$success-hover: darken($success, 10%);
@@ -29,7 +29,7 @@ $warning-hover: darken($warning, 10%);
$danger: #FF0000;
$danger-hover: darken($danger, 10%);
$dark: #29344a;
-$light: #f8f9fa;
+$light: #FAFBFE;
$white: #ffffff;
$black: #000000;
$purple: #7367F0;
@@ -44,26 +44,26 @@ $indigo: #4d5ddb;
$yellow: #ffff00;
// Primary
-$primary-100: #FFF5EC;
-$primary-200: #FFECD9;
-$primary-300: #FFE2C7;
-$primary-400: #FFD9B4;
-$primary-500: #FFCFA1;
-$primary-600: #FFC58E;
-$primary-700: #FFBC7B;
-$primary-800: #FFB269;
-$primary-900: #FFA956;
+$primary-100: #ede7f3;
+$primary-200: #d3c2e3;
+$primary-300: #b99cd3;
+$primary-400: #9f76c3;
+$primary-500: #8551b3;
+$primary-600: #6e3f98;
+$primary-700: #57317a;
+$primary-800: #40225c;
+$primary-900: #2a153d;
// Secondary
-$secondary-100: #E6EAED;
-$secondary-200: #CED5DB;
-$secondary-300: #B5C0C9;
-$secondary-400: #9DABB7;
-$secondary-500: #8496A6;
-$secondary-600: #6B8094;
-$secondary-700: #536B82;
-$secondary-800: #3A5670;
-$secondary-900: #22415E;
+$secondary-100: #fdfbff;
+$secondary-200: #f8f4fc;
+$secondary-300: #f1eaf9;
+$secondary-400: #e0d3f1;
+$secondary-500: #c8b0e6;
+$secondary-600: #af8ddb;
+$secondary-700: #9369cc;
+$secondary-800: #7547aa;
+$secondary-900: #563180;
// Success
$success-100: #EAF9F1;
@@ -158,7 +158,7 @@ $theme-colors: (
"black": $black,
"purple": $purple,
"yellow": $yellow,
- "teal": $teal
+ "teal": $teal,
);
$text-color: #5B6670;
@@ -282,4 +282,4 @@ $h2-font-size: $font-size-base * 2;
$h3-font-size: $font-size-base * 1.75;
$h4-font-size: $font-size-base * 1.5;
$h5-font-size: $font-size-base * 1.25;
-$h6-font-size: $font-size-base;
+$h6-font-size: $font-size-base;
\ No newline at end of file
diff --git a/src/utils/currency.js b/src/utils/currency.js
new file mode 100644
index 0000000..6cffb66
--- /dev/null
+++ b/src/utils/currency.js
@@ -0,0 +1,9 @@
+const formatRupiah = (angka) => {
+ return new Intl.NumberFormat("id-ID", {
+ style: "currency",
+ currency: "IDR",
+ minimumFractionDigits: 0,
+ }).format(angka);
+};
+
+export { formatRupiah };
diff --git a/src/utils/date.js b/src/utils/date.js
new file mode 100644
index 0000000..1f933e4
--- /dev/null
+++ b/src/utils/date.js
@@ -0,0 +1,13 @@
+const formatDate = (isoDate) => {
+ const date = new Date(isoDate);
+
+ const formatted = date.toLocaleString("en-GB", {
+ day: "2-digit",
+ month: "short", // example: July
+ year: "numeric",
+ });
+
+ return formatted
+};
+
+export { formatDate };
|