Leagsy, an online gift shop for League of Legend fans, is a clone of the e-commerce website Etys. It offers a pleasant browsing experience on League of Legend merchandises. Users can browse, filter, sort, review, and add merchandises to her/his shopping cart.
Disclaimer: Leagsy is built for learning and demonostration purposes only. All images and descriptions associated with product listings were taken from Riot Games Merch
Leagsy is built using a Rails backend, PostgreSQL for the database management, Rails activestorage with AWS S3 cloud for image hosting, AJAX for API calls, and React/Redux for the frontend rendering and state management.
- Search product by name and category
- Press ESC to clear search
- Click on search result to go to product detail view
- Cycle through product photos by clicking the left/right arrow buttons
- Clicking image thunmbnail selects the image for large view
- Utilized react hook
useState()
to track and update the state of image display
const [current, setCurrent] = useState(0);
const length = images.length;
if (!Array.isArray(images) || images.length <= 0) return null;
const prevImg = () => {
setCurrent(current === 0 ? length - 1 : current - 1);
};
const nextImg = () => {
setCurrent(current === length - 1 ? 0 : current + 1);
};
- Sort products by price(high -> low or low -> high) or by rating(high -> low)
- Utilized ternary operator to sort products depending on the sorting preference(
selectedOptions
) stored in component state
const { selectedOption } = this.state;
const { category, filteredProducts } = this.props;
const sortedProducts =
selectedOption !== null
? selectedOption.value === "ratinghigh"
? filteredProducts.slice().sort((a, b) => b.avgRating - a.avgRating)
: selectedOption.value === "pricehigh"
? filteredProducts.slice().sort((a, b) => b.price - a.price)
: selectedOption.value === "pricelow"
? filteredProducts.slice().sort((a, b) => a.price - b.price)
: filteredProducts
: filteredProducts;
- Prompt user to login/registered before reviewing a product
- Check for required field (rating value) before allowing user to submit review
- Same user can only leave 1 review for each product
- Conditionally render review create form/ delete review button depending on the user state(login? reviewed?)
render(){
...
const ownReview = productReviews.filter(
(review) => review && review.reviewerId === sessionId
);
const othersReviews = productReviews.filter(
(review) => review && review.reviewerId !== sessionId
);
...
<div>
{ownReview && ownReview.length === 1 ? (
<ReviewShow review={ownReview[0]} key={ownReview[0].id} />
) : (
<ReviewForm productId={product.id} />
)}
{othersReviews.map((review, key) => (
<ReviewShow review={review} key={key} />
))}
</div>
}
- CRUD functions for shopping cart items
- Sync update item count indicator next to the shopping cart icon upon cart item creation/deletion
- Sync update cart sub-total upon cart item quantity update
Products seeding data are taking from Riot Merch Store
- Implement product search feature
- Refactor CSS code and optimize for mobile devices