First Pass at E-Commerce Front End Service#1
Conversation
mikellewade
left a comment
There was a problem hiding this comment.
Look through the application and great as a first pass! Left some comments mainly about making it more DRY so students have less to read through, conceptual questions and then some niceties. Let me know if you have any questions.
| <div> | ||
| <label>ID</label> | ||
| <input type="text" value={user.id} disabled /> | ||
| </div> | ||
| <div> | ||
| <label>First Name</label> | ||
| <input | ||
| type="text" | ||
| name="firstName" | ||
| value={formData.firstName} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> |
There was a problem hiding this comment.
You could make a helper function that constructs the controlled inputs. If you look in Flasky Frontend, you will see the pattern. I believe it's in one of the Forms sessions. That way the code will be more DRY. Would most likely need to alter the function, of course.
| })); | ||
| }; | ||
|
|
||
| const handleSubmit = (e: FormEvent) => { |
There was a problem hiding this comment.
In VScode it says that FormEvent is deprecated. It states that the following:
" FormEvent doesn't actually exist. You probably meant to use ChangeEvent, InputEvent, SubmitEvent, or just SyntheticEvent instead depending on the event type."
Based on the function, I am assuming that you will need a SubmitEvent instead.
There was a problem hiding this comment.
I missed this one when I was refactoring! Changed it to a SubmitEvent!
|
|
||
| const [status, setStatus] = useState<'idle' | 'saving' | 'saved' | 'error'>('idle'); | ||
|
|
||
| const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { |
There was a problem hiding this comment.
Instead of the React.ChangeEvent<HTMLInputElement>, I think you could remove the React prefix and just import it at the top of the file like the FormEvent.
| const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
| const { name, value, type, checked } = e.target; | ||
| setFormData(prev => ({ | ||
| ...prev, | ||
| [name]: type === 'checkbox' ? checked : value, | ||
| })); | ||
| }; | ||
|
|
||
| const handleSubmit = (e: React.SubmitEvent<HTMLFormElement>) => { |
There was a problem hiding this comment.
Like in the UserForm.tsx, just a suggestion to import the different events that the top of the file to remove the React prefix.
| <form onSubmit={handleSubmit}> | ||
| <div> | ||
| <label>First Name</label> | ||
| <input | ||
| type="text" | ||
| name="firstName" | ||
| value={formData.firstName} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| <div> | ||
| <label>Last Name</label> | ||
| <input | ||
| type="text" | ||
| name="lastName" | ||
| value={formData.lastName} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> |
There was a problem hiding this comment.
As mentioned in UserForm.tsx, you could DRY this up by making the helper function that constructs controlled inputs.
|
|
||
| const orderCards = orders.map((order: Order) => { | ||
| return ( | ||
| <li key={order.id}> |
There was a problem hiding this comment.
Currently, you have an li item tag here and also inside the OrderCard.tsx component. React is throwing a warning about having li tags nested within li tags. I think it is safe to remove the one inside the OrderCard.tsx file.
There was a problem hiding this comment.
Changed it to a dummy parent tag!
| <li><button onClick={()=>deleteProduct(id)}>Delete Item</button></li> | ||
| </> | ||
| ) : ( | ||
| <li><button onClick={() => addItem({ productId: id, name, price, quantity: numItem })}>Add to Cart</button></li> |
There was a problem hiding this comment.
Could we maybe add some user feedback here for when the item is added? At first I didn't think that it worked .
There was a problem hiding this comment.
Added some very simple feedback!
There was a problem hiding this comment.
In this file, there are a few times you reference an individual item as i, could we choose a variable name that is more descriptive of the data that it is referencing?
| userId: user?.id ?? '', | ||
| userEmail: user?.email ?? '', |
There was a problem hiding this comment.
Conceptually speaking, I would assume that any consumer that needs this information would call the useAuth hook to retrieve this information. Would we want to remove this from the Cart context?
…and updating product with image
Co-authored-by: Mikelle <119449245+mikellewade@users.noreply.github.com>
|
Thank you so much for looking through this and for your suggestions! I think I got them all with a couple that I'll save for another update. The big ones I got were:
|
mikellewade
left a comment
There was a problem hiding this comment.
So sorry, I did not see that you submitted all the changes. The reply in the thread was late at night so I didn't see the notification. Apologies! But looks great, just commented about a couple of things. Let me know what you think or if you have any questions.
There was a problem hiding this comment.
Oh nice! I didn't even think about this approach.
| e.preventDefault(); | ||
| setStatus('saving'); | ||
|
|
||
| if(user === null){ |
There was a problem hiding this comment.
| if(user === null){ | |
| if (user === null){ |
| axios.post(`${userUrl}/users/`, { | ||
| first_name: formData.firstName, | ||
| last_name: formData.lastName, | ||
| email: formData.email, | ||
| is_admin: formData.isAdmin, | ||
| }) | ||
| .then(() => setStatus('saved')) | ||
| .catch(() => setStatus('error')); | ||
| } | ||
| else { | ||
| axios.put(`${userUrl}/users/${user?.id}`, { | ||
| first_name: formData.firstName, | ||
| last_name: formData.lastName, | ||
| email: formData.email, | ||
| is_admin: formData.isAdmin, | ||
| }) | ||
| .then(() => setStatus('saved')) | ||
| .catch(() => setStatus('error')); | ||
| } |
There was a problem hiding this comment.
Given that the only difference between these calls are the HTTP methods (put vs post) and the URLs. To make it more DRY you could condense this to a function and then have a conditional. Something like this perhaps:
const saveUser = () => {
const method = user ? 'put' : 'post';
const url = user ? `${userUrl}/users/${user.id}` : `${userUrl}/users/`;
axios[method](url, {
first_name: formData.firstName,
last_name: formData.lastName,
email: formData.email,
is_admin: formData.isAdmin,
})
.then(() => setStatus('saved'))
.catch(() => setStatus('error'));
};|
|
||
| const orderCards = orders.map((order: Order) => { | ||
| return ( | ||
| <li key={order.id}> |
| const inputName = event.target.name; | ||
|
|
||
| setFormState(prev => ({...prev, | ||
| [inputName]: inputName ==='price'|| inputName === 'stock'? Number(inputValue) : inputValue})); |
There was a problem hiding this comment.
| [inputName]: inputName ==='price'|| inputName === 'stock'? Number(inputValue) : inputValue})); | |
| [inputName]: inputName ==='price'|| inputName === 'stock' ? Number(inputValue) : inputValue})); |
| onChange={handleChange} | ||
| /> | ||
| ); | ||
| }; |
There was a problem hiding this comment.
You could refactor the you make controlled components into a single one and pull it out into a utility file so the code would be more DRY. But I don't think that is the highest priority.
|
|
||
| return ( | ||
| <div> | ||
| <h1> Add User </h1> |
There was a problem hiding this comment.
A conditional based on if the user is null or not for Update User or Add User?
There was a problem hiding this comment.
Maybe just some styling on this component so it is easier to digest the information being displayed?
| const addStock = (product: Product, newStock: number) => { | ||
| return { ...product, stock: newStock}; | ||
| }; | ||
|
|
||
| const getAllProductsAPI = () => { | ||
| return axios.get(`${productUrl}/products/`) | ||
| .then(response => response.data) | ||
| }; | ||
| const updateProductAPI = (id: string, updateData: Partial<Product>) => { | ||
| return axios.patch(`${productUrl}/products/${id}`, updateData) | ||
| } | ||
| const deleteProductAPI = (id : string) => { | ||
| return axios.delete(`${productUrl}/products/${id}`) | ||
| }; | ||
| const convertFromAPI = (apiProduct: APIProduct): Product => { | ||
| return { | ||
| ...apiProduct, | ||
| id: apiProduct.productId, | ||
| }; | ||
|
|
||
| }; | ||
| const addProductAPI = (newProduct: Omit<Product, 'id'>) => { | ||
| return axios.post(`${productUrl}/products/`, newProduct) | ||
| .then(response => response.data) | ||
| }; |
| id: String(fetchedUser.id), | ||
| firstName: fetchedUser.first_name, | ||
| lastName: fetchedUser.last_name, | ||
| email: fetchedUser.email, | ||
| isAdmin: fetchedUser.is_admin // Map snake_case to camelCase |
There was a problem hiding this comment.
Yeah, I don't think its terribly important.
This is a basic front end for the E-Commerce Site. Minimal testing and styling currently that will be built out later.
Current abilities:
Login - User can login or create a new account, which will be sent to the User Microservice
Products - If the user is an admin, they can see all the products, delete them or update stock on the Home page. If the user is not an admin, they can see all products and add them to a cart.
Orders - As a cart is created, users can submit a cart to the Order microservice. Admins can see all orders. Non-Admins can see their orders.
User - Users can update their own information.