Fix Mathu Coding und Payment fix

This commit is contained in:
FlorianSpeicher
2025-06-11 13:30:36 +02:00
parent 4b3d280789
commit ab72054820
7 changed files with 199 additions and 138 deletions

View File

@@ -59,7 +59,7 @@
"other": "Sonstiges",
"outOfStock": "Ausverkauft",
"payment": "Bezahlung",
"paymentNotAvailable": "Keine Zahlungsmöglichkeit hinterlegt.",
"paymentNotAvailable": "Keine Zahlungsmethoden verfügbar.",
"pageDoesNotExist": "Ups! Diese Seite existiert nicht.",
"phone": "Telefon",
"placeOrder": "Zahlungspflichtig bestellen",
@@ -91,5 +91,7 @@
"noRatingsYet": "Noch keine Bewertungen vorhanden.",
"accounts": "Konten",
"statistics": "Statistiken",
"thanksForRating": "Vielen Dank für die Bewertung!"
"thanksForRating": "Vielen Dank für die Bewertung!",
"telephone": "Telefon",
"basketEmpty": "Der Warenkorb ist leer."
}

View File

@@ -91,5 +91,7 @@
"noRatingsYet": "No ratings yet",
"accounts": "Accounts",
"statistics": "Statistics",
"thanksForRating": "Thank you for rating!"
"thanksForRating": "Thank you for rating!",
"telephone": "Telephone",
"basketEmpty": "The shopping cart is empty."
}

View File

@@ -1,13 +1,14 @@
import React, { createContext, useContext, useState } from 'react';
import Item from '../components/Item';
interface BasketItem {
itemId: string;
item: Item;
quantity: number;
}
interface BasketContextType {
basket: BasketItem[];
addToBasket: (itemId: string, quantity: number) => void;
addToBasket: (item: Item, quantity: number) => void;
clearBasket: () => void;
}
@@ -16,19 +17,19 @@ const BasketContext = createContext<BasketContextType | undefined>(undefined);
export const BasketProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [basket, setBasket] = useState<BasketItem[]>([]);
const addToBasket = (itemId: string, quantity: number) => {
const addToBasket = (item: Item, quantity: number) => {
setBasket((prevBasket) => {
const existingItem = prevBasket.find((item) => item.itemId === itemId);
const existingItem = prevBasket.find((basketItem) => basketItem.item.uuid === item.uuid);
if (existingItem) {
// Update quantity if item already exists
return prevBasket.map((item) =>
item.itemId === itemId
? { ...item, quantity: item.quantity + quantity }
: item
return prevBasket.map((basketItem) =>
basketItem.item.uuid === item.uuid
? { ...basketItem, quantity: basketItem.quantity + quantity }
: basketItem
);
}
// Add new item to basket
return [...prevBasket, { itemId, quantity }];
return [...prevBasket, { item, quantity }];
});
};

View File

@@ -14,7 +14,7 @@ export default function ItemCard({ item }: { item: Item }) {
const { addToBasket } = useBasket();
const handleAddToCart = () => {
addToBasket(item.id, 1);
addToBasket(item, 1);
console.log(`Added ${1} of ${item.name} to basket`);
};

View 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>
);
}

View File

@@ -41,7 +41,7 @@ export default function ProductInfo({ item }: { item: Item }) {
const handleAddToCart = () => {
addToBasket(item.id, quantity);
addToBasket(item, quantity);
setOpen(true);
console.log(`Added {quantity} of €{item.name} to basket`);
};

View File

@@ -1,32 +1,33 @@
import React, { useState } from 'react';
import {
Box,
Button,
Container,
Step,
StepLabel,
Stepper,
Typography,
TextField,
Divider,
Grid,
Paper,
List,
ListItem,
ListItemText,
Divider,
styled,
Paper,
Step,
StepLabel,
Stepper,
TextField,
Typography
} 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 {useTranslation} from "react-i18next";
import { useBasket } from '../helper/BasketProvider';
const Item = styled(Paper)(({ theme }) => ({
backgroundColor: theme.palette.background.paper,
color: theme.palette.text.primary,
...theme.typography.body2,
padding: theme.spacing(1),
textAlign: 'center',
}));
type ShippingDetails = {
firstName: string;
lastName: string;
telefon: string;
address: string;
postalCode: string;
city: string;
country: string;
};
export default function Payment() {
@@ -35,13 +36,14 @@ export default function Payment() {
const navigator = useNavigate();
const { basket, clearBasket } = useBasket();
const [activeStep, setActiveStep] = useState(0);
const [shippingDetails, setShippingDetails] = useState({
const [shippingDetails, setShippingDetails] = useState<ShippingDetails>({
firstName: '',
lastName: '',
telefon: '',
address: '',
postalCode: '',
city: '',
country: ''
country: 'Deutschland',
});
const [orderNumber, setOrderNumber] = useState<string | null>(null);
const steps = [t('reviewCart'), t('shippingDetails'), t('payment'), t('orderSummary')];
@@ -71,6 +73,18 @@ export default function Payment() {
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) => {
switch (step) {
case 0:
@@ -79,18 +93,24 @@ export default function Payment() {
<Typography variant="h6" gutterBottom>
{t('reviewCart')}
</Typography>
<List>
{basket.map((item) => (
<ListItem key={item.itemId}>
<ListItemText
primary={`Item ID: ${item.itemId}`}
secondary={`Quantity: ${item.quantity}`}
/>
</ListItem>
))}
</List>
{basket.length === 0 ? (
<Typography color="error" sx={{ my: 2 }}>
{t('basketEmpty')}
</Typography>
) : (
<List>
{basket.map((item) => (
<ListItem key={item.item.uuid}>
<ListItemText
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 }} />
<Button variant="outlined" color="error" onClick={handleClearBasket}>
<Button variant="outlined" color="error" onClick={handleClearBasket} disabled={basket.length === 0}>
{t('clearCart')}
</Button>
</Box>
@@ -102,60 +122,70 @@ export default function Payment() {
{t('shippingDetails')}
</Typography>
<Grid container spacing={2}>
<Item>
<TextField
fullWidth
label={t('firstName')}
name="firstName"
value={shippingDetails.firstName}
onChange={handleInputChange}
/>
</Item>
<Item>
<TextField
fullWidth
label={t('lastName')}
name="lastName"
value={shippingDetails.lastName}
onChange={handleInputChange}
/>
</Item>
<Item>
<TextField
fullWidth
label={t('address')}
name="address"
value={shippingDetails.address}
onChange={handleInputChange}
/>
</Item>
<Item>
<TextField
fullWidth
label={t('postalCode')}
name="postalCode"
value={shippingDetails.postalCode}
onChange={handleInputChange}
/>
</Item>
<Item>
<TextField
fullWidth
label={t('city')}
name="city"
value={shippingDetails.city}
onChange={handleInputChange}
/>
</Item>
<Item>
<TextField
fullWidth
label={t('country')}
name="country"
value={shippingDetails.country}
onChange={handleInputChange}
/>
</Item>
<TextField
fullWidth
label={t('firstName')}
name="firstName"
value={shippingDetails.firstName}
onChange={handleInputChange}
required
/>
<TextField
fullWidth
label={t('lastName')}
name="lastName"
value={shippingDetails.lastName}
onChange={handleInputChange}
required
/>
<TextField
fullWidth
label={t('telephone')}
name="telefon"
value={shippingDetails.telefon}
onChange={handleInputChange}
type='number'
/>
<TextField
fullWidth
label={t('address')}
name="address"
value={shippingDetails.address}
onChange={handleInputChange}
required
/>
<TextField
fullWidth
label={t('postalCode')}
name="postalCode"
value={shippingDetails.postalCode}
onChange={handleInputChange}
required
type='number'
/>
<TextField
fullWidth
label={t('city')}
name="city"
value={shippingDetails.city}
onChange={handleInputChange}
required
/>
<TextField
fullWidth
label={t('country')}
name="country"
value={shippingDetails.country}
onChange={handleInputChange}
required
/>
</Grid>
</Box>
);
@@ -194,10 +224,10 @@ export default function Payment() {
<Typography variant="h6">{t('orderedItems')}:</Typography>
<List>
{basket.map((item) => (
<ListItem key={item.itemId}>
<ListItem key={item.item.uuid}>
<ListItemText
primary={`Item ID: ${item.itemId}`}
secondary={`Quantity: ${item.quantity}`}
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>
))}
@@ -211,45 +241,53 @@ export default function Payment() {
return (
<div className="page-background">
<Container maxWidth="md" sx={{ py: 4 }}>
<Paper elevation={3} sx={{ p: 4 }}>
<Typography variant="h4" align="center" gutterBottom>
{t('completeYourOrder')}
</Typography>
<Stepper activeStep={activeStep} alternativeLabel>
{steps.map((label) => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
</Step>
))}
</Stepper>
<Box sx={{ mt: 4 }}>{renderStepContent(activeStep)}</Box>
<Box sx={{ display: 'flex', justifyContent: 'space-between', mt: 4 }}>
<Button
disabled={activeStep === 0}
onClick={handleBack}
variant="outlined"
>
{t('back')}
</Button>
{activeStep === steps.length - 1 ? (
<Container maxWidth="md" sx={{ py: 4 }}>
<Paper elevation={3} sx={{ p: 4 }}>
<Typography variant="h4" align="center" gutterBottom>
{t('completeYourOrder')}
</Typography>
<Stepper activeStep={activeStep} alternativeLabel>
{steps.map((label) => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
</Step>
))}
</Stepper>
<Box sx={{ mt: 4 }}>{renderStepContent(activeStep)}</Box>
<Box sx={{ display: 'flex', justifyContent: 'space-between', mt: 4 }}>
<Button
variant="contained"
color="primary"
onClick={() => {
navigator('/');
}}
disabled={activeStep === 0}
onClick={handleBack}
variant="outlined"
>
{t('finish')}
{t('back')}
</Button>
) : (
<Button variant="contained" color="primary" onClick={handleNext}>
{activeStep === steps.length - 2 ? t('placeOrder') : t('next')}
</Button>
)}
</Box>
</Paper>
</Container>
{activeStep === steps.length - 1 ? (
<Button
variant="contained"
color="primary"
onClick={() => {
navigator('/');
}}
>
{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>
);
}