Skip to content

Commit

Permalink
updated context store and create produce form
Browse files Browse the repository at this point in the history
  • Loading branch information
adizafri2000 committed Jun 21, 2024
1 parent 4834174 commit d013de0
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 88 deletions.
151 changes: 117 additions & 34 deletions web/src/components/CreateProduceForm.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,65 @@
import { useState } from "react";
import { TextField, Button, Box, Typography, useTheme, MenuItem } from '@mui/material';
import React, { useState, useContext, useEffect } from "react";
import { useNavigate } from 'react-router-dom';
import UserContext from '../contexts/UserContext.jsx';
import { TextField, Button, Box, Typography, Select, MenuItem, FormControl, InputLabel, Grid } from '@mui/material';
import CircularProgress from "@mui/material/CircularProgress";
import storeService from "../services/store.jsx";
import produceService from "../services/produce.jsx";

const CreateProduceForm = ({ store }) => {
const CreateProduceForm = () => {
const { user, loading: userContextLoading } = useContext(UserContext);
const [store, setStore] = useState();
const [name, setName] = useState('');
const [type, setType] = useState('');
const [stock, setStock] = useState('');
const [unitPrice, setUnitPrice] = useState('');
const [sellingUnit, setSellingUnit] = useState('');
const [description, setDescription] = useState('');
const [status, setStatus] = useState('');
const [image, setImage] = useState('');
const theme = useTheme();
const [imageFile, setImageFile] = useState(null);
const [fileError, setFileError] = useState('');
const [isLoading, setIsLoading] = useState(true);
const navigate = useNavigate()

useEffect(() => {
const fetchStoreFromContext = async () => {
if (!user) {
navigate('/login');
return;
}

try {
if (user.store) {
setStore(user.store);
} else {
console.log('User does not have a store')
navigate('/login');
}
} catch (error) {
console.error("Error fetching store or produce:", error);
} finally {
setIsLoading(false);
}
};

if (!userContextLoading) {
fetchStoreFromContext();
}
}, [userContextLoading, user, navigate])

const handleFileChange = (event) => {
const file = event.target.files[0];
if (file) {
if (!file.type.startsWith('image/')) {
setFileError('Invalid file type. Please select an image file.');
} else if (file.size > 10 * 1024 * 1024) { // file size limit 10MB
setFileError('File size should not exceed 10MB');
} else {
setFileError('');
setImageFile(file);
}
}
};

const handleSubmit = (event) => {
event.preventDefault();
Expand All @@ -23,25 +72,31 @@ const CreateProduceForm = ({ store }) => {
sellingUnit,
description,
status,
image,
image: imageFile,
store
};

console.log('Produce data:', data);
// TODO: Call the API to create the produce
};

if (userContextLoading || isLoading) {
return <CircularProgress />;
}

return (
<Box
component="form"
onSubmit={handleSubmit}
sx={{
display: 'flex',
flexDirection: 'column',
width: '300px',
maxWidth: '600px', // maximum width of the form
width: '100%', // form takes up 100% of the parent container's width
margin: '0 auto',
gap: '20px',
marginTop: '100px',
padding: '20px',
backgroundColor: '#FFFFFF',
}}
>
Expand All @@ -54,63 +109,91 @@ const CreateProduceForm = ({ store }) => {
value={name}
required={true}
onChange={({ target }) => setName(target.value)}
fullWidth
/>
<TextField
label="Type"
variant="outlined"
value={type}
required={true}
onChange={({ target }) => setType(target.value)}
/>
<FormControl fullWidth variant="outlined">
<InputLabel>Type</InputLabel>
<Select
label="Type"
value={type}
required={true}
onChange={({ target }) => setType(target.value)}
>
<MenuItem value="Vegetables">Vegetables</MenuItem>
<MenuItem value="Fruits">Fruits</MenuItem>
</Select>
</FormControl>
<TextField
label="Stock"
variant="outlined"
type="number"
value={stock}
required={true}
onChange={({ target }) => setStock(target.value)}
fullWidth
/>
<TextField
label="Unit Price"
variant="outlined"
type="number"
value={unitPrice}
required={true}
onChange={({ target }) => setUnitPrice(target.value)}
/>
<TextField
label="Selling Unit"
variant="outlined"
value={sellingUnit}
required={true}
onChange={({ target }) => setSellingUnit(target.value)}
/>
<Grid container spacing={2}>
<Grid item xs={12} sm={8}>
<TextField
label="Unit Price (RM)"
variant="outlined"
type="number"
value={unitPrice}
required={true}
onChange={({ target }) => setUnitPrice(target.value)}
fullWidth
/>
</Grid>
<Grid item xs={12} sm={4}>
<FormControl fullWidth variant="outlined">
<InputLabel>Selling Unit</InputLabel>
<Select
label="Selling Unit"
value={sellingUnit}
required={true}
onChange={({ target }) => setSellingUnit(target.value)}
>
<MenuItem value="kg">kg</MenuItem>
<MenuItem value="g">g</MenuItem>
<MenuItem value="piece">piece</MenuItem>
<MenuItem value="bag">bag</MenuItem>
<MenuItem value="box">box</MenuItem>
</Select>
</FormControl>
</Grid>
</Grid>
<TextField
label="Description"
variant="outlined"
value={description}
required={true}
onChange={({ target }) => setDescription(target.value)}
fullWidth
/>
<TextField
label="Status"
variant="outlined"
value={status}
required={true}
onChange={({ target }) => setStatus(target.value)}
fullWidth
/>
<label htmlFor="image-upload">Upload Produce Image:</label>
<TextField
label="Image URL"
id="image-upload"
type="file"
variant="outlined"
value={image}
required={true}
onChange={({ target }) => setImage(target.value)}
accept="image/*"
onChange={handleFileChange}
fullWidth
/>
{fileError && <p>{fileError}</p>}
<Button
variant="contained"
type="submit"
sx={{
backgroundColor: theme.palette.primary.main,
marginTop: '20px',
backgroundColor: '#3f51b5',
color: '#FFFFFF',
padding: '10px 20px',
borderRadius: '10px',
Expand Down
41 changes: 22 additions & 19 deletions web/src/contexts/UserContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,33 @@ export const UserProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);

// Load user from local storage
const setUserDetails = async (user) => {
try {
if (user.type === 'Farmer') {
const response = await storeService.getByFarmer(user.id);
setUser(prevUser => ({ ...prevUser, store: response.data.id }));
} else {
const response = await cartService.getByAccount(user.id);
setUser(prevUser => ({ ...prevUser, cart: response.data.id }));
}
} catch (error) {
if (error.status === 404) {
if (user.type === 'Farmer') {
setUser(prevUser => ({ ...prevUser, store: null }));
} else {
setUser(prevUser => ({ ...prevUser, cart: null }));
}
}
}
};

useEffect(() => {
const fetchUserData = async () => {
const storedUser = localStorage.getItem('user');
if (storedUser) {
const user = JSON.parse(storedUser);
setUser(user);

if (user.type === 'Farmer') {
console.log('Farmer account detected, fetching store and putting into user context')
const response = await storeService.getByFarmer(user.id);
setUser(prevUser => ({ ...prevUser, store: response.data.id }));
} else {
console.log('Consumer account detected, fetching cart and putting into user context')
const response = await cartService.getByAccount(user.id);
setUser(prevUser => ({ ...prevUser, cart: response.data.id }));
}
await setUserDetails(user);
}
setLoading(false);
}
Expand All @@ -36,14 +46,7 @@ export const UserProvider = ({ children }) => {
const user = { email, name, type, id, accessToken, refreshToken };
setUser(user);
localStorage.setItem('user', JSON.stringify(user));

if (type === 'farmer') {
const response = await storeService.getByFarmer(id);
setUser(prevUser => ({ ...prevUser, store: response.data.id }));
} else {
const response = await cartService.getByAccount(id);
setUser(prevUser => ({ ...prevUser, cart: response.data.id }));
}
await setUserDetails(user);
};

const logout = () => {
Expand Down
14 changes: 1 addition & 13 deletions web/src/pages/CreateProducePage.jsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,12 @@
import React, { useContext } from 'react';
import CreateProduceForm from '../components/CreateProduceForm.jsx';
import produceService from '../services/produce';
import UserContext from '../contexts/UserContext.jsx';

const CreateProducePage = () => {
const { user } = useContext(UserContext);

const handleCreateProduce = async (produceData) => {
try {
const response = await produceService.create(user.token, produceData);
console.log('Produce created:', response.data);
// TODO: Redirect to the store page or show a success message
} catch (error) {
console.error('Error creating produce:', error);
// TODO: Show an error message
}
};

return (
<CreateProduceForm store={user.store} onSubmit={handleCreateProduce} />
<CreateProduceForm />
);
};

Expand Down
33 changes: 21 additions & 12 deletions web/src/pages/StorePage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,17 @@ const StorePage = () => {
}

try {
if (user.type === 'Farmer') {
if (user.store) {
const response = await storeService.getByFarmer(user.id);
const storeData = response.data;
setStore(storeData);

const produceResponse = await produceService.getByStore(storeData.id);
const produceListData = produceResponse.data;
setProduceList(produceListData);
} else {
console.log('User does not have a store')
// Handle the case when user.store is null
}
} catch (error) {
console.error("Error fetching store or produce:", error);
Expand All @@ -53,18 +56,24 @@ const StorePage = () => {

return (
<Container>
<Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
<Typography variant="h4">{user.name}'s Store</Typography>
<Button variant="contained" onClick={() => navigate('/create-produce')}>Add New Produce</Button>
</Box>
<h3>{store?.name}</h3>
<Grid container spacing={3}>
{produceList.map(produce => (
<Grid item xs={12} sm={6} md={4} lg={3} key={produce.id}>
<ProduceCard produce={produce} />
{store ? (
<>
<Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
<Typography variant="h4">{user.name}'s Store</Typography>
<Button variant="contained" onClick={() => navigate('/store/create-produce')}>Add New Produce</Button>
</Box>
<h3>{store?.name}</h3>
<Grid container spacing={3}>
{produceList.map(produce => (
<Grid item xs={12} sm={6} md={4} lg={3} key={produce.id}>
<ProduceCard produce={produce} />
</Grid>
))}
</Grid>
))}
</Grid>
</>
) : (
<Typography variant="h6">No store exists for user</Typography>
)}
</Container>
);
};
Expand Down
6 changes: 3 additions & 3 deletions web/src/services/cart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ const getAll = async () => {
try {
return await api.get(`${baseUrl}`);
} catch (error) {
throw error.response.data.message;
throw error.response.data;
}
};

const getById = async (id) => {
try {
return await api.get(`${baseUrl}/${id}`);
} catch (error) {
throw error.response.data.message;
throw error.response.data;
}
};

const getByAccount = async (consumerId) => {
try {
return await api.get(`${baseUrl}?accountId=${consumerId}`);
} catch (error) {
throw error.response.data.message;
throw error.response.data;
}
};

Expand Down
Loading

0 comments on commit d013de0

Please sign in to comment.