diff --git a/public/images/logos/logo.png b/public/images/logos/logo.png new file mode 100644 index 0000000..f9d7a0e Binary files /dev/null and b/public/images/logos/logo.png differ diff --git a/src/@core/svg/Logo.tsx b/src/@core/svg/Logo.tsx index 7915a37..1e4a156 100644 --- a/src/@core/svg/Logo.tsx +++ b/src/@core/svg/Logo.tsx @@ -3,34 +3,7 @@ import type { SVGAttributes } from 'react' const Logo = (props: SVGAttributes) => { return ( - - - - - - + ) } diff --git a/src/@core/theme/colorSchemes.ts b/src/@core/theme/colorSchemes.ts index 14d3341..8b34306 100644 --- a/src/@core/theme/colorSchemes.ts +++ b/src/@core/theme/colorSchemes.ts @@ -9,7 +9,7 @@ const colorSchemes = (skin: Skin): Theme['colorSchemes'] => { light: { palette: { primary: { - main: '#7367F0', + main: '#36175e', light: '#8F85F3', dark: '#675DD8', lighterOpacity: 'rgb(var(--mui-palette-primary-mainChannel) / 0.08)', @@ -161,7 +161,7 @@ const colorSchemes = (skin: Skin): Theme['colorSchemes'] => { dark: { palette: { primary: { - main: '#7367F0', + main: '#36175e', light: '#8F85F3', dark: '#675DD8', lighterOpacity: 'rgb(var(--mui-palette-primary-mainChannel) / 0.08)', diff --git a/src/app/[lang]/(dashboard)/(private)/apps/ecommerce/products/add/page.tsx b/src/app/[lang]/(dashboard)/(private)/apps/ecommerce/products/add/page.tsx index 2f43b9a..fd936e5 100644 --- a/src/app/[lang]/(dashboard)/(private)/apps/ecommerce/products/add/page.tsx +++ b/src/app/[lang]/(dashboard)/(private)/apps/ecommerce/products/add/page.tsx @@ -3,12 +3,11 @@ import Grid from '@mui/material/Grid2' // Component Imports import ProductAddHeader from '@views/apps/ecommerce/products/add/ProductAddHeader' -import ProductInformation from '@views/apps/ecommerce/products/add/ProductInformation' import ProductImage from '@views/apps/ecommerce/products/add/ProductImage' -import ProductVariants from '@views/apps/ecommerce/products/add/ProductVariants' -import ProductInventory from '@views/apps/ecommerce/products/add/ProductInventory' -import ProductPricing from '@views/apps/ecommerce/products/add/ProductPricing' +import ProductInformation from '@views/apps/ecommerce/products/add/ProductInformation' import ProductOrganize from '@views/apps/ecommerce/products/add/ProductOrganize' +import ProductPricing from '@views/apps/ecommerce/products/add/ProductPricing' +import ProductVariants from '@views/apps/ecommerce/products/add/ProductVariants' const eCommerceProductsAdd = () => { return ( @@ -27,9 +26,6 @@ const eCommerceProductsAdd = () => { - - - diff --git a/src/app/[lang]/(dashboard)/(private)/apps/ecommerce/products/list/page.tsx b/src/app/[lang]/(dashboard)/(private)/apps/ecommerce/products/list/page.tsx index 988f940..cb570ce 100644 --- a/src/app/[lang]/(dashboard)/(private)/apps/ecommerce/products/list/page.tsx +++ b/src/app/[lang]/(dashboard)/(private)/apps/ecommerce/products/list/page.tsx @@ -2,7 +2,6 @@ import Grid from '@mui/material/Grid2' // Component Imports -import ProductCard from '@views/apps/ecommerce/products/list/ProductCard' import ProductListTable from '@views/apps/ecommerce/products/list/ProductListTable' // Data Imports @@ -29,9 +28,6 @@ const eCommerceProductsList = async () => { return ( - - - diff --git a/src/app/[lang]/(dashboard)/(private)/layout.tsx b/src/app/[lang]/(dashboard)/(private)/layout.tsx index 6932bde..22bbca4 100644 --- a/src/app/[lang]/(dashboard)/(private)/layout.tsx +++ b/src/app/[lang]/(dashboard)/(private)/layout.tsx @@ -67,7 +67,7 @@ const Layout = async (props: ChildrenType & { params: Promise<{ lang: Locale }> - + {/* */} ) diff --git a/src/app/[lang]/layout.tsx b/src/app/[lang]/layout.tsx index 919865e..2650c16 100644 --- a/src/app/[lang]/layout.tsx +++ b/src/app/[lang]/layout.tsx @@ -30,9 +30,9 @@ import '@assets/iconify-icons/generated-icons.css' import { ReactQueryProvider } from '../../providers/ReactQueryProvider' export const metadata = { - title: 'Vuexy - MUI Next.js Admin Dashboard Template', + title: 'APSKEL', description: - 'Vuexy - MUI Next.js Admin Dashboard Template - is the most developer friendly & highly customizable Admin Dashboard Template based on MUI v5.' + 'Apsekel' } const RootLayout = async (props: ChildrenType & { params: Promise<{ lang: Locale }> }) => { diff --git a/src/app/favicon.ico b/src/app/favicon.ico index 60a94e9..d4af67f 100644 Binary files a/src/app/favicon.ico and b/src/app/favicon.ico differ diff --git a/src/components/layout/horizontal/Footer.tsx b/src/components/layout/horizontal/Footer.tsx index 2b076f6..c6400d2 100644 --- a/src/components/layout/horizontal/Footer.tsx +++ b/src/components/layout/horizontal/Footer.tsx @@ -4,9 +4,10 @@ import FooterContent from './FooterContent' const Footer = () => { return ( - - - + // + // + // + <> ) } diff --git a/src/components/layout/shared/Loading.tsx b/src/components/layout/shared/Loading.tsx index 41b2770..7df9989 100644 --- a/src/components/layout/shared/Loading.tsx +++ b/src/components/layout/shared/Loading.tsx @@ -3,7 +3,7 @@ import { CircularProgress } from '@mui/material' export default function Loading({ size = 60 }: { size?: number }) { return (
- +
) } diff --git a/src/components/layout/vertical/Footer.tsx b/src/components/layout/vertical/Footer.tsx index 32138dc..0d1d956 100644 --- a/src/components/layout/vertical/Footer.tsx +++ b/src/components/layout/vertical/Footer.tsx @@ -4,9 +4,10 @@ import FooterContent from './FooterContent' const Footer = () => { return ( - - - + // + // + // + <> ) } diff --git a/src/configs/primaryColorConfig.ts b/src/configs/primaryColorConfig.ts index ccfd296..4d89f7c 100644 --- a/src/configs/primaryColorConfig.ts +++ b/src/configs/primaryColorConfig.ts @@ -10,7 +10,7 @@ const primaryColorConfig: PrimaryColorConfig[] = [ { name: 'primary-1', light: '#8F85F3', - main: '#7367F0', + main: '#36175e', dark: '#675DD8' }, { diff --git a/src/configs/themeConfig.ts b/src/configs/themeConfig.ts index dd686b4..1242763 100644 --- a/src/configs/themeConfig.ts +++ b/src/configs/themeConfig.ts @@ -54,7 +54,7 @@ export type Config = { } const themeConfig: Config = { - templateName: 'Vuexy', + templateName: 'APSKEL', homePageUrl: '/dashboards/crm', settingsCookieName: 'vuexy-mui-next-demo-1', mode: 'system', // 'system', 'light', 'dark' diff --git a/src/services/mutations/ingredients.ts b/src/services/mutations/ingredients.ts new file mode 100644 index 0000000..0486f8a --- /dev/null +++ b/src/services/mutations/ingredients.ts @@ -0,0 +1,52 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query' +import { CustomerRequest } from '../../types/services/customer' +import { api } from '../api' +import { toast } from 'react-toastify' + +export const useIngredientsMutation = () => { + const queryClient = useQueryClient() + + const createCustomer = useMutation({ + mutationFn: async (newCustomer: CustomerRequest) => { + const response = await api.post('/customers', newCustomer) + return response.data + }, + onSuccess: () => { + toast.success('Customer created successfully!') + queryClient.invalidateQueries({ queryKey: ['customers'] }) + }, + onError: (error: any) => { + toast.error(error.response?.data?.errors?.[0]?.cause || 'Create failed') + } + }) + + const updateCustomer = useMutation({ + mutationFn: async ({ id, payload }: { id: string; payload: CustomerRequest }) => { + const response = await api.put(`/customers/${id}`, payload) + return response.data + }, + onSuccess: () => { + toast.success('Customer updated successfully!') + queryClient.invalidateQueries({ queryKey: ['customers'] }) + }, + onError: (error: any) => { + toast.error(error.response?.data?.errors?.[0]?.cause || 'Update failed') + } + }) + + const deleteCustomer = useMutation({ + mutationFn: async (id: string) => { + const response = await api.delete(`/customers/${id}`) + return response.data + }, + onSuccess: () => { + toast.success('Customer deleted successfully!') + queryClient.invalidateQueries({ queryKey: ['customers'] }) + }, + onError: (error: any) => { + toast.error(error.response?.data?.errors?.[0]?.cause || 'Delete failed') + } + }) + + return { createCustomer, updateCustomer, deleteCustomer } +} diff --git a/src/services/queries/ingredients.ts b/src/services/queries/ingredients.ts new file mode 100644 index 0000000..f355566 --- /dev/null +++ b/src/services/queries/ingredients.ts @@ -0,0 +1,36 @@ +import { useQuery } from '@tanstack/react-query' +import { Ingredients } from '../../types/services/ingredient' +import { api } from '../api' + +interface IngredientsQueryParams { + page?: number + limit?: number + search?: string +} + +export function useIngredients(params: IngredientsQueryParams = {}) { + const { page = 1, limit = 10, search = '', ...filters } = params + + return useQuery({ + queryKey: ['ingredients', { page, limit, search, ...filters }], + queryFn: async () => { + const queryParams = new URLSearchParams() + + queryParams.append('page', page.toString()) + queryParams.append('limit', limit.toString()) + + if (search) { + queryParams.append('search', search) + } + + Object.entries(filters).forEach(([key, value]) => { + if (value !== undefined && value !== null && value !== '') { + queryParams.append(key, value.toString()) + } + }) + + const res = await api.get(`/ingredients?${queryParams.toString()}`) + return res.data.data + } + }) +} diff --git a/src/types/services/ingredient.ts b/src/types/services/ingredient.ts new file mode 100644 index 0000000..9204cd5 --- /dev/null +++ b/src/types/services/ingredient.ts @@ -0,0 +1,38 @@ +export type Unit = { + id: string + organization_id: string + outlet_id: string + name: string + abbreviation: string + is_active: boolean + created_at: string + updated_at: string +} + +export type IngredientItem = { + id: string + organization_id: string + outlet_id: string + name: string + unit_id: string + cost: number + stock: number + is_semi_finished: boolean + is_active: boolean + metadata: Record // bisa diganti jika metadata memiliki struktur spesifik + created_at: string + updated_at: string + unit: Unit +} + +export type Pagination = { + page: number + limit: number + total_count: number + total_pages: number +} + +export type Ingredients = { + data: IngredientItem[] + pagination: Pagination +} diff --git a/src/views/apps/ecommerce/customers/list/CustomerListTable.tsx b/src/views/apps/ecommerce/customers/list/CustomerListTable.tsx index 8214fd4..3a75941 100644 --- a/src/views/apps/ecommerce/customers/list/CustomerListTable.tsx +++ b/src/views/apps/ecommerce/customers/list/CustomerListTable.tsx @@ -181,10 +181,6 @@ const CustomerListTable = () => { header: 'Phone', cell: ({ row }) => {row.original.phone || '-'} }), - columnHelper.accessor('address', { - header: 'Address', - cell: ({ row }) => {row.original.address || '-'} - }), columnHelper.accessor('is_active', { header: 'Status', cell: ({ row }) => ( @@ -196,6 +192,10 @@ const CustomerListTable = () => { /> ) }), + columnHelper.accessor('address', { + header: 'Address', + cell: ({ row }) => {row.original.address || '-'} + }), columnHelper.accessor('actions', { header: 'Actions', cell: ({ row }) => ( diff --git a/src/views/apps/ecommerce/products/ingredient/ProductIngredientTable.tsx b/src/views/apps/ecommerce/products/ingredient/ProductIngredientTable.tsx index 2cc908d..6b54716 100644 --- a/src/views/apps/ecommerce/products/ingredient/ProductIngredientTable.tsx +++ b/src/views/apps/ecommerce/products/ingredient/ProductIngredientTable.tsx @@ -31,9 +31,9 @@ import { Box, Chip, CircularProgress } from '@mui/material' import ConfirmDeleteDialog from '../../../../../components/dialogs/confirm-delete' import Loading from '../../../../../components/layout/shared/Loading' import { useUnitsMutation } from '../../../../../services/mutations/units' -import { useUnits } from '../../../../../services/queries/units' -import { Unit } from '../../../../../types/services/unit' -import { formatDate } from '../../../../../utils/transform' +import { useIngredients } from '../../../../../services/queries/ingredients' +import { IngredientItem } from '../../../../../types/services/ingredient' +import { formatCurrency } from '../../../../../utils/transform' declare module '@tanstack/table-core' { interface FilterFns { @@ -44,7 +44,7 @@ declare module '@tanstack/table-core' { } } -type UnitWithActionsType = Unit & { +type IngredientWithActionsType = IngredientItem & { actions?: string } @@ -91,7 +91,7 @@ const DebouncedInput = ({ } // Column Definitions -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const ProductIngredientTable = () => { // States @@ -102,17 +102,18 @@ const ProductIngredientTable = () => { const [pageSize, setPageSize] = useState(10) const [unitId, setUnitId] = useState('') const [openConfirm, setOpenConfirm] = useState(false) - const [currentUnit, setCurrentUnit] = useState() + const [search, setSearch] = useState('') // Fetch products with pagination and search - const { data, isLoading, error, isFetching } = useUnits({ + const { data, isLoading, error, isFetching } = useIngredients({ page: currentPage, - limit: pageSize + limit: pageSize, + search }) const { mutate: deleteUnit, isPending: isDeleting } = useUnitsMutation().deleteUnit - const units = data?.data ?? [] + const ingredients = data?.data ?? [] const totalCount = data?.pagination.total_count ?? 0 const handlePageChange = useCallback((event: unknown, newPage: number) => { @@ -132,7 +133,7 @@ const ProductIngredientTable = () => { }) } - const columns = useMemo[]>( + const columns = useMemo[]>( () => [ { id: 'select', @@ -169,9 +170,17 @@ const ProductIngredientTable = () => { ) }), - columnHelper.accessor('abbreviation', { - header: 'Abbreviation', - cell: ({ row }) => {row.original.abbreviation || '-'} + columnHelper.accessor('cost', { + header: 'Cost', + cell: ({ row }) => {formatCurrency(row.original.cost) || '-'} + }), + columnHelper.accessor('stock', { + header: 'Stock', + cell: ({ row }) => {row.original.stock} + }), + columnHelper.accessor('unit', { + header: 'Unit', + cell: ({ row }) => {row.original.unit.name} }), columnHelper.accessor('is_active', { header: 'Status', @@ -184,9 +193,16 @@ const ProductIngredientTable = () => { /> ) }), - columnHelper.accessor('created_at', { - header: 'Created Date', - cell: ({ row }) => {formatDate(row.original.created_at)} + columnHelper.accessor('is_semi_finished', { + header: 'Semi Finished', + cell: ({ row }) => ( + + ) }), columnHelper.accessor('actions', { header: 'Actions', @@ -194,7 +210,6 @@ const ProductIngredientTable = () => {
{ - setCurrentUnit(row.original) setEditUnitOpen(!editUnitOpen) }} > @@ -228,7 +243,7 @@ const ProductIngredientTable = () => { ) const table = useReactTable({ - data: units as Unit[], + data: ingredients as IngredientItem[], columns, filterFns: { fuzzy: fuzzyFilter @@ -253,16 +268,16 @@ const ProductIngredientTable = () => {
console.log(value)} + value={search} + onChange={value => setSearch(value as string)} placeholder='Search Product' className='max-sm:is-full' />
table.setPageSize(Number(e.target.value))} + value={pageSize} + onChange={handlePageSizeChange} className='flex-auto max-sm:is-full sm:is-[70px]' > 10 diff --git a/src/views/apps/ecommerce/stock/list/StockListTable.tsx b/src/views/apps/ecommerce/stock/list/StockListTable.tsx index d56eaac..0fd21d8 100644 --- a/src/views/apps/ecommerce/stock/list/StockListTable.tsx +++ b/src/views/apps/ecommerce/stock/list/StockListTable.tsx @@ -8,7 +8,6 @@ import { useCallback, useEffect, useMemo, useState } from 'react' // MUI Imports import Button from '@mui/material/Button' import Card from '@mui/material/Card' -import CardHeader from '@mui/material/CardHeader' import Checkbox from '@mui/material/Checkbox' import Chip from '@mui/material/Chip' import Divider from '@mui/material/Divider' @@ -36,12 +35,12 @@ import OptionMenu from '@core/components/option-menu' // Style Imports import tableStyles from '@core/styles/table.module.css' import { Box, CircularProgress } from '@mui/material' -import AddStockDrawer from './AddStockDrawer' import ConfirmDeleteDialog from '../../../../../components/dialogs/confirm-delete' import Loading from '../../../../../components/layout/shared/Loading' import { useInventoriesMutation } from '../../../../../services/mutations/inventories' import { useInventories } from '../../../../../services/queries/inventories' import { Inventory } from '../../../../../types/services/inventory' +import AddStockDrawer from './AddStockDrawer' declare module '@tanstack/table-core' { interface FilterFns { @@ -165,14 +164,6 @@ const StockListTable = () => { header: 'Product', cell: ({ row }) => {row.original.product_id} }), - columnHelper.accessor('quantity', { - header: 'Quantity', - cell: ({ row }) => {row.original.quantity} - }), - columnHelper.accessor('reorder_level', { - header: 'Reorder Level', - cell: ({ row }) => {row.original.reorder_level} - }), columnHelper.accessor('is_low_stock', { header: 'Status', cell: ({ row }) => ( @@ -184,6 +175,14 @@ const StockListTable = () => { /> ) }), + columnHelper.accessor('quantity', { + header: 'Quantity', + cell: ({ row }) => {row.original.quantity} + }), + columnHelper.accessor('reorder_level', { + header: 'Reorder Level', + cell: ({ row }) => {row.original.reorder_level} + }), columnHelper.accessor('actions', { header: 'Actions', cell: ({ row }) => ( @@ -239,8 +238,6 @@ const StockListTable = () => { return ( <> - - {/* {}} productData={[]} /> */}