Compare commits
10 Commits
6bb1758040
...
ada2e1cb72
| Author | SHA1 | Date | |
|---|---|---|---|
| ada2e1cb72 | |||
| 786c9e13f0 | |||
| 0acdfdb1eb | |||
| 3d49f32175 | |||
| 3be5cba323 | |||
| b7c5734a1b | |||
| a155c991c6 | |||
| b6ffdaf03f | |||
| 325b27262e | |||
| 8771e025bc |
BIN
src/client/dd-hub-react/public/assets/images/dd-button-icon.webp
Normal file
|
After Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 149 KiB |
31
src/client/dd-hub-react/src/api/product-service.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
export type Product = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
price?: number;
|
||||||
|
status?: string;
|
||||||
|
version?: string;
|
||||||
|
coverUrl?: string;
|
||||||
|
colors?: string[];
|
||||||
|
priceSale?: number;
|
||||||
|
url?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send a request to the server to get the products
|
||||||
|
* @returns Array of products
|
||||||
|
*/
|
||||||
|
export function getProductsAsync(): Promise<Product[]> {
|
||||||
|
//TODO: Implement the API call using fetch or axios
|
||||||
|
return Promise.resolve([
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
name: "User Manager",
|
||||||
|
version: "1.0.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
name: "Envelope Generator",
|
||||||
|
version: "1.0.0"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
@@ -19,11 +19,12 @@ type AppProps = {
|
|||||||
export default function App({ children }: AppProps) {
|
export default function App({ children }: AppProps) {
|
||||||
useScrollToTop();
|
useScrollToTop();
|
||||||
|
|
||||||
const githubButton = () => (
|
const ddButton = () => (
|
||||||
<Fab
|
<Fab
|
||||||
size="medium"
|
size="medium"
|
||||||
aria-label="Github"
|
aria-label="Digital Data"
|
||||||
href="https://github.com/minimal-ui-kit/material-kit-react"
|
href="https://digitaldata.works/"
|
||||||
|
target="_blank"
|
||||||
sx={{
|
sx={{
|
||||||
zIndex: 9,
|
zIndex: 9,
|
||||||
right: 20,
|
right: 20,
|
||||||
@@ -31,17 +32,21 @@ export default function App({ children }: AppProps) {
|
|||||||
width: 48,
|
width: 48,
|
||||||
height: 48,
|
height: 48,
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
bgcolor: 'grey.800',
|
bgcolor: 'transparent',
|
||||||
|
boxShadow: 'none'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Iconify width={24} icon="socials:github" sx={{ '--color': 'white' }} />
|
<img
|
||||||
|
src="/assets/images/dd-button-icon.webp"
|
||||||
|
alt="Digital Data"
|
||||||
|
/>
|
||||||
</Fab>
|
</Fab>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
{children}
|
{children}
|
||||||
{githubButton()}
|
{ddButton()}
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import Link from '@mui/material/Link';
|
import Link from '@mui/material/Link';
|
||||||
import Card from '@mui/material/Card';
|
import Card from '@mui/material/Card';
|
||||||
@@ -6,22 +8,15 @@ import Typography from '@mui/material/Typography';
|
|||||||
|
|
||||||
import { fCurrency } from 'src/utils/format-number';
|
import { fCurrency } from 'src/utils/format-number';
|
||||||
|
|
||||||
|
import { Product } from 'src/api/product-service';
|
||||||
|
|
||||||
import { Label } from 'src/components/label';
|
import { Label } from 'src/components/label';
|
||||||
import { ColorPreview } from 'src/components/color-utils';
|
import { ColorPreview } from 'src/components/color-utils';
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
export type ProductItemProps = {
|
// TODO: Add explanation part
|
||||||
id: string;
|
export function ProductItem({ product }: { product: Product }) {
|
||||||
name: string;
|
|
||||||
price: number;
|
|
||||||
status: string;
|
|
||||||
coverUrl: string;
|
|
||||||
colors: string[];
|
|
||||||
priceSale: number | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function ProductItem({ product }: { product: ProductItemProps }) {
|
|
||||||
const renderStatus = (
|
const renderStatus = (
|
||||||
<Label
|
<Label
|
||||||
variant="inverted"
|
variant="inverted"
|
||||||
@@ -38,11 +33,30 @@ export function ProductItem({ product }: { product: ProductItemProps }) {
|
|||||||
</Label>
|
</Label>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const renderVersion = (
|
||||||
|
<Label
|
||||||
|
variant="inverted"
|
||||||
|
color='info'
|
||||||
|
sx={{
|
||||||
|
zIndex: 9,
|
||||||
|
top: 16,
|
||||||
|
right: 16,
|
||||||
|
position: 'absolute',
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{product.version}
|
||||||
|
</Label>
|
||||||
|
);
|
||||||
|
|
||||||
|
const [imgSrc, setImgSrc] = useState(product.coverUrl ?? "/assets/images/product/product-default.webp");
|
||||||
|
|
||||||
const renderImg = (
|
const renderImg = (
|
||||||
<Box
|
<Box
|
||||||
component="img"
|
component="img"
|
||||||
alt={product.name}
|
alt={product.name}
|
||||||
src={product.coverUrl}
|
src={imgSrc}
|
||||||
|
onError={() => setImgSrc('/assets/images/product/product-default.webp')}
|
||||||
sx={{
|
sx={{
|
||||||
top: 0,
|
top: 0,
|
||||||
width: 1,
|
width: 1,
|
||||||
@@ -74,11 +88,12 @@ export function ProductItem({ product }: { product: ProductItemProps }) {
|
|||||||
<Card>
|
<Card>
|
||||||
<Box sx={{ pt: '100%', position: 'relative' }}>
|
<Box sx={{ pt: '100%', position: 'relative' }}>
|
||||||
{product.status && renderStatus}
|
{product.status && renderStatus}
|
||||||
|
{product.version && renderVersion}
|
||||||
{renderImg}
|
{renderImg}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Stack spacing={2} sx={{ p: 3 }}>
|
<Stack spacing={2} sx={{ p: 3 }}>
|
||||||
<Link color="inherit" underline="hover" variant="subtitle2" noWrap>
|
<Link color="inherit" underline="hover" variant="subtitle2" noWrap target="_blank" href={product.url ?? '/404'}>
|
||||||
{product.name}
|
{product.name}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
@@ -89,7 +104,7 @@ export function ProductItem({ product }: { product: ProductItemProps }) {
|
|||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ColorPreview colors={product.colors} />
|
<ColorPreview colors={product?.colors ?? []} />
|
||||||
{renderPrice}
|
{renderPrice}
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useCallback } from 'react';
|
import { useState, useCallback, useEffect } from 'react';
|
||||||
|
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import Grid from '@mui/material/Grid';
|
import Grid from '@mui/material/Grid';
|
||||||
@@ -7,9 +7,10 @@ import Typography from '@mui/material/Typography';
|
|||||||
|
|
||||||
import { _products } from 'src/_mock';
|
import { _products } from 'src/_mock';
|
||||||
import { DashboardContent } from 'src/layouts/dashboard';
|
import { DashboardContent } from 'src/layouts/dashboard';
|
||||||
|
import { getProductsAsync, Product } from 'src/api/product-service';
|
||||||
|
|
||||||
import { ProductItem } from '../product-item';
|
|
||||||
import { ProductSort } from '../product-sort';
|
import { ProductSort } from '../product-sort';
|
||||||
|
import { ProductItem } from '../product-item';
|
||||||
import { CartIcon } from '../product-cart-widget';
|
import { CartIcon } from '../product-cart-widget';
|
||||||
import { ProductFilters } from '../product-filters';
|
import { ProductFilters } from '../product-filters';
|
||||||
|
|
||||||
@@ -64,6 +65,8 @@ export function ProductsView() {
|
|||||||
|
|
||||||
const [filters, setFilters] = useState<FiltersProps>(defaultFilters);
|
const [filters, setFilters] = useState<FiltersProps>(defaultFilters);
|
||||||
|
|
||||||
|
const [products, setProducts] = useState<Array<Product>>([]);
|
||||||
|
|
||||||
const handleOpenFilter = useCallback(() => {
|
const handleOpenFilter = useCallback(() => {
|
||||||
setOpenFilter(true);
|
setOpenFilter(true);
|
||||||
}, []);
|
}, []);
|
||||||
@@ -84,6 +87,12 @@ export function ProductsView() {
|
|||||||
(key) => filters[key as keyof FiltersProps] !== defaultFilters[key as keyof FiltersProps]
|
(key) => filters[key as keyof FiltersProps] !== defaultFilters[key as keyof FiltersProps]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getProductsAsync().then((res) => {
|
||||||
|
setProducts(res);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardContent>
|
<DashboardContent>
|
||||||
<CartIcon totalItems={8} />
|
<CartIcon totalItems={8} />
|
||||||
@@ -139,7 +148,7 @@ export function ProductsView() {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Grid container spacing={3}>
|
<Grid container spacing={3}>
|
||||||
{_products.map((product) => (
|
{products.map((product) => (
|
||||||
<Grid key={product.id} size={{ xs: 12, sm: 6, md: 3 }}>
|
<Grid key={product.id} size={{ xs: 12, sm: 6, md: 3 }}>
|
||||||
<ProductItem product={product} />
|
<ProductItem product={product} />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||