Fix Mathu Coding und Payment fix
This commit is contained in:
@@ -59,7 +59,7 @@
|
|||||||
"other": "Sonstiges",
|
"other": "Sonstiges",
|
||||||
"outOfStock": "Ausverkauft",
|
"outOfStock": "Ausverkauft",
|
||||||
"payment": "Bezahlung",
|
"payment": "Bezahlung",
|
||||||
"paymentNotAvailable": "Keine Zahlungsmöglichkeit hinterlegt.",
|
"paymentNotAvailable": "Keine Zahlungsmethoden verfügbar.",
|
||||||
"pageDoesNotExist": "Ups! Diese Seite existiert nicht.",
|
"pageDoesNotExist": "Ups! Diese Seite existiert nicht.",
|
||||||
"phone": "Telefon",
|
"phone": "Telefon",
|
||||||
"placeOrder": "Zahlungspflichtig bestellen",
|
"placeOrder": "Zahlungspflichtig bestellen",
|
||||||
@@ -91,5 +91,7 @@
|
|||||||
"noRatingsYet": "Noch keine Bewertungen vorhanden.",
|
"noRatingsYet": "Noch keine Bewertungen vorhanden.",
|
||||||
"accounts": "Konten",
|
"accounts": "Konten",
|
||||||
"statistics": "Statistiken",
|
"statistics": "Statistiken",
|
||||||
"thanksForRating": "Vielen Dank für die Bewertung!"
|
"thanksForRating": "Vielen Dank für die Bewertung!",
|
||||||
|
"telephone": "Telefon",
|
||||||
|
"basketEmpty": "Der Warenkorb ist leer."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,5 +91,7 @@
|
|||||||
"noRatingsYet": "No ratings yet",
|
"noRatingsYet": "No ratings yet",
|
||||||
"accounts": "Accounts",
|
"accounts": "Accounts",
|
||||||
"statistics": "Statistics",
|
"statistics": "Statistics",
|
||||||
"thanksForRating": "Thank you for rating!"
|
"thanksForRating": "Thank you for rating!",
|
||||||
|
"telephone": "Telephone",
|
||||||
|
"basketEmpty": "The shopping cart is empty."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import React, { createContext, useContext, useState } from 'react';
|
import React, { createContext, useContext, useState } from 'react';
|
||||||
|
import Item from '../components/Item';
|
||||||
|
|
||||||
interface BasketItem {
|
interface BasketItem {
|
||||||
itemId: string;
|
item: Item;
|
||||||
quantity: number;
|
quantity: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BasketContextType {
|
interface BasketContextType {
|
||||||
basket: BasketItem[];
|
basket: BasketItem[];
|
||||||
addToBasket: (itemId: string, quantity: number) => void;
|
addToBasket: (item: Item, quantity: number) => void;
|
||||||
clearBasket: () => void;
|
clearBasket: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,19 +17,19 @@ const BasketContext = createContext<BasketContextType | undefined>(undefined);
|
|||||||
export const BasketProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
export const BasketProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||||
const [basket, setBasket] = useState<BasketItem[]>([]);
|
const [basket, setBasket] = useState<BasketItem[]>([]);
|
||||||
|
|
||||||
const addToBasket = (itemId: string, quantity: number) => {
|
const addToBasket = (item: Item, quantity: number) => {
|
||||||
setBasket((prevBasket) => {
|
setBasket((prevBasket) => {
|
||||||
const existingItem = prevBasket.find((item) => item.itemId === itemId);
|
const existingItem = prevBasket.find((basketItem) => basketItem.item.uuid === item.uuid);
|
||||||
if (existingItem) {
|
if (existingItem) {
|
||||||
// Update quantity if item already exists
|
// Update quantity if item already exists
|
||||||
return prevBasket.map((item) =>
|
return prevBasket.map((basketItem) =>
|
||||||
item.itemId === itemId
|
basketItem.item.uuid === item.uuid
|
||||||
? { ...item, quantity: item.quantity + quantity }
|
? { ...basketItem, quantity: basketItem.quantity + quantity }
|
||||||
: item
|
: basketItem
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Add new item to basket
|
// Add new item to basket
|
||||||
return [...prevBasket, { itemId, quantity }];
|
return [...prevBasket, { item, quantity }];
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export default function ItemCard({ item }: { item: Item }) {
|
|||||||
const { addToBasket } = useBasket();
|
const { addToBasket } = useBasket();
|
||||||
|
|
||||||
const handleAddToCart = () => {
|
const handleAddToCart = () => {
|
||||||
addToBasket(item.id, 1);
|
addToBasket(item, 1);
|
||||||
console.log(`Added ${1} of ${item.name} to basket`);
|
console.log(`Added ${1} of ${item.name} to basket`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
18
01-frontend/src/helper/navbar/LoginPopUp.tsx
Normal file
18
01-frontend/src/helper/navbar/LoginPopUp.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
export default function LoginPopUp() {
|
||||||
|
return (
|
||||||
|
<div className="login-popup">
|
||||||
|
<h2>Login</h2>
|
||||||
|
<form>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="username">Username</label>
|
||||||
|
<input type="text" id="username" name="username" required />
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="password">Password</label>
|
||||||
|
<input type="password" id="password" name="password" required />
|
||||||
|
</div>
|
||||||
|
<button type="submit">Login</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@ export default function ProductInfo({ item }: { item: Item }) {
|
|||||||
|
|
||||||
|
|
||||||
const handleAddToCart = () => {
|
const handleAddToCart = () => {
|
||||||
addToBasket(item.id, quantity);
|
addToBasket(item, quantity);
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
console.log(`Added {quantity} of €{item.name} to basket`);
|
console.log(`Added {quantity} of €{item.name} to basket`);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,32 +1,33 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Container,
|
Container,
|
||||||
Step,
|
Divider,
|
||||||
StepLabel,
|
|
||||||
Stepper,
|
|
||||||
Typography,
|
|
||||||
TextField,
|
|
||||||
Grid,
|
Grid,
|
||||||
Paper,
|
|
||||||
List,
|
List,
|
||||||
ListItem,
|
ListItem,
|
||||||
ListItemText,
|
ListItemText,
|
||||||
Divider,
|
Paper,
|
||||||
styled,
|
Step,
|
||||||
|
StepLabel,
|
||||||
|
Stepper,
|
||||||
|
TextField,
|
||||||
|
Typography
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { useBasket } from '../helper/BasketProvider';
|
import React, { useState } from 'react';
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import {useTranslation} from "react-i18next";
|
import { useBasket } from '../helper/BasketProvider';
|
||||||
|
|
||||||
const Item = styled(Paper)(({ theme }) => ({
|
type ShippingDetails = {
|
||||||
backgroundColor: theme.palette.background.paper,
|
firstName: string;
|
||||||
color: theme.palette.text.primary,
|
lastName: string;
|
||||||
...theme.typography.body2,
|
telefon: string;
|
||||||
padding: theme.spacing(1),
|
address: string;
|
||||||
textAlign: 'center',
|
postalCode: string;
|
||||||
}));
|
city: string;
|
||||||
|
country: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export default function Payment() {
|
export default function Payment() {
|
||||||
@@ -35,13 +36,14 @@ export default function Payment() {
|
|||||||
const navigator = useNavigate();
|
const navigator = useNavigate();
|
||||||
const { basket, clearBasket } = useBasket();
|
const { basket, clearBasket } = useBasket();
|
||||||
const [activeStep, setActiveStep] = useState(0);
|
const [activeStep, setActiveStep] = useState(0);
|
||||||
const [shippingDetails, setShippingDetails] = useState({
|
const [shippingDetails, setShippingDetails] = useState<ShippingDetails>({
|
||||||
firstName: '',
|
firstName: '',
|
||||||
lastName: '',
|
lastName: '',
|
||||||
|
telefon: '',
|
||||||
address: '',
|
address: '',
|
||||||
postalCode: '',
|
postalCode: '',
|
||||||
city: '',
|
city: '',
|
||||||
country: ''
|
country: 'Deutschland',
|
||||||
});
|
});
|
||||||
const [orderNumber, setOrderNumber] = useState<string | null>(null);
|
const [orderNumber, setOrderNumber] = useState<string | null>(null);
|
||||||
const steps = [t('reviewCart'), t('shippingDetails'), t('payment'), t('orderSummary')];
|
const steps = [t('reviewCart'), t('shippingDetails'), t('payment'), t('orderSummary')];
|
||||||
@@ -71,6 +73,18 @@ export default function Payment() {
|
|||||||
clearBasket();
|
clearBasket();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Hilfsfunktion prüfen, ob alle Pflichtfelder ausgefüllt sind
|
||||||
|
const isShippingDetailsValid = () => {
|
||||||
|
return (
|
||||||
|
shippingDetails.firstName.trim() !== '' &&
|
||||||
|
shippingDetails.lastName.trim() !== '' &&
|
||||||
|
shippingDetails.address.trim() !== '' &&
|
||||||
|
shippingDetails.postalCode.trim() !== '' &&
|
||||||
|
shippingDetails.city.trim() !== '' &&
|
||||||
|
shippingDetails.country.trim() !== ''
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const renderStepContent = (step: number) => {
|
const renderStepContent = (step: number) => {
|
||||||
switch (step) {
|
switch (step) {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -79,18 +93,24 @@ export default function Payment() {
|
|||||||
<Typography variant="h6" gutterBottom>
|
<Typography variant="h6" gutterBottom>
|
||||||
{t('reviewCart')}
|
{t('reviewCart')}
|
||||||
</Typography>
|
</Typography>
|
||||||
<List>
|
{basket.length === 0 ? (
|
||||||
{basket.map((item) => (
|
<Typography color="error" sx={{ my: 2 }}>
|
||||||
<ListItem key={item.itemId}>
|
{t('basketEmpty')}
|
||||||
<ListItemText
|
</Typography>
|
||||||
primary={`Item ID: ${item.itemId}`}
|
) : (
|
||||||
secondary={`Quantity: ${item.quantity}`}
|
<List>
|
||||||
/>
|
{basket.map((item) => (
|
||||||
</ListItem>
|
<ListItem key={item.item.uuid}>
|
||||||
))}
|
<ListItemText
|
||||||
</List>
|
primary={`${item.item.name} (${item.item.price100 / 100} €)`}
|
||||||
|
secondary={`Item ID: ${item.item.uuid} \n Quantity: ${item.quantity} \n Price: ${(item.item.price100 * item.quantity) / 100} €`}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
)}
|
||||||
<Divider sx={{ my: 2 }} />
|
<Divider sx={{ my: 2 }} />
|
||||||
<Button variant="outlined" color="error" onClick={handleClearBasket}>
|
<Button variant="outlined" color="error" onClick={handleClearBasket} disabled={basket.length === 0}>
|
||||||
{t('clearCart')}
|
{t('clearCart')}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -102,60 +122,70 @@ export default function Payment() {
|
|||||||
{t('shippingDetails')}
|
{t('shippingDetails')}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Item>
|
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
label={t('firstName')}
|
label={t('firstName')}
|
||||||
name="firstName"
|
name="firstName"
|
||||||
value={shippingDetails.firstName}
|
value={shippingDetails.firstName}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
/>
|
required
|
||||||
</Item>
|
/>
|
||||||
<Item>
|
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
label={t('lastName')}
|
label={t('lastName')}
|
||||||
name="lastName"
|
name="lastName"
|
||||||
value={shippingDetails.lastName}
|
value={shippingDetails.lastName}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
/>
|
required
|
||||||
</Item>
|
/>
|
||||||
<Item>
|
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
label={t('address')}
|
label={t('telephone')}
|
||||||
name="address"
|
name="telefon"
|
||||||
value={shippingDetails.address}
|
value={shippingDetails.telefon}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
/>
|
type='number'
|
||||||
</Item>
|
/>
|
||||||
<Item>
|
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
label={t('postalCode')}
|
label={t('address')}
|
||||||
name="postalCode"
|
name="address"
|
||||||
value={shippingDetails.postalCode}
|
value={shippingDetails.address}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
/>
|
required
|
||||||
</Item>
|
/>
|
||||||
<Item>
|
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
label={t('city')}
|
label={t('postalCode')}
|
||||||
name="city"
|
name="postalCode"
|
||||||
value={shippingDetails.city}
|
value={shippingDetails.postalCode}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
/>
|
required
|
||||||
</Item>
|
type='number'
|
||||||
<Item>
|
/>
|
||||||
<TextField
|
|
||||||
fullWidth
|
<TextField
|
||||||
label={t('country')}
|
fullWidth
|
||||||
name="country"
|
label={t('city')}
|
||||||
value={shippingDetails.country}
|
name="city"
|
||||||
onChange={handleInputChange}
|
value={shippingDetails.city}
|
||||||
/>
|
onChange={handleInputChange}
|
||||||
</Item>
|
required
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label={t('country')}
|
||||||
|
name="country"
|
||||||
|
value={shippingDetails.country}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
required
|
||||||
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
@@ -194,10 +224,10 @@ export default function Payment() {
|
|||||||
<Typography variant="h6">{t('orderedItems')}:</Typography>
|
<Typography variant="h6">{t('orderedItems')}:</Typography>
|
||||||
<List>
|
<List>
|
||||||
{basket.map((item) => (
|
{basket.map((item) => (
|
||||||
<ListItem key={item.itemId}>
|
<ListItem key={item.item.uuid}>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={`Item ID: ${item.itemId}`}
|
primary={`${item.item.name} (${item.item.price100 / 100} €)`}
|
||||||
secondary={`Quantity: ${item.quantity}`}
|
secondary={`Item ID: ${item.item.uuid} \n Quantity: ${item.quantity} \n Price: ${(item.item.price100 * item.quantity) / 100} €`}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
))}
|
))}
|
||||||
@@ -211,45 +241,53 @@ export default function Payment() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page-background">
|
<div className="page-background">
|
||||||
<Container maxWidth="md" sx={{ py: 4 }}>
|
<Container maxWidth="md" sx={{ py: 4 }}>
|
||||||
<Paper elevation={3} sx={{ p: 4 }}>
|
<Paper elevation={3} sx={{ p: 4 }}>
|
||||||
<Typography variant="h4" align="center" gutterBottom>
|
<Typography variant="h4" align="center" gutterBottom>
|
||||||
{t('completeYourOrder')}
|
{t('completeYourOrder')}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Stepper activeStep={activeStep} alternativeLabel>
|
<Stepper activeStep={activeStep} alternativeLabel>
|
||||||
{steps.map((label) => (
|
{steps.map((label) => (
|
||||||
<Step key={label}>
|
<Step key={label}>
|
||||||
<StepLabel>{label}</StepLabel>
|
<StepLabel>{label}</StepLabel>
|
||||||
</Step>
|
</Step>
|
||||||
))}
|
))}
|
||||||
</Stepper>
|
</Stepper>
|
||||||
<Box sx={{ mt: 4 }}>{renderStepContent(activeStep)}</Box>
|
<Box sx={{ mt: 4 }}>{renderStepContent(activeStep)}</Box>
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mt: 4 }}>
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', mt: 4 }}>
|
||||||
<Button
|
|
||||||
disabled={activeStep === 0}
|
|
||||||
onClick={handleBack}
|
|
||||||
variant="outlined"
|
|
||||||
>
|
|
||||||
{t('back')}
|
|
||||||
</Button>
|
|
||||||
{activeStep === steps.length - 1 ? (
|
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
disabled={activeStep === 0}
|
||||||
color="primary"
|
onClick={handleBack}
|
||||||
onClick={() => {
|
variant="outlined"
|
||||||
navigator('/');
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{t('finish')}
|
{t('back')}
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
{activeStep === steps.length - 1 ? (
|
||||||
<Button variant="contained" color="primary" onClick={handleNext}>
|
<Button
|
||||||
{activeStep === steps.length - 2 ? t('placeOrder') : t('next')}
|
variant="contained"
|
||||||
</Button>
|
color="primary"
|
||||||
)}
|
onClick={() => {
|
||||||
</Box>
|
navigator('/');
|
||||||
</Paper>
|
}}
|
||||||
</Container>
|
>
|
||||||
|
{t('finish')}
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={handleNext}
|
||||||
|
disabled={
|
||||||
|
basket.length === 0 ||
|
||||||
|
(activeStep === 1 && !isShippingDetailsValid())
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{activeStep === steps.length - 2 ? t('placeOrder') : t('next')}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
</Container>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user