fix: Remove demo pages and add testDataService for production build
This commit is contained in:
@@ -1,429 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { Button } from 'primereact/button';
|
||||
import { Column } from 'primereact/column';
|
||||
import { DataTable } from 'primereact/datatable';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { FileUpload } from 'primereact/fileupload';
|
||||
import { InputNumber } from 'primereact/inputnumber';
|
||||
import { InputText } from 'primereact/inputtext';
|
||||
import { InputTextarea } from 'primereact/inputtextarea';
|
||||
import { RadioButton } from 'primereact/radiobutton';
|
||||
import { Rating } from 'primereact/rating';
|
||||
import { Toast } from 'primereact/toast';
|
||||
import { Toolbar } from 'primereact/toolbar';
|
||||
import { classNames } from 'primereact/utils';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { ProductService } from '../../../../demo/service/ProductService';
|
||||
import type { Demo } from '@/types';
|
||||
|
||||
const Crud = () => {
|
||||
let emptyProduct: Demo.Product = {
|
||||
id: null,
|
||||
name: '',
|
||||
image: null,
|
||||
description: '',
|
||||
category: null,
|
||||
price: 0,
|
||||
quantity: 0,
|
||||
rating: 0,
|
||||
inventoryStatus: 'INSTOCK'
|
||||
};
|
||||
|
||||
const [products, setProducts] = useState(null);
|
||||
const [productDialog, setProductDialog] = useState(false);
|
||||
const [deleteProductDialog, setDeleteProductDialog] = useState(false);
|
||||
const [deleteProductsDialog, setDeleteProductsDialog] = useState(false);
|
||||
const [product, setProduct] = useState(emptyProduct);
|
||||
const [selectedProducts, setSelectedProducts] = useState(null);
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
const [globalFilter, setGlobalFilter] = useState(null);
|
||||
const toast = useRef(null);
|
||||
const dt = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
ProductService.getProducts().then((data) => setProducts(data));
|
||||
}, []);
|
||||
|
||||
const formatCurrency = (value) => {
|
||||
return value.toLocaleString('en-US', {
|
||||
style: 'currency',
|
||||
currency: 'USD'
|
||||
});
|
||||
};
|
||||
|
||||
const openNew = () => {
|
||||
setProduct(emptyProduct);
|
||||
setSubmitted(false);
|
||||
setProductDialog(true);
|
||||
};
|
||||
|
||||
const hideDialog = () => {
|
||||
setSubmitted(false);
|
||||
setProductDialog(false);
|
||||
};
|
||||
|
||||
const hideDeleteProductDialog = () => {
|
||||
setDeleteProductDialog(false);
|
||||
};
|
||||
|
||||
const hideDeleteProductsDialog = () => {
|
||||
setDeleteProductsDialog(false);
|
||||
};
|
||||
|
||||
const saveProduct = () => {
|
||||
setSubmitted(true);
|
||||
|
||||
if (product.name.trim()) {
|
||||
let _products = [...products];
|
||||
let _product = { ...product };
|
||||
if (product.id) {
|
||||
const index = findIndexById(product.id);
|
||||
|
||||
_products[index] = _product;
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: 'Successful',
|
||||
detail: 'Product Updated',
|
||||
life: 3000
|
||||
});
|
||||
} else {
|
||||
_product.id = createId();
|
||||
_product.code = createId();
|
||||
_product.image = 'product-placeholder.svg';
|
||||
_products.push(_product);
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: 'Successful',
|
||||
detail: 'Product Created',
|
||||
life: 3000
|
||||
});
|
||||
}
|
||||
|
||||
setProducts(_products);
|
||||
setProductDialog(false);
|
||||
setProduct(emptyProduct);
|
||||
}
|
||||
};
|
||||
|
||||
const editProduct = (product) => {
|
||||
setProduct({ ...product });
|
||||
setProductDialog(true);
|
||||
};
|
||||
|
||||
const confirmDeleteProduct = (product) => {
|
||||
setProduct(product);
|
||||
setDeleteProductDialog(true);
|
||||
};
|
||||
|
||||
const deleteProduct = () => {
|
||||
let _products = products.filter((val) => val.id !== product.id);
|
||||
setProducts(_products);
|
||||
setDeleteProductDialog(false);
|
||||
setProduct(emptyProduct);
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: 'Successful',
|
||||
detail: 'Product Deleted',
|
||||
life: 3000
|
||||
});
|
||||
};
|
||||
|
||||
const findIndexById = (id) => {
|
||||
let index = -1;
|
||||
for (let i = 0; i < products.length; i++) {
|
||||
if (products[i].id === id) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
};
|
||||
|
||||
const createId = () => {
|
||||
let id = '';
|
||||
let chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
for (let i = 0; i < 5; i++) {
|
||||
id += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
return id;
|
||||
};
|
||||
|
||||
const exportCSV = () => {
|
||||
dt.current.exportCSV();
|
||||
};
|
||||
|
||||
const confirmDeleteSelected = () => {
|
||||
setDeleteProductsDialog(true);
|
||||
};
|
||||
|
||||
const deleteSelectedProducts = () => {
|
||||
let _products = products.filter((val) => !selectedProducts.includes(val));
|
||||
setProducts(_products);
|
||||
setDeleteProductsDialog(false);
|
||||
setSelectedProducts(null);
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: 'Successful',
|
||||
detail: 'Products Deleted',
|
||||
life: 3000
|
||||
});
|
||||
};
|
||||
|
||||
const onCategoryChange = (e) => {
|
||||
let _product = { ...product };
|
||||
_product['category'] = e.value;
|
||||
setProduct(_product);
|
||||
};
|
||||
|
||||
const onInputChange = (e, name) => {
|
||||
const val = (e.target && e.target.value) || '';
|
||||
let _product = { ...product };
|
||||
_product[`${name}`] = val;
|
||||
|
||||
setProduct(_product);
|
||||
};
|
||||
|
||||
const onInputNumberChange = (e, name) => {
|
||||
const val = e.value || 0;
|
||||
let _product = { ...product };
|
||||
_product[`${name}`] = val;
|
||||
|
||||
setProduct(_product);
|
||||
};
|
||||
|
||||
const leftToolbarTemplate = () => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="my-2">
|
||||
<Button severity="success" label="New" icon="pi pi-plus" className="mr-2" onClick={openNew} />
|
||||
<Button severity="danger" label="Delete" icon="pi pi-trash" onClick={confirmDeleteSelected} disabled={!selectedProducts || !selectedProducts.length} />
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const rightToolbarTemplate = () => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<FileUpload mode="basic" accept="image/*" maxFileSize={1000000} chooseLabel="Import" className="mr-2 inline-block" />
|
||||
<Button severity="help" label="Export" icon="pi pi-upload" onClick={exportCSV} />
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const codeBodyTemplate = (rowData) => {
|
||||
return (
|
||||
<>
|
||||
<span className="p-column-title">Code</span>
|
||||
{rowData.code}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const nameBodyTemplate = (rowData) => {
|
||||
return (
|
||||
<>
|
||||
<span className="p-column-title">Name</span>
|
||||
{rowData.name}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const imageBodyTemplate = (rowData) => {
|
||||
return (
|
||||
<>
|
||||
<span className="p-column-title">Image</span>
|
||||
<img src={`/demo/images/product/${rowData.image}`} alt={rowData.image} className="shadow-2" width="100" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const priceBodyTemplate = (rowData) => {
|
||||
return (
|
||||
<>
|
||||
<span className="p-column-title">Price</span>
|
||||
{formatCurrency(rowData.price)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const categoryBodyTemplate = (rowData) => {
|
||||
return (
|
||||
<>
|
||||
<span className="p-column-title">Category</span>
|
||||
{rowData.category}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const ratingBodyTemplate = (rowData) => {
|
||||
return (
|
||||
<>
|
||||
<span className="p-column-title">Reviews</span>
|
||||
<Rating value={rowData.rating} readOnly cancel={false} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const statusBodyTemplate = (rowData) => {
|
||||
return (
|
||||
<>
|
||||
<span className="p-column-title">Status</span>
|
||||
<span className={`product-badge status-${rowData.inventoryStatus.toLowerCase()}`}>{rowData.inventoryStatus}</span>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const actionBodyTemplate = (rowData) => {
|
||||
return (
|
||||
<>
|
||||
<Button icon="pi pi-pencil" rounded severity="success" className="mr-2" onClick={() => editProduct(rowData)} />
|
||||
<Button icon="pi pi-trash" rounded severity="warning" onClick={() => confirmDeleteProduct(rowData)} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const header = (
|
||||
<div className="flex flex-column md:flex-row md:justify-content-between md:align-items-center">
|
||||
<h5 className="m-0">Manage Products</h5>
|
||||
<span className="block mt-2 md:mt-0 p-input-icon-left">
|
||||
<i className="pi pi-search" />
|
||||
<InputText type="search" onInput={(e) => setGlobalFilter((e.target as HTMLInputElement).value)} placeholder="Search..." />
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
const productDialogFooter = (
|
||||
<>
|
||||
<Button label="Cancel" icon="pi pi-times" text onClick={hideDialog} />
|
||||
<Button label="Save" icon="pi pi-check" text onClick={saveProduct} />
|
||||
</>
|
||||
);
|
||||
const deleteProductDialogFooter = (
|
||||
<>
|
||||
<Button label="No" icon="pi pi-times" text onClick={hideDeleteProductDialog} />
|
||||
<Button label="Yes" icon="pi pi-check" text onClick={deleteProduct} />
|
||||
</>
|
||||
);
|
||||
const deleteProductsDialogFooter = (
|
||||
<>
|
||||
<Button label="No" icon="pi pi-times" text onClick={hideDeleteProductsDialog} />
|
||||
<Button label="Yes" icon="pi pi-check" text onClick={deleteSelectedProducts} />
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="grid crud-demo">
|
||||
<div className="col-12">
|
||||
<div className="card">
|
||||
<Toast ref={toast} />
|
||||
<Toolbar className="mb-4" left={leftToolbarTemplate} right={rightToolbarTemplate}></Toolbar>
|
||||
|
||||
<DataTable
|
||||
ref={dt}
|
||||
value={products}
|
||||
selection={selectedProducts}
|
||||
onSelectionChange={(e) => setSelectedProducts(e.value)}
|
||||
paginator
|
||||
rows={10}
|
||||
rowsPerPageOptions={[5, 10, 25]}
|
||||
className="datatable-responsive"
|
||||
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown"
|
||||
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} products"
|
||||
globalFilter={globalFilter}
|
||||
emptyMessage="No products found."
|
||||
header={header}
|
||||
responsiveLayout="scroll"
|
||||
>
|
||||
<Column selectionMode="multiple" headerStyle={{ width: '4rem' }}></Column>
|
||||
<Column field="code" header="Code" sortable body={codeBodyTemplate} headerStyle={{ minWidth: '15rem' }}></Column>
|
||||
<Column field="name" header="Name" sortable body={nameBodyTemplate} headerStyle={{ minWidth: '15rem' }}></Column>
|
||||
<Column header="Image" body={imageBodyTemplate}></Column>
|
||||
<Column field="price" header="Price" body={priceBodyTemplate} sortable></Column>
|
||||
<Column field="category" header="Category" sortable body={categoryBodyTemplate} headerStyle={{ minWidth: '10rem' }}></Column>
|
||||
<Column field="rating" header="Reviews" body={ratingBodyTemplate} sortable></Column>
|
||||
<Column field="inventoryStatus" header="Status" body={statusBodyTemplate} sortable headerStyle={{ minWidth: '10rem' }}></Column>
|
||||
<Column body={actionBodyTemplate} headerStyle={{ minWidth: '10rem' }}></Column>
|
||||
</DataTable>
|
||||
|
||||
<Dialog visible={productDialog} style={{ width: '450px' }} header="Product Details" modal className="p-fluid" footer={productDialogFooter} onHide={hideDialog}>
|
||||
{product.image && <img src={`/demo/images/product/${product.image}`} alt={product.image} width="150" className="mt-0 mx-auto mb-5 block shadow-2" />}
|
||||
<div className="field">
|
||||
<label htmlFor="name">Name</label>
|
||||
<InputText
|
||||
id="name"
|
||||
value={product.name}
|
||||
onChange={(e) => onInputChange(e, 'name')}
|
||||
required
|
||||
autoFocus
|
||||
className={classNames({
|
||||
'p-invalid': submitted && !product.name
|
||||
})}
|
||||
/>
|
||||
{submitted && !product.name && <small className="p-invalid">Name is required.</small>}
|
||||
</div>
|
||||
<div className="field">
|
||||
<label htmlFor="description">Description</label>
|
||||
<InputTextarea id="description" value={product.description} onChange={(e) => onInputChange(e, 'description')} required rows={3} cols={20} />
|
||||
</div>
|
||||
|
||||
<div className="field">
|
||||
<label className="mb-3">Category</label>
|
||||
<div className="formgrid grid">
|
||||
<div className="field-radiobutton col-6">
|
||||
<RadioButton inputId="category1" name="category" value="Accessories" onChange={onCategoryChange} checked={product.category === 'Accessories'} />
|
||||
<label htmlFor="category1">Accessories</label>
|
||||
</div>
|
||||
<div className="field-radiobutton col-6">
|
||||
<RadioButton inputId="category2" name="category" value="Clothing" onChange={onCategoryChange} checked={product.category === 'Clothing'} />
|
||||
<label htmlFor="category2">Clothing</label>
|
||||
</div>
|
||||
<div className="field-radiobutton col-6">
|
||||
<RadioButton inputId="category3" name="category" value="Electronics" onChange={onCategoryChange} checked={product.category === 'Electronics'} />
|
||||
<label htmlFor="category3">Electronics</label>
|
||||
</div>
|
||||
<div className="field-radiobutton col-6">
|
||||
<RadioButton inputId="category4" name="category" value="Fitness" onChange={onCategoryChange} checked={product.category === 'Fitness'} />
|
||||
<label htmlFor="category4">Fitness</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="formgrid grid">
|
||||
<div className="field col">
|
||||
<label htmlFor="price">Price</label>
|
||||
<InputNumber id="price" value={product.price as number} onValueChange={(e) => onInputNumberChange(e, 'price')} mode="currency" currency="USD" locale="en-US" />
|
||||
</div>
|
||||
<div className="field col">
|
||||
<label htmlFor="quantity">Quantity</label>
|
||||
<InputNumber id="quantity" value={product.quantity} onValueChange={(e) => onInputNumberChange(e, 'quantity')} />
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
|
||||
<Dialog visible={deleteProductDialog} style={{ width: '450px' }} header="Confirm" modal footer={deleteProductDialogFooter} onHide={hideDeleteProductDialog}>
|
||||
<div className="flex align-items-center justify-content-center">
|
||||
<i className="pi pi-exclamation-triangle mr-3" style={{ fontSize: '2rem' }} />
|
||||
{product && (
|
||||
<span>
|
||||
Are you sure you want to delete <b>{product.name}</b>?
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</Dialog>
|
||||
|
||||
<Dialog visible={deleteProductsDialog} style={{ width: '450px' }} header="Confirm" modal footer={deleteProductsDialogFooter} onHide={hideDeleteProductsDialog}>
|
||||
<div className="flex align-items-center justify-content-center">
|
||||
<i className="pi pi-exclamation-triangle mr-3" style={{ fontSize: '2rem' }} />
|
||||
{product && <span>Are you sure you want to delete the selected products?</span>}
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Crud;
|
||||
Reference in New Issue
Block a user