([]);\r\n\r\n useEffect(() =>\r\n {\r\n if (allCategoriesData)\r\n {\r\n const extendedProducts = allCategoriesData.map((category: IRestApiProductCategoryDTO) => ({\r\n ...category, // Spread the existing properties\r\n isNew: false, // Add default value for isNew\r\n cacheValue: Guid.NewGuid(), // Generate a new GUID\r\n }));\r\n\r\n setProductCategories(extendedProducts as IRestApiProductCategoryExtended[]);\r\n }\r\n }, [ allCategoriesData ]);\r\n\r\n\r\n const handleEditClick = (id: GridRowId) => (event: React.MouseEvent) => \r\n {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n console.log('Edit clicked', id);\r\n\r\n const category = productCategories.find(cat => cat.id === id);\r\n\r\n if (category)\r\n {\r\n console.log('Opening modal for:', category);\r\n\r\n setCurrentProductCategory(category);\r\n setEditModalOpen(true);\r\n }\r\n };\r\n\r\n const handleSaveClick = (id: GridRowId) => () =>\r\n {\r\n setRowModesModel({ ...rowModesModel, [ id ]: { mode: GridRowModes.View } });\r\n };\r\n\r\n const handleDeleteClick = (id: GridRowId) => () =>\r\n {\r\n const category = productCategories.find(cat => cat.id === id);\r\n\r\n if (category)\r\n {\r\n setCurrentProductCategory(category);\r\n setDeleteModalOpen(true);\r\n }\r\n };\r\n\r\n const handleCancelClick = (id: GridRowId) => () =>\r\n {\r\n setRowModesModel({\r\n ...rowModesModel,\r\n [ id ]: { mode: GridRowModes.View, ignoreModifications: true },\r\n });\r\n };\r\n\r\n const handleDeleteDialogClose = () =>\r\n {\r\n setDeleteModalOpen(false);\r\n };\r\n\r\n\r\n const handleAddCategory = () =>\r\n {\r\n setAddModalOpen(true);\r\n };\r\n\r\n const handleSelectionChange = (newSelection: GridRowId[]) =>\r\n {\r\n setSelectedRows(newSelection);\r\n };\r\n\r\n const handleDeleteAllCheckedRows = () =>\r\n {\r\n setDeleteMultipleModalOpen(true); // Open the delete multiple modal\r\n };\r\n\r\n const handleDeleteMultipleDialogClose = () =>\r\n {\r\n setDeleteMultipleModalOpen(false);\r\n };\r\n\r\n const handleEditModalClose = () =>\r\n {\r\n console.log('Closing modal');\r\n\r\n setEditModalOpen(false);\r\n setCurrentProductCategory(null); // Reset the current product category\r\n };\r\n\r\n if (allCategoriesLoading) return (Loading...
);\r\n\r\n if (allCategoriesError) return (Error: { `${allCategoriesError}` }
);\r\n\r\n const columns: GridColDef[] = [\r\n {\r\n field: 'name',\r\n headerName: 'Name',\r\n editable: false,\r\n type: 'string',\r\n flex: 1,\r\n minWidth: 50,\r\n headerClassName: 'column-header',\r\n renderCell: (params: GridRenderCellParams) =>\r\n {\r\n const handleClick = (event: React.MouseEvent) =>\r\n {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n navigate(`/categories/${toCamelCase(params.value)}`, { state: { categoryId: params.row.id } });\r\n };\r\n\r\n return (\r\n \r\n { params.value }\r\n \r\n );\r\n }\r\n },\r\n {\r\n field: 'title',\r\n headerName: 'Title',\r\n editable: false,\r\n type: 'string',\r\n flex: 1.25,\r\n minWidth: 150,\r\n headerClassName: 'column-header',\r\n },\r\n {\r\n field: 'subtitle',\r\n headerName: 'Subtitle',\r\n editable: false,\r\n type: 'string',\r\n flex: 1.5,\r\n minWidth: 150,\r\n headerClassName: 'column-header',\r\n },\r\n {\r\n field: 'description',\r\n headerName: 'Description',\r\n editable: false,\r\n type: 'string',\r\n flex: 3,\r\n minWidth: 300,\r\n headerClassName: 'column-header',\r\n renderCell: (params) => (\r\n \r\n ),\r\n },\r\n {\r\n field: 'sortOrder',\r\n headerName: 'Order',\r\n editable: false,\r\n type: 'number',\r\n flex: 0.5,\r\n minWidth: 50,\r\n headerClassName: 'column-header',\r\n },\r\n {\r\n field: 'bannerImage',\r\n headerName: 'Image',\r\n sortable: false,\r\n flex: 0.5,\r\n minWidth: 50,\r\n renderCell: (params) =>\r\n {\r\n return ();\r\n }\r\n },\r\n {\r\n field: 'thumbnailImage',\r\n headerName: 'Thumb',\r\n sortable: false,\r\n flex: 0.5,\r\n minWidth: 50,\r\n renderCell: (params) =>\r\n {\r\n return ();\r\n }\r\n },\r\n {\r\n field: 'actions',\r\n headerName: 'Actions',\r\n editable: false,\r\n sortable: false,\r\n flex: 0.5,\r\n minWidth: 100,\r\n headerClassName: 'column-header',\r\n renderCell: (params: GridRenderCellParams) =>\r\n (\r\n \r\n ),\r\n }\r\n ];\r\n\r\n if (productCategories && productCategories.length > 0)\r\n {\r\n const rows: IRestApiProductCategoryExtended[] = [ ...productCategories ]\r\n .sort((a, b) => a.sortOrder! - b.sortOrder!);\r\n\r\n return (\r\n \r\n\r\n \r\n\r\n }\r\n onClick={ handleAddCategory }>\r\n Add Category\r\n \r\n\r\n \r\n\r\n \r\n\r\n \r\n {\r\n currentProductCategory && (\r\n \r\n )\r\n }\r\n {\r\n currentProductCategory && (\r\n \r\n )\r\n }\r\n {\r\n setAddModalOpen(false) }\r\n />\r\n }\r\n {\r\n selectedRows.includes(cat.id!)) }\r\n />\r\n }\r\n \r\n );\r\n }\r\n\r\n return (\r\n \r\n );\r\n}\r\n\r\nexport default ProductCategoriesMain;\r\n","import * as React from 'react';\r\n\r\nimport { Box, Container, Grid, Typography } from '@mui/material';\r\n\r\nimport StyledPaperComponent from '../../../../components/styled/StyledCardComponents/StyledPaperComponent';\r\nimport ProductCategoriesMain from './ProductCategoriesMain';\r\nimport { UserRole, withSecurity } from '../../../../types/authenticationTypes';\r\n\r\nconst ProductCategoriesAdministration: React.FC<{}> = ({ }) =>\r\n{\r\n return (\r\n \r\n \r\n\r\n \r\n\r\n \r\n \r\n \r\n \r\n Manage your product catalog by adding, editing, or deleting categories. Keep your\r\n inventory up to date with relevant titles, descriptions, and images. Also,\r\n streamline your catalog by removing outdated categories. Manage sorting, stock levels,\r\n and pricing to enhance your customers' shopping experience.\r\n \r\n\r\n \r\n Keep your offerings organized and appealing to boost customer satisfaction and sales.\r\n \r\n \r\n\r\n \r\n\r\n \r\n \r\n \r\n \r\n \r\n );\r\n};\r\n\r\nexport default withSecurity(ProductCategoriesAdministration, UserRole.PowerUser);\r\n","import { useState } from 'react';\r\nimport { IRestApiProductWithImagesDTO } from '../../../../../stores/api/Generated/Entities/RestApiProductWithImagesDTO';\r\n\r\nexport const useFormData = () =>\r\n{\r\n const [ formData, setFormData ] = useState(null);\r\n\r\n const handleChange = (event: React.ChangeEvent) =>\r\n {\r\n const { name, value } = event.target;\r\n setFormData(prevState => ({\r\n ...prevState,\r\n [ name ]: value\r\n }));\r\n };\r\n\r\n const handleCheckboxChange = (event: React.ChangeEvent) =>\r\n {\r\n const { name, checked } = event.target;\r\n setFormData(prevState => ({\r\n ...prevState,\r\n [ name ]: checked\r\n }));\r\n };\r\n\r\n const clearFormData = () =>\r\n {\r\n setFormData(null);\r\n }\r\n\r\n return {\r\n formData,\r\n setFormData,\r\n clearFormData,\r\n handleChange,\r\n handleCheckboxChange\r\n };\r\n};\r\n","import { useState } from 'react';\r\n\r\nexport interface IdEntity\r\n{\r\n\tid?: string;\r\n}\r\n\r\ninterface UseModalPropertyEditorResult\r\n{\r\n\titems: TProperty[];\r\n\tisEditorOpen: boolean;\r\n\topenEditor: () => void;\r\n\tcloseEditor: () => void;\r\n\tsetItems: (items: TProperty[]) => void;\r\n\thandleDeleteItem: (id: string) => void;\r\n\thandleAddItem: () => void;\r\n\thandleSaveItem: (item: TProperty) => void;\r\n\thandleSaveItems: (items: TProperty[]) => void;\r\n\thandleCancelItem: () => void;\r\n}\r\n\r\nexport const useModalPropertyEditor = (): UseModalPropertyEditorResult =>\r\n{\r\n\tconst [ isEditorOpen, setIsEditorOpen ] = useState(false);\r\n\tconst [ items, setItems ] = useState([]);\r\n\r\n\tconst openEditor = () =>\r\n\t{\r\n\t\tsetIsEditorOpen(true);\r\n\t}\r\n\r\n\tconst closeEditor = () =>\r\n\t{\r\n\t\tsetIsEditorOpen(false);\r\n\t}\r\n\r\n\tconst handleDeleteItem = (id: string) =>\r\n\t{\r\n\t\tif (!items || items.length === 0)\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tsetItems(prevState => prevState.filter(item => item.id !== id) || []);\r\n\t};\r\n\r\n\tconst handleAddItem = () =>\r\n\t{\r\n\t\tsetIsEditorOpen(true);\r\n\t};\r\n\r\n\tconst handleSaveItem = (item: TProperty) =>\r\n\t{\r\n\t\tif (!item.id || items.findIndex(i => i.id === item.id) === -1)\r\n\t\t{\r\n\t\t\tsetItems(prevState => ([ ...(prevState || []), item ]));\r\n\t\t}\r\n\r\n\t\tsetIsEditorOpen(false);\r\n\t};\r\n\r\n\tconst handleSaveItems = (items: TProperty[]) =>\r\n\t{\r\n\t\tsetItems(items);\r\n\t\tsetIsEditorOpen(false);\r\n\t};\r\n\r\n\tconst handleCancelItem = () =>\r\n\t{\r\n\t\tsetIsEditorOpen(false);\r\n\t};\r\n\r\n\treturn {\r\n\t\titems,\r\n\t\tisEditorOpen,\r\n\t\topenEditor,\r\n\t\tcloseEditor,\r\n\t\tsetItems,\r\n\t\thandleDeleteItem,\r\n\t\thandleAddItem,\r\n\t\thandleSaveItem,\r\n\t\thandleSaveItems,\r\n\t\thandleCancelItem\r\n\t};\r\n};\r\n","import React, { useState, useEffect } from 'react';\r\nimport {\r\n Button, Dialog, DialogActions, DialogContent, DialogTitle,\r\n Checkbox, ListItemText, CircularProgress,\r\n Box, Typography, Grid, ListItem\r\n} from '@mui/material';\r\nimport { IRestApiProductCategoryDTO } from '../../../../stores/api/Generated/Entities/RestApiProductCategoryDTO';\r\nimport { restApiProductCategories } from '../../../../stores/api/Generated/Endpoints/RestApiProductCategories';\r\nimport { IRestApiProductCategoryMinimalDTO } from '../../../../stores/api/Generated/Entities/RestApiProductCategoryMinimalDTO';\r\n\r\ninterface CategorySelectionModalProps {\r\n open: boolean;\r\n selectedCategories: IRestApiProductCategoryMinimalDTO[];\r\n\r\n onSave: (categories: IRestApiProductCategoryMinimalDTO[]) => void;\r\n onClose: () => void;\r\n}\r\n\r\nconst CategorySelectionModal: React.FC = ({ open, onClose, selectedCategories, onSave }) => {\r\n const [selected, setSelected] = useState(selectedCategories);\r\n\r\n const { data: productCategoryData, error: productCategoryError, isLoading: productCategoryLoading } = restApiProductCategories.hooks.queries.getAllNames();\r\n\r\n useEffect(() => {\r\n if (productCategoryData) {\r\n setSelected(selectedCategories);\r\n }\r\n }, [productCategoryData, selectedCategories]);\r\n\r\n const handleToggle = (category: IRestApiProductCategoryMinimalDTO) => {\r\n const currentIndex = selected.findIndex(c => c.id === category.id);\r\n const newSelected = [...selected];\r\n\r\n if (currentIndex === -1) {\r\n newSelected.push(category);\r\n } else {\r\n newSelected.splice(currentIndex, 1);\r\n }\r\n\r\n setSelected(newSelected);\r\n };\r\n\r\n const handleSave = () => {\r\n onSave(selected);\r\n onClose();\r\n };\r\n\r\n return (\r\n \r\n );\r\n};\r\n\r\nexport default CategorySelectionModal;\r\n","import React from 'react';\r\nimport { Box, Button, List, ListItem, ListItemText, Typography, IconButton, Grid, useTheme } from '@mui/material';\r\nimport DeleteIcon from '@mui/icons-material/Delete';\r\nimport CircleIcon from '@mui/icons-material/Circle';\r\nimport { IRestApiProductColorDTO } from '../../../../../stores/api/Generated/Entities/RestApiProductColorDTO';\r\n\r\ninterface ProductColorListProps\r\n{\r\n productColors: IRestApiProductColorDTO[];\r\n handleDeleteColor: (id: string) => void;\r\n handleAddColor: () => void;\r\n disabled: boolean;\r\n}\r\n\r\nconst ProductColorList: React.FC = ({ productColors, handleDeleteColor, handleAddColor, disabled }) =>\r\n{\r\n const theme = useTheme();\r\n\r\n const onDeleteColor = (event: React.MouseEvent, colorId: string) =>\r\n {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n handleDeleteColor(colorId);\r\n }\r\n return (\r\n\r\n\r\n \r\n \r\n Product Colors\r\n \r\n { productColors.length > 0 ? (\r\n\r\n \r\n { productColors.map((color, index) => (\r\n \r\n \r\n\r\n \r\n\r\n \r\n { index + 1 }. { color.name }\r\n \r\n\r\n \r\n\r\n onDeleteColor(evt, color.id!) }>\r\n \r\n \r\n \r\n )) }\r\n \r\n\r\n ) : (\r\n No colors available\r\n ) }\r\n \r\n \r\n \r\n \r\n )\r\n};\r\n\r\nexport default ProductColorList;\r\n","import React from 'react';\r\nimport { Box, Button, List, ListItem, ListItemText, Typography, IconButton, Grid, Theme, useTheme } from '@mui/material';\r\nimport DeleteIcon from '@mui/icons-material/Delete';\r\nimport { IRestApiProductSizeDTO } from '../../../../../stores/api/Generated/Entities/RestApiProductSizeDTO';\r\n\r\ninterface ProductSizeListProps\r\n{\r\n productSizes: IRestApiProductSizeDTO[];\r\n handleDeleteSize: (id: string) => void;\r\n handleAddSize: () => void;\r\n disabled: boolean;\r\n}\r\n\r\nconst ProductSizeList: React.FC = (props) => \r\n{\r\n const theme: Theme = useTheme();\r\n\r\n const { productSizes, handleDeleteSize, handleAddSize, disabled } = props;\r\n\r\n const onDeleteSize = (event: React.MouseEvent, sizeId: string) =>\r\n {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n handleDeleteSize(sizeId);\r\n }\r\n\r\n return (\r\n \r\n \r\n Product Sizes\r\n \r\n { productSizes.length > 0 ? (\r\n\r\n \r\n\r\n { productSizes.map((size, index) => (\r\n \r\n\r\n \r\n { index + 1 }. { size.value }\r\n \r\n\r\n onDeleteSize(evt, size.id!) }>\r\n \r\n \r\n\r\n \r\n )) }\r\n\r\n \r\n\r\n ) : (\r\n No sizes available\r\n ) }\r\n \r\n \r\n \r\n \r\n )\r\n\r\n};\r\n\r\nexport default ProductSizeList;\r\n","import React from 'react';\r\n\r\nimport { Box, Button, Grid, Theme, Typography, useTheme } from '@mui/material';\r\n\r\nimport IconButton from '@mui/material/IconButton';\r\nimport DeleteIcon from '@mui/icons-material/Delete';\r\n\r\nimport { IRestApiProductCategoryMinimalDTO } from '../../../../../stores/api/Generated/Entities/RestApiProductCategoryMinimalDTO';\r\n\r\n\r\nexport interface IProductCategoryListProps\r\n{\r\n selectedCategories: IRestApiProductCategoryMinimalDTO[];\r\n\r\n setSelectedCategories: (categories: IRestApiProductCategoryMinimalDTO[]) => void;\r\n openCategoryModal: () => void;\r\n}\r\n\r\nconst ProductCategoryList: React.FC = (props: IProductCategoryListProps) =>\r\n{\r\n const theme: Theme = useTheme();\r\n\r\n const { selectedCategories, setSelectedCategories, openCategoryModal } = props;\r\n\r\n const onDeleteCategory = (event: React.MouseEvent, categoryId: string) =>\r\n {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n setSelectedCategories(selectedCategories.filter((category) => category.id !== categoryId));\r\n }\r\n\r\n return (\r\n\r\n \r\n \r\n Product Categories\r\n \r\n\r\n { selectedCategories.length > 0 ? (\r\n\r\n \r\n\r\n { selectedCategories.map((category, index) => (\r\n \r\n\r\n \r\n { index + 1 }. { category.name }\r\n \r\n\r\n onDeleteCategory(evt, category.id!) }>\r\n \r\n \r\n\r\n \r\n )) }\r\n\r\n \r\n\r\n ) : (\r\n \r\n\r\n \r\n No categories selected\r\n \r\n\r\n \r\n ) }\r\n \r\n\r\n \r\n\r\n \r\n \r\n\r\n );\r\n}\r\n\r\nexport default ProductCategoryList;","import React from 'react';\r\nimport { Fragment, useEffect } from 'react';\r\n\r\nimport { Box, Checkbox, FormControlLabel, TextField, useTheme } from '@mui/material';\r\n\r\nimport { IRestApiProductCategoryMinimalDTO } from '../../../../../stores/api/Generated/Entities/RestApiProductCategoryMinimalDTO';\r\nimport { IRestApiProductWithImagesDTO } from '../../../../../stores/api/Generated/Entities/RestApiProductWithImagesDTO';\r\nimport { UseImageEditingResult } from '../../hooks/useImageEditing';\r\n\r\nimport ProductColorList from './ProductColorList';\r\nimport ProductSizeList from './ProductSizeList';\r\nimport ProductCategoryList from './ProductCategoryList';\r\nimport ImageEditComponent from '../../components/ImageEditComponent';\r\n\r\ninterface IProductModalDialogContentProps\r\n{\r\n formData: IRestApiProductWithImagesDTO | null;\r\n selectedCategories: IRestApiProductCategoryMinimalDTO[];\r\n saveDisabled: boolean;\r\n imageEditing: UseImageEditingResult;\r\n\r\n setSelectedCategories: (categories: IRestApiProductCategoryMinimalDTO[]) => void;\r\n handleChange: (event: React.ChangeEvent) => void;\r\n handleCheckboxChange: (event: React.ChangeEvent) => void;\r\n handleDeleteColor: (id: string) => void;\r\n handleAddColor: () => void;\r\n handleDeleteSize: (id: string) => void;\r\n handleAddSize: () => void;\r\n openCategoryModal: () => void;\r\n}\r\n\r\nconst ProductModalDialogContent: React.FC = (props) =>\r\n{\r\n const theme = useTheme();\r\n\r\n const {\r\n formData,\r\n selectedCategories,\r\n saveDisabled,\r\n imageEditing,\r\n setSelectedCategories,\r\n handleChange,\r\n handleCheckboxChange,\r\n handleDeleteColor,\r\n handleAddColor,\r\n handleDeleteSize,\r\n handleAddSize,\r\n openCategoryModal\r\n } = props;\r\n\r\n const {\r\n bannerImage,\r\n thumbnailImage,\r\n handleEditImage\r\n } = imageEditing;\r\n\r\n useEffect(() =>\r\n {\r\n if (formData?.productCategories)\r\n {\r\n setSelectedCategories(formData.productCategories);\r\n }\r\n\r\n }, [ formData?.productCategories ]);\r\n\r\n return (\r\n \r\n \r\n\r\n \r\n\r\n \r\n\r\n \r\n \r\n \r\n \r\n\r\n \r\n\r\n \r\n\r\n \r\n \r\n\r\n \r\n\r\n }\r\n label=\"Available\"\r\n />\r\n\r\n }\r\n label=\"Highlight\"\r\n />\r\n\r\n \r\n \r\n\r\n \r\n \r\n\r\n \r\n\r\n \r\n \r\n\r\n \r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n \r\n \r\n );\r\n};\r\n\r\nexport default ProductModalDialogContent;\r\n","import React, { useEffect, useState } from 'react';\r\n\r\nimport { Box, Button, TextField, Dialog, DialogActions, DialogContent, DialogTitle, Tab, Tabs, Typography, Grid, Link } from '@mui/material';\r\n\r\nimport CircleIcon from '@mui/icons-material/Circle';\r\n\r\nimport { SketchPicker } from 'react-color';\r\nimport { Guid } from '../../../../utilities/Guid';\r\nimport { restApiProducts } from '../../../../stores/api/Generated/Endpoints/RestApiProducts';\r\nimport { IRestApiProductColorDTO } from '../../../../stores/api/Generated/Entities/RestApiProductColorDTO';\r\n\r\nexport type AddProductColorType = 'New' | 'Existing';\r\n\r\ninterface ProductColorEditorModalProps\r\n{\r\n open: boolean;\r\n initialColor?: string;\r\n initialName?: string;\r\n onSave: (colorDTO: IRestApiProductColorDTO) => void;\r\n onCancel: () => void;\r\n}\r\n\r\nconst ProductColorEditorModal: React.FC = (props) =>\r\n{\r\n const { open, initialColor, initialName, onSave, onCancel } = props;\r\n\r\n const { data: allProductColorsData, error: allProductColorsError, isLoading: allProductColorsLoading } = restApiProducts.hooks.queries.getExistingProductColors();\r\n\r\n const [ tabValue, setTabValue ] = useState('existingColor');\r\n const [ currentColor, setCurrentColor ] = useState(null);\r\n\r\n useEffect(() =>\r\n {\r\n if (tabValue === 'newColor')\r\n {\r\n setCurrentColor({\r\n id: Guid.NewGuid().Value,\r\n name: initialName || '',\r\n hexCode: initialColor || '#000000'\r\n });\r\n }\r\n }, [ tabValue ]);\r\n\r\n const handleTabChange = (event: React.SyntheticEvent, newValue: string) =>\r\n {\r\n setTabValue(newValue);\r\n };\r\n\r\n const handleColorSelect = (colorId: string, colorName: string, colorHex: string) =>\r\n {\r\n setCurrentColor({\r\n id: colorId,\r\n name: colorName,\r\n hexCode: colorHex\r\n });\r\n };\r\n\r\n const handleSave = (colorId: string, colorName: string, colorHexCode: string) =>\r\n {\r\n onSave({\r\n id: tabValue === 'existingColor' ? colorId : Guid.NewGuid().Value,\r\n name: colorName,\r\n hexCode: colorHexCode\r\n });\r\n }\r\n\r\n return (\r\n \r\n );\r\n};\r\n\r\nexport default ProductColorEditorModal;\r\n","import React, { useEffect, useState } from 'react';\r\nimport { Box, Button, TextField, Dialog, DialogActions, DialogContent, DialogTitle, Tab, Tabs, Typography, Grid, Link } from '@mui/material';\r\nimport { Guid } from '../../../../utilities/Guid';\r\nimport { restApiProducts } from '../../../../stores/api/Generated/Endpoints/RestApiProducts';\r\nimport { IRestApiProductSizeDTO } from '../../../../stores/api/Generated/Entities/RestApiProductSizeDTO';\r\n\r\nexport type AddProductSizeType = 'New' | 'Existing';\r\n\r\ninterface ProductSizeEditorModalProps\r\n{\r\n open: boolean;\r\n initialSize?: string;\r\n initialOrder?: number;\r\n onSave: (sizeDTO: IRestApiProductSizeDTO) => void;\r\n onCancel: () => void;\r\n}\r\n\r\nconst ProductSizeEditorModal: React.FC = (props) =>\r\n{\r\n const { open, initialSize, initialOrder, onSave, onCancel } = props;\r\n\r\n const { data: allProductSizesData, error: allProductSizesError, isLoading: allProductSizesLoading } = restApiProducts.hooks.queries.getExistingProductSizes();\r\n\r\n const [ tabValue, setTabValue ] = useState('existingSize');\r\n const [ currentSize, setCurrentSize ] = useState(null);\r\n\r\n useEffect(() =>\r\n {\r\n if (tabValue === 'newSize')\r\n {\r\n setCurrentSize({\r\n id: Guid.NewGuid().Value,\r\n value: '',\r\n displayOrder: 0\r\n });\r\n }\r\n\r\n }, [ tabValue ]);\r\n\r\n const handleTabChange = (event: React.SyntheticEvent, newValue: string) =>\r\n {\r\n setTabValue(newValue);\r\n };\r\n\r\n const handleSizeSelect = (sizeId: string, sizeValue: string, displayOrder: number) =>\r\n {\r\n setCurrentSize({\r\n id: sizeId,\r\n value: sizeValue,\r\n displayOrder\r\n });\r\n };\r\n\r\n const handleSave = (sizeId: string, sizeValue: string, displayOrder: number) =>\r\n {\r\n onSave({\r\n id: tabValue === 'existingSize' ? sizeId : Guid.NewGuid().Value,\r\n value: sizeValue,\r\n displayOrder\r\n });\r\n }\r\n\r\n return (\r\n \r\n );\r\n};\r\n\r\nexport default ProductSizeEditorModal;\r\n","import React from 'react';\r\nimport { Button, DialogActions } from '@mui/material';\r\nimport CancelIcon from '@mui/icons-material/Cancel';\r\nimport SaveIcon from '@mui/icons-material/Save';\r\n\r\ninterface ProductDialogActionsProps\r\n{\r\n onCancel: () => void;\r\n onSave: () => void;\r\n saveDisabled: boolean; // Add saveDisabled prop\r\n}\r\n\r\nconst ProductDialogActions: React.FC = ({ onCancel, onSave, saveDisabled }) =>\r\n{\r\n return (\r\n \r\n }>\r\n Cancel\r\n \r\n } disabled={ saveDisabled }>\r\n Save\r\n \r\n \r\n );\r\n};\r\n\r\nexport default ProductDialogActions;\r\n","import React, { Fragment, useEffect } from 'react';\r\nimport { Dialog, DialogContent, DialogTitle, CircularProgress, Box } from '@mui/material';\r\n\r\nimport { restApiProducts } from '../../../../stores/api/Generated/Endpoints/RestApiProducts';\r\nimport { useFormData } from './hooks/useFormData';\r\nimport { useModalPropertyEditor } from '../hooks/useModalPropertyEditor';\r\nimport { useImageEditing } from '../hooks/useImageEditing';\r\nimport { RestApiProductDTO } from '../../../../stores/api/Generated/Entities/RestApiProductDTO';\r\nimport { IRestApiProductCategoryMinimalDTO, RestApiProductCategoryMinimalDTO } from '../../../../stores/api/Generated/Entities/RestApiProductCategoryMinimalDTO';\r\nimport { IRestApiProductWithImagesDTO } from '../../../../stores/api/Generated/Entities/RestApiProductWithImagesDTO';\r\nimport { IRestApiProductColorDTO } from '../../../../stores/api/Generated/Entities/RestApiProductColorDTO';\r\nimport { IRestApiProductSizeDTO } from '../../../../stores/api/Generated/Entities/RestApiProductSizeDTO';\r\n\r\nimport CategorySelectionModal from './CategorySelectionModal';\r\nimport ProductModalDialogContent from './components/ProductModalDialogContent';\r\nimport ProductColorEditorModal from './ProductColorEditorModal';\r\nimport ProductSizeEditorModal from './ProductSizeEditorModal';\r\nimport ProductDialogActions from './components/ProductDialogActions';\r\nimport ImageCropperModal from '../../../../components/ImageCropperModal';\r\nimport useLoadingDialog from '../../../../hooks/useLoadingDialog';\r\n\r\n\r\ninterface IEditProductModalProps\r\n{\r\n open: boolean;\r\n currentProductId: string;\r\n currentProductName: string;\r\n onClose: () => void;\r\n}\r\n\r\nconst EditProductModal: React.FC = (props) =>\r\n{\r\n const { open, currentProductId, currentProductName, onClose } = props;\r\n\r\n const { formData, setFormData, clearFormData, handleChange, handleCheckboxChange } = useFormData();\r\n const { data: productData, error: productError, isLoading: productLoading } = restApiProducts.hooks.queries.getByIdWithImages({ id: currentProductId });\r\n const [ patchProduct ] = restApiProducts.hooks.mutations.update();\r\n const { showWithMessage, hide } = useLoadingDialog();\r\n\r\n const {\r\n bannerImage,\r\n thumbnailImage,\r\n imageToEdit,\r\n setImage,\r\n removeImage,\r\n clearImages,\r\n handleEditImage,\r\n handleCropSave,\r\n setImageToEdit\r\n } = useImageEditing();\r\n\r\n const {\r\n items: productColors,\r\n isEditorOpen: isColorEditorOpen,\r\n setItems: setProductColors,\r\n openEditor: openColorEditor,\r\n closeEditor: closeColorEditor,\r\n handleDeleteItem: handleDeleteColor,\r\n handleAddItem: handleAddColor,\r\n handleSaveItem: handleSaveColor,\r\n handleSaveItems: handleSaveColors,\r\n handleCancelItem: handleCancelColor\r\n } = useModalPropertyEditor();\r\n\r\n const {\r\n items: productSizes,\r\n isEditorOpen: isSizeEditorOpen,\r\n openEditor: openSizeEditor,\r\n closeEditor: closeSizeEditor,\r\n setItems: setProductSizes,\r\n handleDeleteItem: handleDeleteSize,\r\n handleAddItem: handleAddSize,\r\n handleSaveItem: handleSaveSize,\r\n handleSaveItems: handleSaveSizes,\r\n handleCancelItem: handleCancelSize,\r\n } = useModalPropertyEditor();\r\n\r\n const {\r\n items: selectedCategories,\r\n isEditorOpen: isCategoryModalOpen,\r\n openEditor: openCategoryEditor,\r\n closeEditor: closeCategoryEditor,\r\n setItems: setSelectedCategories,\r\n handleDeleteItem: handleDeleteCategory,\r\n handleAddItem: handleAddCategory,\r\n handleSaveItem: handleSaveCategory,\r\n handleSaveItems: handleSaveCategories,\r\n handleCancelItem: handleCancelCategory,\r\n } = useModalPropertyEditor();\r\n\r\n useEffect(() =>\r\n {\r\n if (open && currentProductId)\r\n {\r\n clearFormData(); // Clear form data before loading new product data\r\n clearImages(); // Clear images before loading new ones\r\n }\r\n }, [ open, currentProductId ]);\r\n\r\n useEffect(() =>\r\n {\r\n if (productLoading)\r\n {\r\n showWithMessage(`Loading Product '${currentProductName}'...`);\r\n\r\n return;\r\n }\r\n\r\n hide();\r\n\r\n }, [ productLoading ]);\r\n\r\n\r\n useEffect(() =>\r\n {\r\n if (productData)\r\n {\r\n setFormData(productData);\r\n\r\n if (productData.productColors && productData.productColors.length > 0)\r\n {\r\n const currColors = productData.productColors;\r\n setProductColors(currColors);\r\n }\r\n\r\n if (productData.productSizes && productData.productSizes.length > 0)\r\n {\r\n const currSizes = productData.productSizes;\r\n setProductSizes(currSizes);\r\n }\r\n\r\n if (productData.productCategories && productData.productCategories.length > 0)\r\n {\r\n const currCategories = productData.productCategories;\r\n setSelectedCategories(currCategories);\r\n }\r\n\r\n if (productData.bannerImage)\r\n {\r\n setImage(productData.bannerImage);\r\n }\r\n\r\n if (productData.thumbnailImage)\r\n {\r\n setImage(productData.thumbnailImage);\r\n }\r\n }\r\n }, [ productData ]);\r\n\r\n useEffect(() =>\r\n {\r\n setFormData(prevState => ({\r\n ...prevState,\r\n productColors: productColors\r\n }));\r\n\r\n }, [ productColors ]);\r\n\r\n useEffect(() =>\r\n {\r\n setFormData(prevState => ({\r\n ...prevState,\r\n productSizes: productSizes\r\n }));\r\n\r\n }, [ productSizes ]);\r\n\r\n const clearStateAndClose = () =>\r\n {\r\n setFormData(null);\r\n clearImages();\r\n onClose();\r\n }\r\n\r\n const handleSubmit = () =>\r\n {\r\n try\r\n {\r\n if (!formData)\r\n {\r\n onClose();\r\n return;\r\n }\r\n\r\n showWithMessage(`Saving Product '${formData.name}'...`);\r\n\r\n const updatedProductDTO: IRestApiProductWithImagesDTO = {\r\n ...formData,\r\n productCategories: selectedCategories,\r\n bannerImage: bannerImage,\r\n thumbnailImage: thumbnailImage,\r\n };\r\n\r\n patchProduct({ productWithImagesDTO: updatedProductDTO })\r\n .unwrap() // Unwrap the promise to handle the result in the .then() block\r\n .finally(() =>\r\n {\r\n clearStateAndClose();\r\n hide();\r\n });\r\n\r\n } catch (error)\r\n {\r\n console.error(\"Error in handleSubmit:\", error);\r\n hide();\r\n }\r\n };\r\n\r\n return (\r\n \r\n \r\n\r\n { imageToEdit && (\r\n setImageToEdit(null) }\r\n onSave={ handleCropSave }\r\n />\r\n ) }\r\n { isCategoryModalOpen && (\r\n \r\n ) }\r\n\r\n { isColorEditorOpen && (\r\n handleSaveColor(colorDTO) }\r\n />\r\n ) }\r\n\r\n { isSizeEditorOpen && (\r\n handleSaveSize(sizeDTO) }\r\n />\r\n ) }\r\n \r\n );\r\n};\r\n\r\nexport default EditProductModal;\r\n","import * as React from 'react';\r\nimport { useEffect, useState } from 'react';\r\nimport { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, TextField } from '@mui/material';\r\nimport { restApiProducts } from '../../../../stores/api/Generated/Endpoints/RestApiProducts';\r\nimport DeleteIcon from '@mui/icons-material/Delete';\r\nimport CancelIcon from '@mui/icons-material/Cancel';\r\nimport { IRestApiProductDTO } from '../../../../stores/api/Generated/Entities/RestApiProductDTO';\r\n\r\ninterface DeleteProductModalProps\r\n{\r\n open: boolean;\r\n onClose: () => void;\r\n currentProduct: IRestApiProductDTO;\r\n}\r\n\r\nconst DeleteProductModal: React.FC = ({ open, onClose, currentProduct }) =>\r\n{\r\n const [ inputValue, setInputValue ] = useState('');\r\n\r\n const [ deleteProduct ] = restApiProducts.hooks.mutations.deleteById();\r\n\r\n useEffect(() =>\r\n {\r\n if (!open)\r\n {\r\n setInputValue('');\r\n }\r\n\r\n }, [ open ]);\r\n\r\n const handleInputChange = (event: React.ChangeEvent) =>\r\n {\r\n setInputValue(event.target.value);\r\n };\r\n\r\n const handleConfirm = () =>\r\n {\r\n if (inputValue === currentProduct.name)\r\n {\r\n try\r\n {\r\n deleteProduct({ id: currentProduct.id! });\r\n\r\n onClose();\r\n }\r\n catch (error)\r\n {\r\n console.error(\"Error in deleteProduct:\", error);\r\n }\r\n }\r\n };\r\n\r\n return (\r\n \r\n );\r\n};\r\n\r\nexport default DeleteProductModal;\r\n","import React, { Fragment, useEffect } from 'react';\r\nimport { Dialog, DialogContent, DialogTitle } from '@mui/material';\r\n\r\nimport { restApiProducts } from '../../../../stores/api/Generated/Endpoints/RestApiProducts';\r\n\r\nimport { useFormData } from './hooks/useFormData';\r\nimport { Guid } from '../../../../utilities/Guid';\r\nimport { useImageEditing } from '../hooks/useImageEditing';\r\nimport { useModalPropertyEditor } from '../hooks/useModalPropertyEditor';\r\nimport { IRestApiProductDTO, RestApiProductDTO } from '../../../../stores/api/Generated/Entities/RestApiProductDTO';\r\nimport { IRestApiProductCategoryMinimalDTO, RestApiProductCategoryMinimalDTO } from '../../../../stores/api/Generated/Entities/RestApiProductCategoryMinimalDTO';\r\nimport { IRestApiProductWithImagesDTO, RestApiProductWithImagesDTO } from '../../../../stores/api/Generated/Entities/RestApiProductWithImagesDTO';\r\nimport { IRestApiProductColorDTO } from '../../../../stores/api/Generated/Entities/RestApiProductColorDTO';\r\nimport { IRestApiProductSizeDTO } from '../../../../stores/api/Generated/Entities/RestApiProductSizeDTO';\r\n\r\nimport CategorySelectionModal from './CategorySelectionModal';\r\nimport ProductModalDialogContent from './components/ProductModalDialogContent';\r\nimport ProductColorEditorModal from './ProductColorEditorModal';\r\nimport ProductSizeEditorModal from './ProductSizeEditorModal';\r\nimport ImageCropperModal from '../../../../components/ImageCropperModal';\r\nimport ProductDialogActions from './components/ProductDialogActions';\r\nimport useLoadingDialog from '../../../../hooks/useLoadingDialog';\r\n\r\ninterface IAddProductModalProps\r\n{\r\n open: boolean;\r\n onClose: () => void;\r\n}\r\n\r\nconst AddProductModal: React.FC = ({ open, onClose }) =>\r\n{\r\n const initialFormData: IRestApiProductDTO = {\r\n id: '',\r\n name: '',\r\n code: '',\r\n title: '',\r\n description: '',\r\n bannerImageId: null,\r\n thumbnailImageId: null,\r\n stockQuantity: 0,\r\n regularPrice: 0,\r\n liquidationPrice: 0,\r\n available: false,\r\n highlight: false,\r\n sortOrder: 0,\r\n productCategories: [],\r\n productColors: [],\r\n productSizes: [],\r\n };\r\n\r\n const { formData, setFormData, clearFormData, handleChange, handleCheckboxChange } = useFormData();\r\n const [ createProduct ] = restApiProducts.hooks.mutations.create();\r\n const { showWithMessage, hide } = useLoadingDialog();\r\n\r\n const {\r\n bannerImage,\r\n thumbnailImage,\r\n imageToEdit,\r\n setImage,\r\n removeImage,\r\n clearImages,\r\n handleEditImage,\r\n handleCropSave,\r\n setImageToEdit\r\n } = useImageEditing();\r\n\r\n const {\r\n items: productColors,\r\n isEditorOpen: isColorEditorOpen,\r\n setItems: setProductColors,\r\n openEditor: openColorEditor,\r\n closeEditor: closeColorEditor,\r\n handleDeleteItem: handleDeleteColor,\r\n handleAddItem: handleAddColor,\r\n handleSaveItem: handleSaveColor,\r\n handleSaveItems: handleSaveColors,\r\n handleCancelItem: handleCancelColor\r\n } = useModalPropertyEditor();\r\n\r\n const {\r\n items: productSizes,\r\n isEditorOpen: isSizeEditorOpen,\r\n openEditor: openSizeEditor,\r\n closeEditor: closeSizeEditor,\r\n setItems: setProductSizes,\r\n handleDeleteItem: handleDeleteSize,\r\n handleAddItem: handleAddSize,\r\n handleSaveItem: handleSaveSize,\r\n handleSaveItems: handleSaveSizes,\r\n handleCancelItem: handleCancelSize,\r\n } = useModalPropertyEditor();\r\n\r\n const {\r\n items: selectedCategories,\r\n isEditorOpen: isCategoryModalOpen,\r\n openEditor: openCategoryEditor,\r\n closeEditor: closeCategoryEditor,\r\n setItems: setSelectedCategories,\r\n handleDeleteItem: handleDeleteCategory,\r\n handleAddItem: handleAddCategory,\r\n handleSaveItem: handleSaveCategory,\r\n handleSaveItems: handleSaveCategories,\r\n handleCancelItem: handleCancelCategory,\r\n } = useModalPropertyEditor();\r\n\r\n useEffect(() =>\r\n {\r\n if (!formData)\r\n {\r\n setFormData(initialFormData);\r\n }\r\n }, []);\r\n\r\n useEffect(() =>\r\n {\r\n setFormData(prevState => ({\r\n ...prevState,\r\n productColors: productColors\r\n }));\r\n\r\n }, [ productColors ]);\r\n\r\n useEffect(() =>\r\n {\r\n setFormData(prevState => ({\r\n ...prevState,\r\n productSizes: productSizes\r\n }));\r\n\r\n }, [ productSizes ]);\r\n\r\n const clearStateAndClose = () =>\r\n {\r\n setFormData(null);\r\n clearImages();\r\n setSelectedCategories([]);\r\n onClose();\r\n };\r\n\r\n const handleSubmit = () =>\r\n {\r\n try\r\n {\r\n if (!formData)\r\n {\r\n onClose();\r\n return;\r\n }\r\n\r\n showWithMessage(`Saving New Product '${formData.name}'...`);\r\n\r\n const newProductDTO: IRestApiProductWithImagesDTO = {\r\n ...formData,\r\n productCategories: selectedCategories.map(category => new RestApiProductCategoryMinimalDTO(category)),\r\n bannerImage: bannerImage,\r\n thumbnailImage: thumbnailImage,\r\n };\r\n\r\n newProductDTO.id = Guid.NewGuid().Value;\r\n\r\n createProduct({ productWithImagesDTO: newProductDTO })\r\n .unwrap() // Unwrap the promise to handle the result in the .then() block\r\n .finally(() =>\r\n {\r\n clearStateAndClose();\r\n hide();\r\n });\r\n\r\n onClose();\r\n\r\n } catch (error)\r\n {\r\n console.error(\"Error in handleSubmit:\", error);\r\n hide();\r\n }\r\n };\r\n\r\n return (\r\n \r\n \r\n\r\n { imageToEdit && (\r\n setImageToEdit(null) }\r\n onSave={ handleCropSave }\r\n />\r\n ) }\r\n { isCategoryModalOpen && (\r\n \r\n ) }\r\n\r\n { isColorEditorOpen && (\r\n handleSaveColor(colorDTO) }\r\n />\r\n ) }\r\n\r\n { isSizeEditorOpen && (\r\n handleSaveSize(sizeDTO) }\r\n />\r\n ) }\r\n \r\n );\r\n};\r\n\r\nexport default AddProductModal;\r\n","import React, { useState, useEffect } from 'react';\r\nimport\r\n{\r\n Box, Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Grid, TextField, Typography\r\n} from '@mui/material';\r\n\r\nimport DeleteIcon from '@mui/icons-material/Delete';\r\nimport CancelIcon from '@mui/icons-material/Cancel';\r\n\r\nimport { restApiProducts } from '../../../../stores/api/Generated/Endpoints/RestApiProducts';\r\nimport { notNullOrUndefined } from '../../../../utilities/Utils';\r\nimport { RestApiMultipleIdsDTO } from '../../../../stores/api/Generated/Entities/RestApiMultipleIdsDTO';\r\nimport { IRestApiProductDTO } from '../../../../stores/api/Generated/Entities/RestApiProductDTO';\r\n\r\ninterface DeleteMultipleProductsModalProps\r\n{\r\n open: boolean;\r\n onClose: () => void;\r\n ProductsToDelete: IRestApiProductDTO[];\r\n}\r\n\r\nconst DeleteMultipleProductsModal: React.FC = ({ open, onClose, ProductsToDelete }) =>\r\n{\r\n const [ ProductNameInput, setProductNameInput ] = useState('');\r\n const [ numberInput, setNumberInput ] = useState('');\r\n const [ randomSixDigitNumber, setRandomSixDigitNumber ] = useState('');\r\n const [ randomIndex, setRandomIndex ] = useState(0);\r\n const [ deleteProductRange ] = restApiProducts.hooks.mutations.deleteMultipleById();\r\n\r\n useEffect(() =>\r\n {\r\n if (ProductsToDelete.length > 0)\r\n {\r\n setRandomIndex(Math.floor(Math.random() * ProductsToDelete.length));\r\n setRandomSixDigitNumber(Math.floor(100000 + Math.random() * 900000).toString());\r\n }\r\n }, [ ProductsToDelete ]);\r\n\r\n const randomProductName = ProductsToDelete.length > 0 ?\r\n notNullOrUndefined(ProductsToDelete[ randomIndex ]?.name)\r\n ? ProductsToDelete[ randomIndex ].name\r\n : ''\r\n : '';\r\n\r\n const noOfProducts = ProductsToDelete.length;\r\n\r\n const handleProductNameChange = (event: React.ChangeEvent) =>\r\n {\r\n setProductNameInput(event.target.value);\r\n };\r\n\r\n const handleNumberChange = (event: React.ChangeEvent) =>\r\n {\r\n setNumberInput(event.target.value);\r\n };\r\n\r\n const handleConfirm = () =>\r\n {\r\n if (ProductNameInput === randomProductName && numberInput === randomSixDigitNumber)\r\n {\r\n deleteProducts(ProductsToDelete.map(cat => cat.id!));\r\n }\r\n };\r\n\r\n const deleteProducts = async (ids: string[]) =>\r\n {\r\n try\r\n {\r\n const deleteProducts = new RestApiMultipleIdsDTO();\r\n deleteProducts.ids = [ ...ids ];\r\n\r\n await deleteProductRange({ multipleIdsDTO: deleteProducts });\r\n\r\n onClose();\r\n }\r\n catch (error)\r\n {\r\n console.error(\"Error in deleteProducts:\", error);\r\n }\r\n };\r\n\r\n return (\r\n \r\n );\r\n};\r\n\r\nexport default DeleteMultipleProductsModal;\r\n","import React, { useState, useEffect, Fragment } from 'react';\r\nimport { nanoid } from 'nanoid/non-secure';\r\nimport { Box, Button, Checkbox, FormControl, IconButton, InputAdornment, InputLabel, ListItemText, MenuItem, Link as MuiLink, OutlinedInput, Select, SelectChangeEvent, Typography, useTheme } from '@mui/material';\r\nimport { GridColDef, GridColumnVisibilityModel, GridRenderCellParams, GridRowId, GridRowModes, GridRowModesModel, GridValidRowModel } from '@mui/x-data-grid';\r\n\r\nimport AddIcon from '@mui/icons-material/Add';\r\nimport CloseIcon from '@mui/icons-material/Close';\r\n\r\nimport { restApiProducts } from '../../../../stores/api/Generated/Endpoints/RestApiProducts';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport {slugify} from '../../../../utilities/StringUtils';\r\nimport { Guid } from '../../../../utilities/Guid';\r\nimport { IRestApiProductDTO } from '../../../../stores/api/Generated/Entities/RestApiProductDTO';\r\nimport { IRestApiProductColorDTO } from '../../../../stores/api/Generated/Entities/RestApiProductColorDTO';\r\nimport { IRestApiProductSizeDTO } from '../../../../stores/api/Generated/Entities/RestApiProductSizeDTO';\r\nimport { restApiImages } from '../../../../stores/api/Generated/Endpoints/RestApiImages';\r\n\r\nimport EditProductModal from './EditProductModal';\r\nimport DeleteProductModal from './DeleteProductModal';\r\nimport AddProductModal from './AddProductModal';\r\nimport DeleteMultipleProductsModal from './DeleteMultipleProductsModal';\r\nimport GridRowImageWithFallback from '../components/GridRowImageWithFallback';\r\nimport CommonDataGrid from '../components/CommonDataGrid';\r\nimport CommonDataGridActions from '../components/CommonDataGridActions';\r\nimport CommonDataGridDescriptionField from '../components/CommonDataGridDescriptionField';\r\n\r\nimport { restApiProductCategories } from '../../../../stores/api/Generated/Endpoints/RestApiProductCategories';\r\nimport { isNullOrUndefined } from '../../../../utilities/Utils';\r\nimport { GridInitialStateCommunity } from '@mui/x-data-grid/models/gridStateCommunity';\r\n\r\n\r\ninterface IRestApiProductExtended extends IRestApiProductDTO, GridValidRowModel {\r\n isNew: boolean;\r\n cacheValue: Guid;\r\n}\r\n\r\ntype VisibilityModel = {\r\n [K in keyof IRestApiProductDTO]?: boolean;\r\n};\r\n\r\ntype ProductColumnVisibilityModel = GridColumnVisibilityModel & VisibilityModel;\r\n\r\nconst ProductsMain: React.FC<{}> = ({ }) => {\r\n const theme = useTheme();\r\n const navigate = useNavigate();\r\n\r\n const [Products, setProducts] = useState([]);\r\n\r\n const { data: allProductsData, error: allProductsError, isLoading: allProductsLoading } = restApiProducts.hooks.queries.getAll();\r\n const { data: allCategoriesData, error: allCategoriesError, isLoading: allCategoriesLoading } = restApiProductCategories.hooks.queries.getAllMinimal();\r\n\r\n const [triggerProductImage, productImageResult] = restApiImages.hooks.lazyQueries.getImage();\r\n\r\n const [rowModesModel, setRowModesModel] = useState({});\r\n const [currentProduct, setCurrentProduct] = useState(null);\r\n const [editModalOpen, setEditModalOpen] = useState(false);\r\n const [deleteModalOpen, setDeleteModalOpen] = useState(false);\r\n const [addModalOpen, setAddModalOpen] = useState(false);\r\n const [deleteMultipleModalOpen, setDeleteMultipleModalOpen] = useState(false);\r\n const [selectedRows, setSelectedRows] = useState([]);\r\n\r\n const [productColors, setProductColors] = useState([]);\r\n const [productSizes, setProductSizes] = useState([]);\r\n const [selectedCategories, setSelectedCategories] = useState([]);\r\n const [columnVisibilityModel, setColumnVisibilityModel] = React.useState({ isDeleted: false });\r\n\r\n const initialStateModel: GridInitialStateCommunity = {\r\n filter: {\r\n filterModel: {\r\n items: [\r\n {\r\n field: 'isDeleted',\r\n operator: 'is',\r\n value: 'false',\r\n },\r\n ]\r\n }\r\n },\r\n };\r\n\r\n useEffect(() => {\r\n if (allProductsData) {\r\n // If selectedCategory is null, show all products; otherwise, filter by category\r\n const filteredProducts = isNullOrUndefined(selectedCategories) || selectedCategories.length === 0\r\n ? allProductsData\r\n : allProductsData.filter(product =>\r\n product.productCategories?.some(category => selectedCategories.includes(category.id!))\r\n );\r\n\r\n const extendedProducts = filteredProducts.map((product: IRestApiProductDTO) => ({\r\n ...product,\r\n isNew: false,\r\n cacheValue: Guid.NewGuid(),\r\n }));\r\n\r\n setProducts(extendedProducts as IRestApiProductExtended[]);\r\n }\r\n }, [allProductsData, selectedCategories]);\r\n\r\n\r\n useEffect(() => {\r\n if (editModalOpen) {\r\n resetStates();\r\n }\r\n }, [editModalOpen]);\r\n\r\n const handleEditClick = (id: GridRowId) => (event: React.MouseEvent) => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n console.log('Edit clicked', id);\r\n\r\n const product = Products.find(cat => cat.id === id);\r\n\r\n if (product) {\r\n setProductColors(product.productColors || []);\r\n setProductSizes(product.productSizes || []);\r\n setCurrentProduct(product);\r\n setEditModalOpen(true);\r\n }\r\n };\r\n\r\n const resetStates = () => {\r\n //setProductImages({ bannerImage: '', thumbnailImage: '' });\r\n setProductColors([]);\r\n setProductSizes([]);\r\n };\r\n\r\n const handleSaveClick = (id: GridRowId) => () => {\r\n setRowModesModel({ ...rowModesModel, [id]: { mode: GridRowModes.View } });\r\n };\r\n\r\n const handleDeleteClick = (id: GridRowId) => () => {\r\n const product = Products.find(cat => cat.id === id);\r\n if (product) {\r\n setCurrentProduct(product);\r\n setDeleteModalOpen(true);\r\n }\r\n };\r\n\r\n const handleCancelClick = (id: GridRowId) => () => {\r\n setRowModesModel({\r\n ...rowModesModel,\r\n [id]: { mode: GridRowModes.View, ignoreModifications: true },\r\n });\r\n };\r\n\r\n const handleDeleteDialogClose = () => {\r\n setDeleteModalOpen(false);\r\n };\r\n\r\n\r\n const handleAddProduct = () => {\r\n setAddModalOpen(true);\r\n };\r\n\r\n const handleSelectionChange = (newSelection: GridRowId[]) => {\r\n setSelectedRows(newSelection);\r\n };\r\n\r\n const handleDeleteAllCheckedRows = () => {\r\n setDeleteMultipleModalOpen(true);\r\n };\r\n\r\n const handleDeleteMultipleDialogClose = () => {\r\n setDeleteMultipleModalOpen(false);\r\n };\r\n\r\n const handleCategoryChange = (event: SelectChangeEvent) => {\r\n const { target: { value }, } = event;\r\n const values = typeof value === 'string' ? value.split(',') : value;\r\n\r\n setSelectedCategories(values);\r\n };\r\n\r\n const handleColumnVisibilityChange = (newModel: ProductColumnVisibilityModel) => {\r\n setColumnVisibilityModel(newModel);\r\n };\r\n\r\n if (allProductsLoading) return Loading...
;\r\n if (allProductsError) return Error: { `${allProductsError}` }
;\r\n\r\n\r\n const columns: GridColDef[] = [\r\n {\r\n field: 'isDeleted',\r\n headerName: 'Deleted',\r\n editable: false,\r\n type: 'boolean',\r\n flex: 1,\r\n minWidth: 100,\r\n headerClassName: 'column-header',\r\n hideable: true\r\n },\r\n {\r\n field: 'name',\r\n headerName: 'Name',\r\n editable: false,\r\n type: 'string',\r\n flex: 2,\r\n minWidth: 50,\r\n headerClassName: 'column-header',\r\n renderCell: (params: GridRenderCellParams) => {\r\n const handleClick = (event: React.MouseEvent) => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n navigate(`/products/${slugify(params.value)}`, { state: { productId: params.row.id } });\r\n };\r\n return (\r\n \r\n { params.value }\r\n \r\n );\r\n },\r\n },\r\n {\r\n field: 'code',\r\n headerName: 'Code',\r\n editable: false,\r\n type: 'string',\r\n flex: 1,\r\n minWidth: 100,\r\n headerClassName: 'column-header',\r\n },\r\n {\r\n field: 'title',\r\n headerName: 'Title',\r\n editable: false,\r\n type: 'string',\r\n flex: 1.25,\r\n minWidth: 150,\r\n headerClassName: 'column-header',\r\n },\r\n {\r\n field: 'description',\r\n headerName: 'Description',\r\n editable: false,\r\n type: 'string',\r\n flex: 3,\r\n minWidth: 300,\r\n headerClassName: 'column-header',\r\n renderCell: (params) => (\r\n \r\n ),\r\n },\r\n {\r\n field: 'sortOrder',\r\n headerName: 'Order',\r\n editable: false,\r\n type: 'number',\r\n flex: 0.5,\r\n minWidth: 50,\r\n headerClassName: 'column-header',\r\n },\r\n {\r\n field: 'bannerImage',\r\n headerName: 'Image',\r\n sortable: false,\r\n flex: 0.5,\r\n minWidth: 50,\r\n headerClassName: 'column-header',\r\n renderCell: (params) => {\r\n return ();\r\n }\r\n },\r\n {\r\n field: 'thumbnailImage',\r\n headerName: 'Thumb',\r\n sortable: false,\r\n flex: 0.5,\r\n minWidth: 50,\r\n renderCell: (params) => {\r\n return ();\r\n },\r\n },\r\n {\r\n field: 'actions',\r\n headerName: 'Actions',\r\n editable: false,\r\n sortable: false,\r\n flex: 0.5,\r\n minWidth: 100,\r\n headerClassName: 'column-header',\r\n renderCell: (params: GridRenderCellParams) =>\r\n (\r\n \r\n ),\r\n },\r\n ];\r\n\r\n if (allProductsData && allProductsData.length > 0) {\r\n const rows: IRestApiProductExtended[] = [...Products].sort((a, b) => a.sortOrder! - b.sortOrder!);\r\n\r\n return (\r\n \r\n\r\n \r\n\r\n \r\n Filter products:\r\n \r\n\r\n \r\n\r\n Category Filter(s)\r\n\r\n \r\n\r\n \r\n\r\n\r\n }\r\n onClick={ handleAddProduct }>\r\n Add Product\r\n \r\n\r\n \r\n\r\n \r\n\r\n\r\n \r\n { currentProduct && (\r\n setEditModalOpen(false) } />\r\n ) }\r\n { currentProduct && (\r\n \r\n ) }\r\n setAddModalOpen(false) } />\r\n selectedRows.includes(cat.id!)) } />\r\n \r\n );\r\n }\r\n\r\n return ;\r\n};\r\n\r\nexport default ProductsMain;\r\n\r\n","import * as React from 'react';\r\n\r\nimport { Box, Container, Grid, Typography } from '@mui/material';\r\n\r\nimport StyledPaperComponent from '../../../../components/styled/StyledCardComponents/StyledPaperComponent';\r\nimport { UserRole, withSecurity } from '../../../../types/authenticationTypes';\r\nimport ProductsMain from './ProductsMain';\r\n\r\nconst ProductsAdministration: React.FC<{}> = ({ }) =>\r\n{\r\n return (\r\n \r\n \r\n\r\n \r\n\r\n \r\n \r\n \r\n \r\n Manage your product listings by adding, editing, or deleting individual products. Ensure each\r\n product is up to date with accurate names, descriptions, pricing, and images. Adjust stock quantities,\r\n highlight key items, and set liquidation prices to optimize sales and inventory.\r\n \r\n\r\n \r\n Organize products with relevant categories, sizes, colors, and weights to provide a tailored shopping\r\n experience. Keep your product offerings attractive and easily navigable to boost customer satisfaction and sales.\r\n \r\n \r\n\r\n\r\n \r\n\r\n \r\n \r\n \r\n \r\n \r\n );\r\n};\r\n\r\nexport default withSecurity(ProductsAdministration, UserRole.PowerUser);\r\n"],"names":["sx","display","height","flexDirection","overflowX","StyledDataGrid","styled","DataGrid","theme","border","borderRadius","outline","fontWeight","backgroundColor","palette","secondary","main","color","contrastText","props","useTheme","rows","columns","showSelectionBox","initialState","columnVisibilityModel","handleSelectionChange","onColumnVisibilityModelChange","rest","handleVisibilityChange","visibilityModel","defaultInitialState","pagination","paginationModel","page","pageSize","mergedInitialState","pageSizeOptions","checkboxSelection","onRowSelectionModelChange","newSelection","StyledGridActionsCellItem","GridActionsCellItem","primary","boxShadow","params","rowModesModel","handleSaveClick","handleCancelClick","handleEditClick","handleDeleteClick","isInEditMode","row","id","mode","Edit","Fragment","Box","icon","Save","label","success","onClick","Cancel","warning","evt","Delete","error","text","alignItems","variant","fontSize","textAlign","WebkitBoxOrient","WebkitLineClamp","overflow","textOverflow","whiteSpace","src","alt","hasError","setHasError","useState","imgAlt","justifyContent","width","NoPhotographyTwoTone","style","onError","imageId","imageType","imageUrl","GetImageData","image","imageData","margin","maxWidth","maxHeight","handleEditImage","handleDeleteImage","imgTitle","minHeight","p","position","Typography","gutterBottom","Button","startIcon","bottom","right","opacity","transition","useImageEditing","bannerImage","setBannerImage","undefined","thumbnailImage","setThumbnailImage","originalBannerImage","setOriginalBannerImage","originalThumbnailImage","setOriginalThumbnailImage","imageToEdit","setImageToEdit","setImage","removeImage","clearImages","base64Image","handleCropSave","croppedImage","split","newBannerImage","NewGuid","Value","newThumbnailImage","open","onClose","categoriesToDelete","categoryNameInput","setCategoryNameInput","numberInput","setNumberInput","randomSixDigitNumber","setRandomSixDigitNumber","randomIndex","setRandomIndex","deleteProductCategoriesRange","hooks","mutations","deleteMultipleById","useEffect","length","Math","floor","random","toString","randomCategoryName","name","noOfCategories","deleteCategories","async","ids","RestApiMultipleIdsDTO","multipleIdsDTO","Dialog","fullWidth","PaperProps","padding","scroll","DialogTitle","DialogContent","marginTop","DialogContentText","Grid","container","spacing","map","category","index","item","xs","wordBreak","component","textDecoration","TextField","autoFocus","type","value","onChange","event","target","DialogActions","cat","disabled","trim","dialogType","formData","existingCategories","imageEditing","productCategoryId","initialParentCategoryId","handleChange","handleSubmit","parentCategories","setParentCategories","parentCategoryId","setParentCategoryId","mappedCategories","push","categoryId","categoryName","filter","sort","a","b","sortOrder","forEach","parentCategory","find","titleText","autoComplete","title","subtitle","FormControl","InputLabel","Select","selectedCategoryId","MenuItem","marginBottom","flex","marginRight","ImageEditComponent","marginLeft","description","multiline","initialData","updateData","clearStateAndClose","dialogData","setDialogData","reason","prevState","parentCatId","productCategoryName","data","categoryData","categoryError","isLoading","categoryLoading","queries","getWithImagesById","patchProductCategory","update","showWithMessage","hide","useLoadingDialog","setFormData","selectedParentCategoryId","setSelectedParentCategoryId","newData","productCategoryWithImagesDTO","unwrap","finally","ImageCropperModal","onSave","currentProductCategory","inputValue","setInputValue","deleteProductCategory","deleteById","deleteCategory","createProductCategory","create","navigate","productCategories","setProductCategories","allCategoriesData","allCategoriesError","allCategoriesLoading","getAllMinimal","triggerProductCategoryImage","productCategoryImageResult","lazyQueries","getImage","setRowModesModel","setCurrentProductCategory","editModalOpen","setEditModalOpen","deleteModalOpen","setDeleteModalOpen","addModalOpen","setAddModalOpen","deleteMultipleModalOpen","setDeleteMultipleModalOpen","selectedRows","setSelectedRows","extendedProducts","isNew","cacheValue","Guid","preventDefault","stopPropagation","View","ignoreModifications","handleDeleteDialogClose","handleAddCategory","handleDeleteAllCheckedRows","handleDeleteMultipleDialogClose","handleEditModalClose","field","headerName","editable","minWidth","headerClassName","renderCell","underline","state","cursor","CommonDataGridDescriptionField","sortable","GridRowImageWithFallback","bannerImageId","thumbnailImageId","CommonDataGridActions","mb","Add","A","CommonDataGrid","includes","flexGrow","Container","align","alignContent","StyledPaperComponent","effect","effectDuration","headerTitle","headerSize","paragraph","paddingTop","PowerUser","useFormData","clearFormData","handleCheckboxChange","checked","useModalPropertyEditor","isEditorOpen","setIsEditorOpen","items","setItems","openEditor","closeEditor","handleDeleteItem","handleAddItem","handleSaveItem","findIndex","i","handleSaveItems","handleCancelItem","selectedCategories","selected","setSelected","productCategoryData","productCategoryError","productCategoryLoading","getAllNames","paddingRight","CircularProgress","paddingBottom","ListItem","currentIndex","c","newSelected","splice","handleToggle","Checkbox","some","ListItemText","borderTop","productColors","handleDeleteColor","handleAddColor","sm","Circle","hexCode","dark","IconButton","onDeleteColor","colorId","productSizes","handleDeleteSize","handleAddSize","size","onDeleteSize","sizeId","setSelectedCategories","openCategoryModal","onDeleteCategory","fontStyle","saveDisabled","inputProps","code","stockQuantity","regularPrice","liquidationPrice","InputProps","FormControlLabel","control","available","highlight","initialColor","initialName","onCancel","allProductColorsData","allProductColorsError","allProductColorsLoading","getExistingProductColors","tabValue","setTabValue","currentColor","setCurrentColor","Tabs","newValue","textColor","indicatorColor","centered","top","zIndex","Tab","overflowY","productColor","handleColorSelect","colorName","colorHex","Link","onChangeComplete","updatedColor","hex","styles","default","picker","saturation","e","readOnly","handleSave","colorHexCode","initialSize","initialOrder","allProductSizesData","allProductSizesError","allProductSizesLoading","getExistingProductSizes","currentSize","setCurrentSize","displayOrder","productSize","handleSizeSelect","sizeValue","parseInt","currentProductId","currentProductName","productData","productError","productLoading","getByIdWithImages","patchProduct","isColorEditorOpen","setProductColors","openColorEditor","closeColorEditor","handleSaveColor","handleSaveColors","handleCancelColor","isSizeEditorOpen","openSizeEditor","closeSizeEditor","setProductSizes","handleSaveSize","handleSaveSizes","handleCancelSize","isCategoryModalOpen","openCategoryEditor","closeCategoryEditor","handleDeleteCategory","handleSaveCategory","handleSaveCategories","handleCancelCategory","currColors","currSizes","currCategories","updatedProductDTO","productWithImagesDTO","colorDTO","sizeDTO","currentProduct","deleteProduct","initialFormData","createProduct","newProductDTO","RestApiProductCategoryMinimalDTO","ProductsToDelete","ProductNameInput","setProductNameInput","deleteProductRange","randomProductName","noOfProducts","deleteProducts","Product","Products","setProducts","allProductsData","allProductsError","allProductsLoading","getAll","triggerProductImage","productImageResult","setCurrentProduct","setColumnVisibilityModel","isDeleted","initialStateModel","filterModel","operator","product","resetStates","handleAddProduct","handleCategoryChange","values","handleColumnVisibilityChange","newModel","hideable","productId","mr","labelId","input","OutlinedInput","notched","endAdornment","InputAdornment","pointerEvents","edge","Close","multiple","renderValue","join","indexOf"],"sourceRoot":""}