diff --git a/package-lock.json b/package-lock.json index e49778e..2098e2f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "autoprefixer": "10.4.15", "axios": "^1.5.1", "class-variance-authority": "^0.7.0", - "clsx": "^2.0.0", + "clsx": "^2.1.0", "eslint": "8.47.0", "eslint-config-next": "^14.1.0", "lucide-react": "^0.298.0", @@ -33,7 +33,7 @@ "react-dom": "^18.2.0", "react-icons": "^4.12.0", "react-redux": "^8.1.3", - "tailwind-merge": "^2.1.0", + "tailwind-merge": "^2.2.1", "tailwindcss": "3.3.3", "tailwindcss-animate": "^1.0.7", "typescript": "5.1.6" @@ -62,9 +62,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz", - "integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1616,15 +1616,23 @@ "url": "https://joebell.co.uk" } }, + "node_modules/class-variance-authority/node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" }, "node_modules/clsx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", "engines": { "node": ">=6" } @@ -4625,11 +4633,11 @@ } }, "node_modules/tailwind-merge": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.1.0.tgz", - "integrity": "sha512-l11VvI4nSwW7MtLSLYT4ldidDEUwQAMWuSHk7l4zcXZDgnCRa0V3OdCwFfM7DCzakVXMNRwAeje9maFFXT71dQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.1.tgz", + "integrity": "sha512-o+2GTLkthfa5YUt4JxPfzMIpQzZ3adD1vLVkvKE1Twl9UAhGsEbIZhHHZVRttyW177S8PDJI3bTQNaebyofK3Q==", "dependencies": { - "@babel/runtime": "^7.23.5" + "@babel/runtime": "^7.23.7" }, "funding": { "type": "github", @@ -5129,9 +5137,9 @@ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==" }, "@babel/runtime": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz", - "integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "requires": { "regenerator-runtime": "^0.14.0" } @@ -6055,6 +6063,13 @@ "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==", "requires": { "clsx": "2.0.0" + }, + "dependencies": { + "clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==" + } } }, "client-only": { @@ -6063,9 +6078,9 @@ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" }, "clsx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==" }, "color-convert": { "version": "2.0.1", @@ -8120,11 +8135,11 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, "tailwind-merge": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.1.0.tgz", - "integrity": "sha512-l11VvI4nSwW7MtLSLYT4ldidDEUwQAMWuSHk7l4zcXZDgnCRa0V3OdCwFfM7DCzakVXMNRwAeje9maFFXT71dQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.1.tgz", + "integrity": "sha512-o+2GTLkthfa5YUt4JxPfzMIpQzZ3adD1vLVkvKE1Twl9UAhGsEbIZhHHZVRttyW177S8PDJI3bTQNaebyofK3Q==", "requires": { - "@babel/runtime": "^7.23.5" + "@babel/runtime": "^7.23.7" } }, "tailwindcss": { diff --git a/package.json b/package.json index 5bcca79..515f843 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "autoprefixer": "10.4.15", "axios": "^1.5.1", "class-variance-authority": "^0.7.0", - "clsx": "^2.0.0", + "clsx": "^2.1.0", "eslint": "8.47.0", "eslint-config-next": "^14.1.0", "lucide-react": "^0.298.0", @@ -34,7 +34,7 @@ "react-dom": "^18.2.0", "react-icons": "^4.12.0", "react-redux": "^8.1.3", - "tailwind-merge": "^2.1.0", + "tailwind-merge": "^2.2.1", "tailwindcss": "3.3.3", "tailwindcss-animate": "^1.0.7", "typescript": "5.1.6" diff --git a/src/app/(index)/page.tsx b/src/app/(index)/page.tsx index bd5beb2..39fd368 100644 --- a/src/app/(index)/page.tsx +++ b/src/app/(index)/page.tsx @@ -1,11 +1,14 @@ import { Fragment } from "react" import { headers } from 'next/headers'; import Link from "next/link"; +import { redirect } from 'next/navigation' + const Page = ()=>{ const headersList = headers(); const activePath = headersList.get('x-invoke-path'); + redirect('/shop') return ( <> @@ -44,7 +47,7 @@ const Page = ()=>{ : null }
- +
) diff --git a/src/app/(index)/shop/product/[id]/page.tsx b/src/app/(index)/shop/product/[id]/page.tsx index b8b5507..4f85852 100644 --- a/src/app/(index)/shop/product/[id]/page.tsx +++ b/src/app/(index)/shop/product/[id]/page.tsx @@ -6,18 +6,30 @@ import { useRouter } from 'next/navigation' import { useQuery, useQueryClient } from '@tanstack/react-query' import axiosInstance from '@/axios/axiosInstance' import { useState } from 'react' - +import { + Table, + TableBody, + TableCaption, + TableCell, + TableFooter, + TableHead, + TableHeader, + TableRow, + } from "@/components/ui/table" const Page = ({ params }: { params: { id: string } })=>{ const router = useRouter(); - const [products, setProducts] = useState<{category_name: string, category_img: string, products:[{id:number, name:string, price: number}]}>() + const [products, setProducts] = useState<{category_name: string, category_img: string, + products:[{id:number, name:string, price: number, view_only: boolean}], + view_only_products:[{id:number, name:string, price: number, view_only: boolean}] + }>() const query = useQuery({ queryKey: ['productListByCat'], queryFn: async ()=>{ return await axiosInstance.get(`shop/product/list/${params.id}/`) - }, onSuccess(data:any) { - setProducts(data.data) + }, onSuccess(result:any) { + setProducts(result.data) }, }); if(query.isLoading){ @@ -33,41 +45,64 @@ const Page = ({ params }: { params: { id: string } })=>{ return ( <>
-
+
- + {products?.category_name} - { router.push('/shop', { scroll: false }) }} className='cursor-pointer bg-cyan-700 pr-1 pl-1 text-white text-[0.9rem] rounded'>بازگشت + { router.push('/shop', { scroll: false }) }} className='disable-select cursor-pointer bg-cyan-700 pr-1 pl-1 text-white text-[0.9rem] rounded'>بازگشت
-
- +
+
{products?.products.map((iteam)=>{ - return () + if (iteam.view_only!=true){ + return () + } })} - -
-
+ {products?.view_only_products ? ( -

محصول زیر فقط بر مبنای سفارش قابل تولید است

+
+ +

محصولات زیر فقط بر مبنای سفارش قابل تولید است

+ + + + + کد محصول + نام محصول + + + + + {products?.view_only_products.map((iteam:any, key:any)=>{ + return ( + + ----- + {iteam.name} + + ) + })} + + +
- - -
+ + ) : null} + -
{ router.push('/shop', { scroll: false }) }} className='w-full text-center bg-gray-800 text-white rounded mt-2 p-2'> +
{ router.push('/shop', { scroll: false }) }} className='disable-select w-full text-center bg-gray-800 text-white rounded mt-2 p-2'> بازگشت به صفحه قبل
diff --git a/src/app/components/layout/customer-info.tsx b/src/app/components/layout/customer-info.tsx index 9499ef3..b9d77a7 100644 --- a/src/app/components/layout/customer-info.tsx +++ b/src/app/components/layout/customer-info.tsx @@ -26,8 +26,8 @@ const CustomerInfo = ()=>{ return (
-
{nameFamily}
-
خروج
+
{nameFamily}
+
خروج
) } diff --git a/src/app/components/layout/hamber-menu.tsx b/src/app/components/layout/hamber-menu.tsx index 7d03c3d..c558179 100644 --- a/src/app/components/layout/hamber-menu.tsx +++ b/src/app/components/layout/hamber-menu.tsx @@ -1,13 +1,16 @@ 'use client' import { useState } from "react" import TopMenu from "./top-menu" +import { IoMenu } from "react-icons/io5"; const HamberMenu = ()=>{ const [showMenu, setShowMenu] = useState(false) return (
- { setShowMenu(!showMenu) }} >منو + { setShowMenu(!showMenu) }} > + +
) diff --git a/src/app/components/layout/shop/orders-list.tsx b/src/app/components/layout/shop/orders-list.tsx index e282725..9c3cbfb 100644 --- a/src/app/components/layout/shop/orders-list.tsx +++ b/src/app/components/layout/shop/orders-list.tsx @@ -10,12 +10,14 @@ import { RootState } from "@/app/redux/store" import axiosInstance from "@/axios/axiosInstance" import { addAllToCars, removeAllFromCart } from '@/app/redux/features/cartSlice'; import { useState } from 'react' +import {useRouter} from "next/navigation"; const OrdersList = ()=>{ const {orderList} = useOrderContext() const cartData = useSelector((state: RootState) => state.cart) const dispatch = useDispatch() + const router = useRouter() const query = useQuery({ queryKey: ['cartList1'], queryFn: async ()=>{ return await axiosInstance.get(`shop/cart/`) @@ -24,8 +26,12 @@ const OrdersList = ()=>{ }, }); const [cartIsOpen, setCartIsOpen ] = useState(false) + const [disableSubmit, setDisableSubmit] = useState(false) const submitOrder = async ()=>{ + + + setDisableSubmit(true) const orderData = await cartData.map((item)=>{ return { product_id: item.product.id, @@ -38,8 +44,11 @@ const OrdersList = ()=>{ }) if(newOrder.status == 201){ + setDisableSubmit(false) alert("ثبت سفارش انجام شد") dispatch(removeAllFromCart()) + router.push('/orders') + //window.location.reload() } @@ -51,7 +60,7 @@ const OrdersList = ()=>{
- سبد خرید شما + سبد خرید شما { setCartIsOpen(false) }} className="md:hidden bg-slate-900 rounded-lg pr-2 pl-2 pt-1 pb-1">بستن
@@ -59,25 +68,44 @@ const OrdersList = ()=>{ {cartData?cartData.map((iteam, key)=>{ return }):null } + +
+

مشاهده کامل سبد خرید

+ + {!disableSubmit ? ( +
+ ثبت نهایی +
+ ) : null} +
+
-
+
+ +

مشاهده کامل سبد خرید

+ + {!disableSubmit ? ( +
+ ثبت نهایی +
+ ) : null} + -

مشاهده کامل سبد خرید

-
- ثبت نهایی -
{cartData.length > 0 ? ( -
+
{ setCartIsOpen(true) }} className='bg-cyan-800 cursor-pointer text-white rounded-lg pt-2 pb-2 pr-4 pl-4'> - مشاهده سبد خرید - {cartData ? cartData.length : null} + مشاهده سبد خرید + {cartData ? cartData.length : null}
) : null} diff --git a/src/app/components/layout/shop/products-cat.tsx b/src/app/components/layout/shop/products-cat.tsx index b00cec5..4f63055 100644 --- a/src/app/components/layout/shop/products-cat.tsx +++ b/src/app/components/layout/shop/products-cat.tsx @@ -17,17 +17,17 @@ const ProductCategoryBox: any = (props:any)=>{ } return (
-

{props.iteam.name}

+

{props.iteam.name}

- a + a
- + {`${props.iteam.product_count} نوع`} - + مشاهده
diff --git a/src/app/components/layout/shop/products.tsx b/src/app/components/layout/shop/products.tsx index 5fed9b9..fef6b8e 100644 --- a/src/app/components/layout/shop/products.tsx +++ b/src/app/components/layout/shop/products.tsx @@ -70,13 +70,13 @@ const Products = (props:any)=>{
- {props.iteam.name} + {props.iteam.name}
-
- {formatCurrency(props.iteam.price)} - تومان +
+ {formatCurrency(props.iteam.price)} + تومان
@@ -84,8 +84,8 @@ const Products = (props:any)=>{
-
- { addIteamToCart(props.iteam) }} className='cursor-pointer bg-lime-600 text-white rounded pt-1 pb-1 w-full text-center'> +
+ { addIteamToCart(props.iteam) }} className='disable-select cursor-pointer bg-lime-600 text-white rounded pt-1 pb-1 w-full text-center'> {isInCart? "ویرایش":"ثبت"}
diff --git a/src/app/components/layout/top-menu.tsx b/src/app/components/layout/top-menu.tsx index 2d450ef..54011d1 100644 --- a/src/app/components/layout/top-menu.tsx +++ b/src/app/components/layout/top-menu.tsx @@ -1,5 +1,6 @@ import Link from 'next/link' + interface TopMenuProps { showMenu: boolean, setShowMenu: Function, @@ -7,15 +8,20 @@ interface TopMenuProps { const TopMenu = (props: TopMenuProps)=>{ return ( -
    - { props.setShowMenu(false) }} href={"/"}> +
      + + { props.setShowMenu(false) }} href={"/shop"}>
    • صفحه اصلی
    • -
    • سفارشات
    • -
    • تیکت ها
    • -
    • چک ها
    • -
    • واریزی ها
    • -
    • صورت حساب
    • + + { props.setShowMenu(false) }} href={"/orders"}> +
    • سفارشات
    • + + + { props.setShowMenu(false) }} href={"/tickets"}> +
    • تیکت ها
    • + +
    ) } diff --git a/src/app/globals.css b/src/app/globals.css index 6a75725..0760c1c 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -73,4 +73,12 @@ body { @apply bg-background text-foreground; } + .disable-select { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } } \ No newline at end of file diff --git a/src/axios/axiosInstance.ts b/src/axios/axiosInstance.ts index 5912d78..169ef40 100644 --- a/src/axios/axiosInstance.ts +++ b/src/axios/axiosInstance.ts @@ -39,31 +39,47 @@ axiosInstance.interceptors.response.use((response)=> { try { - const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/auth/token/refresh/`, { - method: "POST", - headers: { - 'Content-Type': 'application/json; charset=UTF-8', - }, - body: JSON.stringify({ - 'refresh': localStorage.getItem('refresh') - }) - }); + if (localStorage.getItem('refresh') != 'undefined'){ + const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/auth/token/refresh/`, { + method: "POST", + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + }, + body: JSON.stringify({ + 'refresh': localStorage.getItem('refresh') + }) + }); + + if(res.status==200){ + setCookieFn('isAuth', 'true', 365) + const tokenData = await res.json() + localStorage.setItem('access', tokenData.access) + localStorage.setItem('refresh',tokenData.refresh) + originalRequest.headers.Authorization = `Bearer ${tokenData.access}` + return axiosInstance(originalRequest) + }else{ + + } + } else { + + localStorage.removeItem('access'); + localStorage.removeItem('refresh'); + document.cookie = "isAuth=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; + setTimeout(()=>{ + window.location.replace('/login') + }, 200) - if(res.status==200){ - setCookieFn('isAuth', 'true', 365) - const tokenData = await res.json() - localStorage.setItem('access', tokenData.access) - localStorage.setItem('refresh',tokenData.refresh) - originalRequest.headers.Authorization = `Bearer ${tokenData.access}` - return axiosInstance(originalRequest) - }else{ - } - - } catch(refreshError) { - + + localStorage.removeItem('access'); + localStorage.removeItem('refresh'); + document.cookie = "isAuth=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; + setTimeout(()=>{ + window.location.replace('/login') + }, 200) + throw refreshError; } } diff --git a/src/lib/utils.ts b/src/lib/utils.ts index ec79801..d084cca 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,6 +1,6 @@ import { type ClassValue, clsx } from "clsx" import { twMerge } from "tailwind-merge" - + export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } diff --git a/tailwind.config.ts b/tailwind.config.ts index 0377ea1..84287e8 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,5 +1,6 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { +import type { Config } from "tailwindcss" + +const config = { darkMode: ["class"], content: [ './pages/**/*.{ts,tsx}', @@ -7,6 +8,7 @@ module.exports = { './app/**/*.{ts,tsx}', './src/**/*.{ts,tsx}', ], + prefix: "", theme: { container: { center: true, @@ -58,12 +60,12 @@ module.exports = { }, keyframes: { "accordion-down": { - from: { height: 0 }, + from: { height: "0" }, to: { height: "var(--radix-accordion-content-height)" }, }, "accordion-up": { from: { height: "var(--radix-accordion-content-height)" }, - to: { height: 0 }, + to: { height: "0" }, }, }, animation: { @@ -73,4 +75,6 @@ module.exports = { }, }, plugins: [require("tailwindcss-animate")], -} \ No newline at end of file +} satisfies Config + +export default config \ No newline at end of file