Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Pachj committed Jan 4, 2024
1 parent 2bf75b1 commit 8daadba
Show file tree
Hide file tree
Showing 18 changed files with 444 additions and 174 deletions.
8 changes: 8 additions & 0 deletions shopi-frontend.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$/shopi-frontend" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
4 changes: 4 additions & 0 deletions shopi-frontend/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

265 changes: 117 additions & 148 deletions shopi-frontend/package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion shopi-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
"web-vitals": "^2.1.4",
"@react-buddy/ide-toolbox": "^2.4.0",
"@react-buddy/palette-mui": "^5.0.1"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "6.4.0",
Expand Down
3 changes: 2 additions & 1 deletion shopi-frontend/src/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from "react";
import ProductOverview from "./ProductOverview";

const Home = () => {
return <div>Home</div>;
return <div><ProductOverview /></div>;
};

export default Home;
13 changes: 0 additions & 13 deletions shopi-frontend/src/Product.tsx

This file was deleted.

43 changes: 43 additions & 0 deletions shopi-frontend/src/ProductOverview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useEffect, useState } from "react";
import SimpleProduct from "./components/SimpleProduct/SimpleProduct";
import ProductDetails from "./components/ProductDetails/ProductDetails";

export type Product = {
id: number;
name: string;
description: string;
price: number;
imageLink: string;
};

const ProductOverview = () => {
const [products, setProducts] = useState<Product[]>([]);
const [selectedProduct, setSelectedProduct] = useState<Product | null>(null);

const fetchProducts = async () => {
const response = await fetch("http://localhost:8080/products");
const data = await response.json();
setProducts(data);
};

useEffect(() => {
if (products.length === 0) {
fetchProducts();
}
}, []);

return (
<>
<div>
<h1>Product Overview</h1>
{products &&
products.map((product) => (
<SimpleProduct product={product} key={product.id} setSelectedProduct={setSelectedProduct} />
))}
</div>
{selectedProduct && <ProductDetails simpleProduct={selectedProduct} />}
</>
);
};

export default ProductOverview;
67 changes: 67 additions & 0 deletions shopi-frontend/src/components/ProductDetails/ProductDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Box, CircularProgress, Modal, Typography } from "@mui/material";
import style from "../SimpleProduct/SimpleProduct.module.css";
import React, { useEffect, useState } from "react";
import { Product } from "../../ProductOverview";
import ProductSpecifications from "./ProductSpecifications";

const boxStyle = {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
boxShadow: 24,
p: 4,
};

export type Specification = {
first: string;
second: string;
};

type ProductWithDetails = {
simpleProduct: Product;
specification: Specification[];
};

const ProductDetails = ({ simpleProduct }: { simpleProduct: Product }) => {
const [productWithDetails, setProductWithDetails] = useState<ProductWithDetails | null>(null);
console.log("productDetails", productWithDetails);

const fetchProductDetails = async () => {
const response = await fetch(`http://localhost:8080/products/${simpleProduct.id}`);
const data = await response.json();
setProductWithDetails(data);
};

useEffect(() => {
if (productWithDetails === null) {
fetchProductDetails();
}
});

return (
<Modal open={simpleProduct !== null}>
<Box sx={boxStyle}>
{productWithDetails ? (
<>
<Typography variant={"h4"}>{productWithDetails.simpleProduct.name}</Typography>
<img
className={style.productImage}
src={productWithDetails.simpleProduct.imageLink}
alt={productWithDetails.simpleProduct.name}
/>
<Typography variant={"body1"}>{productWithDetails.simpleProduct.description}</Typography>
<Typography variant={"h5"}>{productWithDetails.simpleProduct.price}</Typography>
<ProductSpecifications specification={productWithDetails.specification} />
</>
) : (
<CircularProgress />
)}
</Box>
</Modal>
);
};

export default ProductDetails;
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Table, TableBody, TableCell, TableContainer, TableRow } from "@mui/material";
import React from "react";
import { Specification } from "./ProductDetails";

const ProductSpecifications = ({ specification }: { specification: Specification[] }) => {
return (
<TableContainer>
<Table>
<TableBody>
{specification.map((spec) => (
<TableRow key={spec.first}>
<TableCell>{spec.first}</TableCell>
<TableCell>{spec.second}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
};
export default ProductSpecifications;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.productImage {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
border-radius: 0.5rem;
transition: all 0.3s ease-in-out;
cursor: pointer;
&:hover {
transform: scale(1.05);
}
}
27 changes: 27 additions & 0 deletions shopi-frontend/src/components/SimpleProduct/SimpleProduct.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Button, Card, CardActions, CardContent } from "@mui/material";
import { Product } from "../../ProductOverview";
import style from "./SimpleProduct.module.css";

const SimpleProduct = ({
product,
setSelectedProduct,
}: {
product: Product;
setSelectedProduct: (value: ((prevState: Product | null) => Product | null) | Product | null) => void;
}) => {
return (
<Card raised={true} sx={{ maxWidth: 300 }}>
<CardContent>
<h2>{product.name}</h2>
<img className={style.productImage} src={product.imageLink} alt={product.name} />
<p>{product.price}</p>
</CardContent>
<CardActions sx={{ display: "flex", justifyContent: "center" }}>
<Button onClick={() => setSelectedProduct(product)}>Details</Button>
<Button>Warenkorb</Button>
</CardActions>
</Card>
);
};

export default SimpleProduct;
70 changes: 70 additions & 0 deletions shopi-frontend/src/dev/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
This directory contains utility files which enable some visual features of the
[React Buddy](https://plugins.jetbrains.com/plugin/17467-react-buddy/) plugin.
Files in the directory should be committed to source control.

React Buddy palettes describe reusable components and building blocks. `React Palette` tool window becomes available
when an editor with React components is active. You can drag and drop items from the tool window to the code editor or
JSX Outline. Alternatively, you can insert components from the palette using code generation
action (`alt+insert` / `⌘ N`).

Add components to the palette using `Add to React Palette` intention or via palette editor (look for the corresponding
link in `palette.tsx`). There are some ready-to-use palettes for popular React libraries which are published as npm
packages and can be added as a dependency:

```jsx
import AntdPalette from "@react-buddy/palette-antd";
import ReactIntlPalette from "@react-buddy/palette-react-intl";

export const PaletteTree = () => (
<Palette>
<AntdPalette/>
<ReactIntlPalette/>
<Category name="App templates">
<Component name="Card">
<Variant name="Loading">
<Card title="Card title">
<Skeleton loading={true} avatar active>
Card content
</Skeleton>
</Card>
</Variant>
</Component>
<Component name="Form">
<Variant proto={FormTemplate}/>
</Component>
</Category>
</Palette>
)
```

React Buddy explicitly registers any previewed component in the `previews.tsx` file so that you can specify required
props.

```jsx
<ComponentPreview path="/Page">
<Page title={'Hello'}/>
</ComponentPreview>
```

You can add some global initialization logic for the preview mode in `useInitital.ts`,
e.g. implicitly obtain user session:

```typescript
export const useInitial: () => InitialHookStatus = () => {
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<boolean>(false);

useEffect(() => {
setLoading(true);
async function login() {
const response = await loginRequest(DEV_LOGIN, DEV_PASSWORD);
if (response?.status !== 200) {
setError(true);
}
setLoading(false);
}
login();
}, []);
return { loading, error };
};
```
6 changes: 6 additions & 0 deletions shopi-frontend/src/dev/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from "react";
import { useInitial } from "./useInitial";

const ComponentPreviews = React.lazy(() => import("./previews"));

export { ComponentPreviews, useInitial };
21 changes: 21 additions & 0 deletions shopi-frontend/src/dev/palette.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react";
import { Fragment } from "react";
import { Category, Component, Variant, Palette } from "@react-buddy/ide-toolbox";
import MUIPalette from "@react-buddy/palette-mui";

export const PaletteTree = () => (
<Palette>
<Category name="App">
<Component name="Loader">
<Variant>
<ExampleLoaderComponent />
</Variant>
</Component>
</Category>
<MUIPalette />
</Palette>
);

export function ExampleLoaderComponent() {
return <Fragment>Loading...</Fragment>;
}
9 changes: 9 additions & 0 deletions shopi-frontend/src/dev/previews.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import { Previews } from "@react-buddy/ide-toolbox";
import { PaletteTree } from "./palette";

const ComponentPreviews = () => {
return <Previews palette={<PaletteTree />}></Previews>;
};

export default ComponentPreviews;
16 changes: 16 additions & 0 deletions shopi-frontend/src/dev/useInitial.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useState } from "react";
import { InitialHookStatus } from "@react-buddy/ide-toolbox";

export const useInitial: () => InitialHookStatus = () => {
const [status, setStatus] = useState<InitialHookStatus>({
loading: false,
error: false,
});
/*
Implement hook functionality here.
If you need to execute async operation, set loading to true and when it's over, set loading to false.
If you caught some errors, set error status to true.
Initial hook is considered to be successfully completed if it will return {loading: false, error: false}.
*/
return status;
};
5 changes: 5 additions & 0 deletions shopi-frontend/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

.center {
display: flex;
justify-content: center;
}
24 changes: 13 additions & 11 deletions shopi-frontend/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { DevSupport } from "@react-buddy/ide-toolbox";
import { ComponentPreviews, useInitial } from "./dev";

const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
<React.StrictMode>
<DevSupport ComponentPreviews={ComponentPreviews} useInitialHook={useInitial}>
<App />
</DevSupport>
</React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
Expand Down

0 comments on commit 8daadba

Please sign in to comment.