Skip to content

Fahim #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-undef */
module.exports = {
env: { browser: true, es2020: true },
extends: [
Expand All @@ -10,5 +11,7 @@ module.exports = {
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': 'warn',

'@typescript-eslint/no-non-null-assertion': 'off',
},
}
};
698 changes: 548 additions & 150 deletions package-lock.json

Large diffs are not rendered by default.

34 changes: 23 additions & 11 deletions src/components/Cart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ import {
HiOutlineTrash,
} from 'react-icons/hi';
import { Button } from './ui/button';
import { IProduct } from '@/types/globalTypes';
import { useAppDispatch, useAppSelector } from '@/redux/hook';
import {
addtoCart,
removeFromCart,
removeOne,
} from '@/redux/feature/cart/CartSlice/cartSlice';

export default function Cart() {
//! Dummy data

const products: IProduct[] = [];
const total = 0;

//! **
//!! redux query
const { products, total } = useAppSelector((state) => state.Cart);
const dispatch = useAppDispatch();

return (
<Sheet>
Expand All @@ -47,18 +49,28 @@ export default function Cart() {
<h1 className="text-2xl self-center">{product?.name}</h1>
<p>Quantity: {product.quantity}</p>
<p className="text-xl">
Total Price: {(product.price * product.quantity!).toFixed(2)}{' '}
$
Total Price: {(product.price * product.quantity!).toFixed(2)}$
</p>
</div>
<div className="border-l pl-5 flex flex-col justify-between">
<Button>
<Button
onClick={() => {
dispatch(addtoCart(product));
}}
>
<HiOutlinePlus size="20" />
</Button>
<Button>
<Button
onClick={() => {
dispatch(removeOne(product));
}}
>
<HiMinus size="20" />
</Button>
<Button
onClick={() => {
dispatch(removeFromCart(product));
}}
variant="destructive"
className="bg-red-500 hover:bg-red-400"
>
Expand Down
5 changes: 5 additions & 0 deletions src/components/ProductCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import { IProduct } from '@/types/globalTypes';
import { toast } from './ui/use-toast';
import { Button } from './ui/button';
import { Link } from 'react-router-dom';
import { useAppDispatch } from '@/redux/hook';
import { addtoCart } from '@/redux/feature/cart/CartSlice/cartSlice';

interface IProps {
product: IProduct;
}

export default function ProductCard({ product }: IProps) {
const dispatch = useAppDispatch();
const handleAddProduct = (product: IProduct) => {
// use dispatch to send data into redux store
dispatch(addtoCart(product));
toast({
description: 'Product Added',
});
Expand Down
70 changes: 58 additions & 12 deletions src/components/ProductReview.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,72 @@
import { ChangeEvent, FormEvent, useState } from 'react';
import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar';
import { Button } from './ui/button';
import { Textarea } from './ui/textarea';
import { FiSend } from 'react-icons/fi';
import {
useGetCommentQuery,
usePostCommentMutation,
} from '@/redux/feature/product/productApi/productApi';

const dummyComments = [
'Bhalo na',
'Ki shob ghori egula??',
'Eta kono product holo ??',
'200 taka dibo, hobe ??',
];
// const dummyComments = [
// 'Bhalo na',
// 'Ki shob ghori egula??',
// 'Eta kono product holo ??',
// '200 taka dibo, hobe ??',
// ];

interface IProps {
id: string;
}

export default function ProductReview({ id }: IProps) {
// !! get query
const { data } = useGetCommentQuery(id, {
refetchOnMountOrArgChange: true,
pollingInterval: 30000,
});

//!! post mutation
const [postComment, { isError, isLoading, isSuccess }] =
usePostCommentMutation();
console.log(`${isLoading} ${isError} ${isSuccess}`);

const [inputValue, setInputValue] = useState<string>('');
console.log(inputValue);
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();

// ! post comment using Mutation
const options = {
id: id,
comment: { comment: inputValue },
};
postComment(options);

setInputValue('');
};

const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
setInputValue(event.target.value);
};

export default function ProductReview() {
return (
<div className="max-w-7xl mx-auto mt-5">
<div className="flex gap-5 items-center">
<Textarea className="min-h-[30px]" />
<Button className="rounded-full h-10 w-10 p-2 text-[25px]">
<form className="flex gap-5 items-center" onSubmit={handleSubmit}>
<Textarea
className="min-h-[30px]"
onChange={handleChange}
value={inputValue}
/>
<Button
type="submit"
className="rounded-full h-10 w-10 p-2 text-[25px]"
>
<FiSend />
</Button>
</div>
</form>
<div className="mt-10">
{dummyComments.map((comment, index) => (
{data?.comment?.map((comment: string, index: number) => (
<div key={index} className="flex gap-3 items-center mb-5">
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" />
Expand Down
15 changes: 15 additions & 0 deletions src/lib/firebase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { initializeApp } from 'firebas/app';
import { getAuth } from 'firebase/auth';

const firebaseConfig = {
apiKey: 'AIzaSyDiXjaqDcUBVWR440_aZk5DbLpgXsRSsqQ',
authDomain: 'simple-ema-john-8bc50.firebaseapp.com',
projectId: 'simple-ema-john-8bc50',
storageBucket: 'simple-ema-john-8bc50.appspot.com',
messagingSenderId: '1080330401067',
appId: '1:1080330401067:web:bc3f1b9675b3d45cf0816e',
};

const app = initializeApp(firebaseConfig);

export const auth = getAuth(app);
6 changes: 5 additions & 1 deletion src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ import ReactDOM from 'react-dom/client';
import './index.css';
import { RouterProvider } from 'react-router-dom';
import routes from './routes/routes.tsx';
import { Provider } from 'react-redux';
import { store } from './redux/store.ts';

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<RouterProvider router={routes} />
<Provider store={store}>
<RouterProvider router={routes} />
</Provider>
</React.StrictMode>
);
6 changes: 2 additions & 4 deletions src/pages/Checkout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Label } from '@/components/ui/label';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { Switch } from '@/components/ui/switch';
import { Textarea } from '@/components/ui/textarea';
import { IProduct } from '@/types/globalTypes';
import { useAppSelector } from '@/redux/hook';

import { useState } from 'react';

Expand All @@ -14,9 +14,7 @@ export default function Checkout() {

//! Dummy Data

const products: IProduct[] = [];

//! **
const { products } = useAppSelector((state) => state.Cart);

return (
<div className="flex justify-center items-center h-[calc(100vh-80px)] gap-10 text-primary">
Expand Down
19 changes: 4 additions & 15 deletions src/pages/ProductDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,12 @@
import ProductReview from '@/components/ProductReview';
import { Button } from '@/components/ui/button';
import { IProduct } from '@/types/globalTypes';
import { useEffect, useState } from 'react';
import { useSingleProductQuery } from '@/redux/feature/product/productApi/productApi';
import { useParams } from 'react-router-dom';

export default function ProductDetails() {
const { id } = useParams();

//! Temporary code, should be replaced with redux
const [data, setData] = useState<IProduct[]>([]);
useEffect(() => {
fetch('../../public/data.json')
.then((res) => res.json())
.then((data) => setData(data));
}, []);

const product = data?.find((item) => item._id === Number(id));

//! Temporary code ends here
const { data: product } = useSingleProductQuery(id);

return (
<>
Expand All @@ -29,14 +18,14 @@ export default function ProductDetails() {
<h1 className="text-3xl font-semibold">{product?.name}</h1>
<p className="text-xl">Rating: {product?.rating}</p>
<ul className="space-y-1 text-lg">
{product?.features?.map((feature) => (
{product?.features?.map((feature: string) => (
<li key={feature}>{feature}</li>
))}
</ul>
<Button>Add to cart</Button>
</div>
</div>
<ProductReview />
<ProductReview id={id!} />
</>
);
}
43 changes: 23 additions & 20 deletions src/pages/Products.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,51 @@ import { Label } from '@/components/ui/label';
import { Slider } from '@/components/ui/slider';
import { Switch } from '@/components/ui/switch';
import { useToast } from '@/components/ui/use-toast';
import { useGetProductsQuery } from '@/redux/feature/product/productApi/productApi';
import {
setPriceRange,
toggleStatus,
} from '@/redux/feature/product/productSlice/productSlice';
import { useAppDispatch, useAppSelector } from '@/redux/hook';
import { IProduct } from '@/types/globalTypes';
import { useEffect, useState } from 'react';

export default function Products() {
const [data, setData] = useState<IProduct[]>([]);
useEffect(() => {
fetch('./data.json')
.then((res) => res.json())
.then((data) => setData(data));
}, []);
const { data, isLoading, error } = useGetProductsQuery(undefined);
console.log(isLoading, error);

const { toast } = useToast();

//! Dummy Data

const status = true;
const priceRange = 100;

//! **
const { priceRange, status } = useAppSelector((state) => state.Product);
const dispatch = useAppDispatch();

const handleSlider = (value: number[]) => {
console.log(value);
dispatch(setPriceRange(value[0]));
};

let productsData;

if (status) {
productsData = data.filter(
(item) => item.status === true && item.price < priceRange
productsData = data?.data?.filter(
(item: { status: boolean; price: number }) =>
item.status === true && item.price < priceRange
);
} else if (priceRange > 0) {
productsData = data.filter((item) => item.price < priceRange);
productsData = data?.data?.filter(
(item: { price: number }) => item.price < priceRange
);
} else {
productsData = data;
productsData = data?.data;
}

return (
<div className="grid grid-cols-12 max-w-7xl mx-auto relative ">
<div className="col-span-3 z mr-10 space-y-5 border rounded-2xl border-gray-200/80 p-5 self-start sticky top-16 h-[calc(100vh-80px)]">
<div>
<h1 className="text-2xl uppercase">Availability</h1>
<div className="flex items-center space-x-2 mt-3">
<div
onClick={() => dispatch(toggleStatus())}
className="flex items-center space-x-2 mt-3"
>
<Switch id="in-stock" />
<Label htmlFor="in-stock">In stock</Label>
</div>
Expand All @@ -64,7 +67,7 @@ export default function Products() {
</div>
</div>
<div className="col-span-9 grid grid-cols-3 gap-10 pb-20">
{productsData?.map((product) => (
{productsData?.map((product: IProduct) => (
<ProductCard product={product} />
))}
</div>
Expand Down
10 changes: 10 additions & 0 deletions src/redux/api/apiSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

export const api = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:5000' }),
tagTypes: ['comments'],
endpoints: () => ({}),
});

export default api;
Loading