├── .eslintrc.json ├── src ├── lib │ ├── seo │ │ ├── index.ts │ │ └── site.ts │ ├── get-icon.tsx │ ├── placeholders.tsx │ ├── fonts.ts │ └── motion │ │ ├── zoom-in-out.ts │ │ ├── zoom-out-in.ts │ │ ├── fade-in-out.ts │ │ ├── height-collapse.ts │ │ ├── fade-in-left.ts │ │ ├── fade-in-right.ts │ │ └── zoom-in-bottom.ts ├── app │ ├── favicon.ico │ ├── (public) │ │ ├── help │ │ │ └── page.tsx │ │ ├── contact │ │ │ └── page.tsx │ │ ├── faq │ │ │ └── page.tsx │ │ ├── shops │ │ │ └── page.tsx │ │ ├── site-map │ │ │ └── page.tsx │ │ ├── search │ │ │ └── page.tsx │ │ ├── about-us │ │ │ └── page.tsx │ │ ├── newsletter │ │ │ └── page.tsx │ │ ├── privacy-policy │ │ │ └── page.tsx │ │ ├── wishlist │ │ │ └── page.tsx │ │ ├── contact-us │ │ │ └── page.tsx │ │ ├── special-offers │ │ │ └── page.tsx │ │ ├── products │ │ │ ├── layout.tsx │ │ │ └── [productSlug] │ │ │ │ └── page.tsx │ │ ├── order-history │ │ │ └── page.tsx │ │ ├── cart │ │ │ └── page.tsx │ │ ├── checkout │ │ │ └── page.tsx │ │ ├── layout.tsx │ │ ├── screens │ │ │ └── ourProductsSection.tsx │ │ └── page.tsx │ ├── (dashboard) │ │ └── account │ │ │ ├── cards │ │ │ └── page.tsx │ │ │ ├── chats │ │ │ └── page.tsx │ │ │ ├── orders │ │ │ └── page.tsx │ │ │ ├── wishlists │ │ │ └── page.tsx │ │ │ ├── addresses │ │ │ ├── [id] │ │ │ │ ├── layout.tsx │ │ │ │ ├── AddressEdit.tsx │ │ │ │ ├── page.tsx │ │ │ │ └── loading.tsx │ │ │ ├── layout.tsx │ │ │ ├── page.tsx │ │ │ ├── new │ │ │ │ └── page.tsx │ │ │ └── components │ │ │ │ └── AddressCard.tsx │ │ │ ├── dashboard │ │ │ ├── layout.tsx │ │ │ ├── page.tsx │ │ │ ├── components │ │ │ │ └── AccountWallets.tsx │ │ │ └── loading.tsx │ │ │ ├── change-password │ │ │ ├── layout.tsx │ │ │ ├── loading.tsx │ │ │ └── page.tsx │ │ │ └── edit │ │ │ ├── components │ │ │ └── ProfileEditComponent.tsx │ │ │ ├── page.tsx │ │ │ └── loading.tsx │ ├── (auth) │ │ ├── signout │ │ │ ├── loading.tsx │ │ │ └── page.tsx │ │ ├── signup │ │ │ ├── activation │ │ │ │ └── [token] │ │ │ │ │ └── page.tsx │ │ │ └── page.tsx │ │ └── layout.tsx │ ├── not-found.tsx │ └── layout.tsx ├── modules │ ├── products │ │ ├── quickView │ │ │ ├── index.ts │ │ │ └── quick-view-short-details.tsx │ │ ├── productQuestion │ │ │ └── postQuestionModal.tsx │ │ └── variation-price.tsx │ ├── checkout │ │ ├── CheckoutLeftSite.tsx │ │ └── address-header.tsx │ ├── review │ │ ├── review-card.tsx │ │ └── review-form-view.tsx │ ├── categories │ │ ├── category-carousel.tsx │ │ └── CategoryCard.tsx │ └── questions │ │ └── questionCard.tsx ├── components │ ├── ui │ │ ├── phone-input.tsx │ │ ├── aspect-ratio.tsx │ │ ├── error-message.tsx │ │ ├── pagination.tsx │ │ ├── skeleton.tsx │ │ ├── toaster.tsx │ │ ├── rate-input.tsx │ │ ├── active-link.tsx │ │ ├── label.tsx │ │ ├── textarea.tsx │ │ ├── separator.tsx │ │ ├── input.tsx │ │ ├── scrollbar.tsx │ │ ├── animated-characters.tsx │ │ ├── drawer-wrapper.tsx │ │ ├── checkbox.tsx │ │ ├── rating-progress-bar.tsx │ │ ├── switch.tsx │ │ ├── hover-card.tsx │ │ ├── star-icon.tsx │ │ ├── rating-badge.tsx │ │ ├── popover.tsx │ │ ├── password-input.tsx │ │ ├── avatar.tsx │ │ ├── scroll-area.tsx │ │ ├── progress.tsx │ │ ├── button.tsx │ │ ├── tabs.tsx │ │ ├── breadcrumb.tsx │ │ ├── card.tsx │ │ ├── search │ │ │ └── search.tsx │ │ └── accordion.tsx │ ├── common │ │ └── shared │ │ │ ├── analytics.tsx │ │ │ ├── gradient-logo.tsx │ │ │ ├── ClientOnly.tsx │ │ │ ├── tailwind-indicator.tsx │ │ │ ├── checkbox.tsx │ │ │ ├── ProgressBar.tsx │ │ │ ├── oauth-signin.tsx │ │ │ └── page-header.tsx │ ├── icons │ │ ├── caret-down.tsx │ │ └── groups │ │ │ ├── index.tsx │ │ │ ├── handbag-icon.tsx │ │ │ ├── furniture-icon.tsx │ │ │ └── dress-icon.tsx │ ├── providers │ │ ├── theme-provider.tsx │ │ ├── google.provider.tsx │ │ └── query.provider.tsx │ ├── skelaton │ │ ├── product-feed-loader.tsx │ │ ├── product-card-loader.tsx │ │ └── SkelatonLoader.tsx │ ├── cart │ │ ├── empty-cart.tsx │ │ ├── cart-count-button.tsx │ │ └── cart-item.tsx │ ├── layout │ │ ├── TopBar.tsx │ │ ├── site-header.tsx │ │ ├── manu │ │ │ └── static-menu.tsx │ │ ├── mobile-menu │ │ │ └── mobile-main-menu.tsx │ │ ├── main-nav.tsx │ │ ├── HeaderBottom.tsx │ │ └── sidebar-mobile.tsx │ ├── shop │ │ ├── filtered-item.tsx │ │ ├── top-bar.tsx │ │ ├── filter-sidebar.tsx │ │ └── category-filter.tsx │ ├── shells │ │ ├── shell.tsx │ │ └── dialog-shell.tsx │ ├── forms │ │ ├── verify-email-form.tsx │ │ └── signin-form.tsx │ └── auth │ │ └── logout-buttons.tsx ├── constants │ └── index.ts ├── hooks │ ├── use-is-homepage.ts │ ├── use-mounted.ts │ ├── api │ │ ├── product │ │ │ ├── useGetProduct.ts │ │ │ └── useGetProducts.ts │ │ ├── question │ │ │ ├── question.ts │ │ │ └── createQuestion.ts │ │ ├── category │ │ │ ├── useGetCategoriesQuery.ts │ │ │ ├── useGetCategories.ts │ │ │ └── useCategories.ts │ │ ├── user │ │ │ ├── useMe.ts │ │ │ └── useUser.tsx │ │ ├── addresses │ │ │ └── useGetAddresses.ts │ │ └── type │ │ │ └── useGetTypes.ts │ ├── use-debounce.ts │ ├── useCurrentUser.ts │ ├── use-token.ts │ ├── use-window-size.ts │ ├── useSearchHook.ts │ ├── use-price.tsx │ └── use-query-params.ts ├── utils │ ├── get-variations.ts │ ├── queryKey │ │ └── query.ts │ ├── authorization-atom.ts │ ├── generate-cart-item-name.ts │ ├── helper.ts │ ├── util.ts │ ├── api │ │ └── api-endpoints.ts │ ├── get-color-class.ts │ └── generate-cart-item.ts ├── configs │ ├── settings.ts │ ├── routes.ts │ └── dashboard.ts ├── services │ ├── group.service.ts │ ├── upload.service.ts │ ├── address.service.ts │ ├── review.service.ts │ ├── user.service.ts │ └── category.service.ts ├── types │ ├── utils.ts │ └── custom.types.ts ├── validations │ └── product.ts ├── placeholders │ ├── coupon.svg │ ├── product.svg │ └── avatar.svg ├── middleware.ts ├── data │ └── promotional-slider.ts └── styles │ └── globals.css ├── public ├── login.jpg ├── madrid_03.jpg ├── fruite-Banner.jpg ├── vercel.svg └── logo.svg ├── postcss.config.js ├── .env.example ├── next.config.js ├── components.json ├── .gitignore └── tsconfig.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/seo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './keywords' 2 | export * from './metadata' -------------------------------------------------------------------------------- /public/login.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SMTanimur/Jazila-bazar/HEAD/public/login.jpg -------------------------------------------------------------------------------- /public/madrid_03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SMTanimur/Jazila-bazar/HEAD/public/madrid_03.jpg -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SMTanimur/Jazila-bazar/HEAD/src/app/favicon.ico -------------------------------------------------------------------------------- /public/fruite-Banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SMTanimur/Jazila-bazar/HEAD/public/fruite-Banner.jpg -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/modules/products/quickView/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./quick-view-product"; 2 | export * from "./quick-view-short-details"; 3 | -------------------------------------------------------------------------------- /src/app/(public)/help/page.tsx: -------------------------------------------------------------------------------- 1 | const HelpPage = () => { 2 | return
HelpPage
; 3 | }; 4 | 5 | export default HelpPage; 6 | -------------------------------------------------------------------------------- /src/components/ui/phone-input.tsx: -------------------------------------------------------------------------------- 1 | import 'react-phone-input-2/lib/bootstrap.css'; 2 | export { default } from 'react-phone-input-2'; 3 | -------------------------------------------------------------------------------- /src/constants/index.ts: -------------------------------------------------------------------------------- 1 | import { ClientSession } from "@/configs/settings"; 2 | 3 | export const AUTH_TOKEN_KEY = ClientSession as string -------------------------------------------------------------------------------- /src/app/(public)/contact/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const page = () => { 4 | return ( 5 |
page
6 | ) 7 | } 8 | 9 | export default page -------------------------------------------------------------------------------- /src/app/(public)/faq/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const FaqPage = () => { 4 | return ( 5 |
FaqPage
6 | ) 7 | } 8 | 9 | export default FaqPage -------------------------------------------------------------------------------- /src/app/(public)/shops/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const ShopsPage = () => { 4 | return ( 5 |
ShopsPage
6 | ) 7 | } 8 | 9 | export default ShopsPage -------------------------------------------------------------------------------- /src/app/(public)/site-map/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const SiteMap = () => { 4 | return ( 5 |
SiteMap
6 | ) 7 | } 8 | 9 | export default SiteMap -------------------------------------------------------------------------------- /src/app/(public)/search/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const SearchPage = () => { 4 | return ( 5 |
SearchPage
6 | ) 7 | } 8 | 9 | export default SearchPage -------------------------------------------------------------------------------- /src/app/(dashboard)/account/cards/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const MyCard = () => { 4 | return ( 5 |
MyCard
6 | ) 7 | } 8 | 9 | export default MyCard -------------------------------------------------------------------------------- /src/app/(public)/about-us/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const AboutUsPage = () => { 4 | return ( 5 |
AboutUsPage
6 | ) 7 | } 8 | 9 | export default AboutUsPage -------------------------------------------------------------------------------- /src/app/(public)/newsletter/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const NewsLetter = () => { 4 | return ( 5 |
NewsLetter
6 | ) 7 | } 8 | 9 | export default NewsLetter -------------------------------------------------------------------------------- /src/app/(public)/privacy-policy/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const PrivacyPage = () => { 4 | return ( 5 |
PrivacyPage
6 | ) 7 | } 8 | 9 | export default PrivacyPage -------------------------------------------------------------------------------- /src/app/(public)/wishlist/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const WishlistPage = () => { 4 | return ( 5 |
WishlistPage
6 | ) 7 | } 8 | 9 | export default WishlistPage -------------------------------------------------------------------------------- /src/hooks/use-is-homepage.ts: -------------------------------------------------------------------------------- 1 | import { usePathname } from "next/navigation"; 2 | 3 | export function useIsHomePage() { 4 | const path = usePathname(); 5 | return path === "/"; 6 | } 7 | -------------------------------------------------------------------------------- /src/app/(dashboard)/account/chats/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const ChatsPage = () => { 4 | return ( 5 |
ChatsPage
6 | ) 7 | } 8 | 9 | export default ChatsPage -------------------------------------------------------------------------------- /src/app/(dashboard)/account/orders/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const MyOrders = () => { 4 | return ( 5 |
MyOrders
6 | ) 7 | } 8 | 9 | export default MyOrders -------------------------------------------------------------------------------- /src/app/(public)/contact-us/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const ContactUsPage = () => { 4 | return ( 5 |
ContactUsPage
6 | ) 7 | } 8 | 9 | export default ContactUsPage -------------------------------------------------------------------------------- /src/app/(public)/special-offers/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const SpecialOffer = () => { 4 | return ( 5 |
SpecialOffer
6 | ) 7 | } 8 | 9 | export default SpecialOffer -------------------------------------------------------------------------------- /src/app/(dashboard)/account/wishlists/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const WishLists = () => { 4 | return ( 5 |
WishLists
6 | ) 7 | } 8 | 9 | export default WishLists -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_APP_URL=http://localhost:4200 2 | NEXT_PUBLIC_API_URL=http://localhost:3333 3 | NEXT_PUBLIC_OAUTH_GOOGLE_ID= 4 | NEXT_PUBLIC_CLIENT_SESSION= 5 | NEXT_PUBLIC_ADMIN_URL=http://localhost:4000 -------------------------------------------------------------------------------- /src/components/ui/aspect-ratio.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio" 4 | 5 | const AspectRatio = AspectRatioPrimitive.Root 6 | 7 | export { AspectRatio } 8 | -------------------------------------------------------------------------------- /src/utils/get-variations.ts: -------------------------------------------------------------------------------- 1 | import groupBy from 'lodash/groupBy'; 2 | 3 | export function getVariations(variations: object | undefined) { 4 | if (!variations) return {}; 5 | return groupBy(variations, 'attribute.slug'); 6 | } 7 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | images: { 4 | domains: ['res.cloudinary.com', 'lh3.googleusercontent.com','www.leafrootfruit.com.au'], 5 | }, 6 | }; 7 | 8 | module.exports = nextConfig; 9 | -------------------------------------------------------------------------------- /src/app/(dashboard)/account/addresses/[id]/layout.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | export default function RootLayout({ 4 | children, 5 | }: { 6 | children: React.ReactNode; 7 | }) { 8 | // offset navbar height 9 | return
{children}
; 10 | } -------------------------------------------------------------------------------- /src/components/common/shared/analytics.tsx: -------------------------------------------------------------------------------- 1 | import Loglib from "@loglib/tracker/react" 2 | 3 | export function Analytics() { 4 | return ( 5 | 10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /src/components/common/shared/gradient-logo.tsx: -------------------------------------------------------------------------------- 1 | export default function GradientLogo() { 2 | return ( 3 |

4 | Jazila Bazaar 5 |

6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/get-icon.tsx: -------------------------------------------------------------------------------- 1 | type Props = { 2 | iconList: any; 3 | iconName: string; 4 | [key: string]: unknown; 5 | }; 6 | export const getIcon = ({ iconList, iconName, ...rest }: Props) => { 7 | const TagName = iconList[iconName]; 8 | return !!TagName ? : null; 9 | }; 10 | -------------------------------------------------------------------------------- /src/utils/queryKey/query.ts: -------------------------------------------------------------------------------- 1 | export const QueryKeys ={ 2 | ME: 'me', 3 | USERS: 'users', 4 | PRODUCTS: 'products', 5 | POPULAR_PRODUCTS: 'popular-products', 6 | COUPONS: 'coupons', 7 | ACTIVATE: 'activate', 8 | VERIFY_COUPONS: 'coupons/verify', 9 | CUSTOMERS: 'customers', 10 | 11 | 12 | } -------------------------------------------------------------------------------- /src/hooks/use-mounted.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | export function useMounted() { 4 | const [mounted, setMounted] = React.useState(false) 5 | 6 | React.useEffect(() => { 7 | setMounted(true) 8 | 9 | return () => setMounted(false) 10 | }, []) 11 | 12 | return mounted 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/placeholders.tsx: -------------------------------------------------------------------------------- 1 | export { default as avatarPlaceholder } from "@/placeholders/avatar.svg"; 2 | export { default as couponPlaceholder } from "@/placeholders/coupon.svg"; 3 | export { default as logoPlaceholder } from "@/placeholders/logo.svg"; 4 | export { default as productPlaceholder } from "@/placeholders/product.svg"; 5 | -------------------------------------------------------------------------------- /src/lib/fonts.ts: -------------------------------------------------------------------------------- 1 | import { JetBrains_Mono as FontMono, Inter as FontSans } from "next/font/google" 2 | 3 | export const fontSans = FontSans({ 4 | subsets: ["latin"], 5 | variable: "--font-sans", 6 | }) 7 | 8 | export const fontMono = FontMono({ 9 | subsets: ["latin"], 10 | variable: "--font-mono", 11 | }) 12 | -------------------------------------------------------------------------------- /src/app/(dashboard)/account/addresses/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | 3 | 4 | export default function RootLayout({ 5 | children, 6 | }: { 7 | children: React.ReactNode; 8 | }) { 9 | // offset navbar height 10 | return ( 11 |
12 | 13 | {children} 14 |
15 | ); 16 | } -------------------------------------------------------------------------------- /src/components/ui/error-message.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | interface ErrorProps { 3 | message?: string; 4 | } 5 | 6 | export const Error: React.FC = ({ message }) => { 7 | return ( 8 |

9 | {message!} 10 |

11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /src/components/icons/caret-down.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const CaretDown = ({ ...props }) => { 3 | return ( 4 | 5 | 10 | 11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /src/components/ui/pagination.tsx: -------------------------------------------------------------------------------- 1 | import RCPagination, { PaginationProps } from 'rc-pagination'; 2 | import React from 'react'; 3 | import 'rc-pagination/assets/index.css'; 4 | 5 | const Pagination: React.FC = (props) => { 6 | return ; 7 | }; 8 | 9 | export default Pagination; 10 | -------------------------------------------------------------------------------- /src/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils" 2 | 3 | function Skeleton({ 4 | className, 5 | ...props 6 | }: React.HTMLAttributes) { 7 | return ( 8 |
12 | ) 13 | } 14 | 15 | export { Skeleton } 16 | -------------------------------------------------------------------------------- /src/utils/authorization-atom.ts: -------------------------------------------------------------------------------- 1 | 2 | import { AUTH_TOKEN_KEY } from '@/constants'; 3 | import { atom } from 'jotai'; 4 | import Cookies from 'js-cookie'; 5 | 6 | export function checkIsLoggedIn() { 7 | const token = Cookies.get(AUTH_TOKEN_KEY); 8 | if (!token) return false; 9 | return true; 10 | } 11 | export const authorizationAtom = atom(checkIsLoggedIn()); 12 | 13 | -------------------------------------------------------------------------------- /src/utils/generate-cart-item-name.ts: -------------------------------------------------------------------------------- 1 | import isEmpty from 'lodash/isEmpty'; 2 | import orderBy from 'lodash/orderBy'; 3 | 4 | export function generateCartItemName(name: string, attributes: object) { 5 | if (!isEmpty(attributes)) { 6 | const sortedAttributes = orderBy(attributes); 7 | return `${name} - ${sortedAttributes.join(', ')}`; 8 | } 9 | return name; 10 | } 11 | -------------------------------------------------------------------------------- /src/configs/settings.ts: -------------------------------------------------------------------------------- 1 | export const BaseClientUrl = process.env.NEXT_PUBLIC_APP_URL; 2 | export const BaseApiUrl = process.env.NEXT_PUBLIC_API_URL; 3 | export const NODE_ENV = process.env.NODE_ENV; 4 | export const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID 5 | export const GoogleApiRedirect = BaseApiUrl + '/v1/auth/google/login'; 6 | export const ClientSession = process.env.NEXT_PUBLIC_CLIENT_SESSION; 7 | -------------------------------------------------------------------------------- /src/app/(public)/products/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | 3 | export const metadata: Metadata = { 4 | title: 'Products' 5 | 6 | }; 7 | export default function RootLayout({ 8 | children, 9 | }: { 10 | children: React.ReactNode; 11 | }) { 12 | // offset navbar height 13 | return ( 14 |
15 | 16 | {children} 17 |
18 | ); 19 | } -------------------------------------------------------------------------------- /src/lib/motion/zoom-in-out.ts: -------------------------------------------------------------------------------- 1 | export function zoomInOut (duration:number = 0.2) { 2 | return { 3 | from: { 4 | scale: 0.9, 5 | transition: { 6 | type: 'easeOut', 7 | duration: duration, 8 | } 9 | }, 10 | to: { 11 | scale: 1, 12 | transition: { 13 | type: 'easeOut', 14 | duration: duration, 15 | } 16 | }, 17 | } 18 | } -------------------------------------------------------------------------------- /src/lib/motion/zoom-out-in.ts: -------------------------------------------------------------------------------- 1 | export function zoomOutIn (duration:number = 0.2) { 2 | return { 3 | from: { 4 | scale: 1.1, 5 | transition: { 6 | type: 'easeOut', 7 | duration: duration, 8 | } 9 | }, 10 | to: { 11 | scale: 1, 12 | transition: { 13 | type: 'easeOut', 14 | duration: duration, 15 | } 16 | }, 17 | } 18 | } -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "src/app/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true 11 | }, 12 | "aliases": { 13 | "components": "@/components", 14 | "utils": "@/lib/utils" 15 | } 16 | } -------------------------------------------------------------------------------- /src/app/(public)/order-history/page.tsx: -------------------------------------------------------------------------------- 1 | import Breadcrumb from '@/components/ui/breadcrumb' 2 | import React from 'react' 3 | 4 | const OrderHistoryPage = () => { 5 | return ( 6 |
7 |
8 | 9 |
10 |
11 | ) 12 | } 13 | 14 | export default OrderHistoryPage -------------------------------------------------------------------------------- /src/components/providers/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { ThemeProvider as NextThemesProvider } from "next-themes"; 4 | import { type ThemeProviderProps } from "next-themes/dist/types"; 5 | 6 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 7 | return ( 8 | 9 | {children} 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/motion/fade-in-out.ts: -------------------------------------------------------------------------------- 1 | export function fadeInOut (duration:number = 0.2) { 2 | return { 3 | from: { 4 | opacity: 0, 5 | transition: { 6 | type: 'easeInOut', 7 | duration: duration, 8 | } 9 | }, 10 | to: { 11 | opacity: 1, 12 | transition: { 13 | type: 'easeInOut', 14 | duration: duration, 15 | } 16 | }, 17 | } 18 | } -------------------------------------------------------------------------------- /src/lib/motion/height-collapse.ts: -------------------------------------------------------------------------------- 1 | export function heightCollapse () { 2 | return { 3 | from: { 4 | opacity: 0, 5 | height: 0, 6 | transition: { 7 | ease: [0.04, 0.62, 0.23, 0.98] 8 | } 9 | }, 10 | to: { 11 | opacity: 1, 12 | height: 'auto', 13 | transition: { 14 | ease: [0.04, 0.62, 0.23, 0.98] 15 | } 16 | }, 17 | } 18 | } -------------------------------------------------------------------------------- /src/app/(dashboard)/account/dashboard/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | 3 | export const metadata: Metadata = { 4 | title: 'Account Information', 5 | description: 'Manage your account settings', 6 | }; 7 | export default function RootLayout({ 8 | children, 9 | }: { 10 | children: React.ReactNode; 11 | }) { 12 | // offset navbar height 13 | return
{children}
; 14 | } -------------------------------------------------------------------------------- /src/components/providers/google.provider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import {GoogleOAuthProvider} from "@react-oauth/google"; 4 | 5 | const GoogleProvider = ({children}: React.PropsWithChildren) => { 6 | return ( 7 | 9 | {children} 10 | 11 | ); 12 | }; 13 | 14 | export default GoogleProvider; -------------------------------------------------------------------------------- /src/lib/motion/fade-in-left.ts: -------------------------------------------------------------------------------- 1 | export function fadeInLeft(duration: number = 0.3) { 2 | return { 3 | from: { 4 | left: "-100%", 5 | transition: { 6 | type: "easeInOut", 7 | duration: duration, 8 | }, 9 | }, 10 | to: { 11 | left: 0, 12 | transition: { 13 | type: "easeInOut", 14 | duration: duration, 15 | }, 16 | }, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/motion/fade-in-right.ts: -------------------------------------------------------------------------------- 1 | export function fadeInRight(duration: number = 0.3) { 2 | return { 3 | from: { 4 | right: '-100%', 5 | transition: { 6 | type: 'easeInOut', 7 | duration: duration, 8 | }, 9 | }, 10 | to: { 11 | right: 0, 12 | transition: { 13 | type: 'easeInOut', 14 | duration: duration, 15 | }, 16 | }, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/seo/site.ts: -------------------------------------------------------------------------------- 1 | export const siteConfig = { 2 | name: "UmmahLink", 3 | url: "https://ummahlink.com", 4 | ogImage: "https://ui.shadcn.com/og.jpg", 5 | description: 6 | "UmmahLink is a social media platform for Muslims to connect with each other.", 7 | links: { 8 | twitter: "https://twitter.com/SMTanimur", 9 | github: "https://github.com/SMTanimur", 10 | }, 11 | } 12 | 13 | export type SiteConfig = typeof siteConfig 14 | -------------------------------------------------------------------------------- /src/hooks/api/product/useGetProduct.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { useQuery } from "@tanstack/react-query" 4 | 5 | import { IProduct } from "@/types" 6 | import { productClient } from "@/services/product.service" 7 | 8 | export const useProductQuery = (slug: string) => { 9 | return useQuery( 10 | ["products", slug], 11 | () => productClient.getProduct(slug), 12 | { 13 | keepPreviousData: true, 14 | } 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /src/hooks/use-debounce.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | export function useDebounce(value: T, delay?: number): T { 4 | const [debouncedValue, setDebouncedValue] = React.useState(value) 5 | 6 | React.useEffect(() => { 7 | const timer = setTimeout(() => setDebouncedValue(value), delay ?? 500) 8 | 9 | return () => { 10 | clearTimeout(timer) 11 | } 12 | }, [value, delay]) 13 | 14 | return debouncedValue 15 | } 16 | -------------------------------------------------------------------------------- /src/app/(dashboard)/account/change-password/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | 3 | export const metadata: Metadata = { 4 | title: 'Change Password ', 5 | description: 'Manage your account settings', 6 | }; 7 | export default function RootLayout({ 8 | children, 9 | }: { 10 | children: React.ReactNode; 11 | }) { 12 | // offset navbar height 13 | return ( 14 |
15 | 16 | {children} 17 |
18 | ); 19 | } -------------------------------------------------------------------------------- /src/components/ui/toaster.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { Toaster as RadToaster } from "sonner" 4 | 5 | export function Toaster() { 6 | return ( 7 | 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /src/app/(public)/products/[productSlug]/page.tsx: -------------------------------------------------------------------------------- 1 | 2 | import { Metadata } from "next"; 3 | import SingleProductPage from "../screens/SingleProductPage"; 4 | type Props = { 5 | params: { 6 | productSlug: string; 7 | }; 8 | }; 9 | export const metadata: Metadata = { 10 | title: 'Product' 11 | 12 | }; 13 | 14 | const Product = ({ params: { productSlug } }: Props) => { 15 | 16 | return 17 | }; 18 | 19 | export default Product; 20 | -------------------------------------------------------------------------------- /src/components/icons/groups/index.tsx: -------------------------------------------------------------------------------- 1 | export { FruitsVegetable } from './fruits-vegetable'; 2 | export { FacialCare } from './facial-care'; 3 | export { Handbag } from './handbag-icon'; 4 | export { DressIcon } from './dress-icon'; 5 | export { FurnitureIcon } from './furniture-icon'; 6 | export { BookIcon } from './book-icon'; 7 | export { MedicineIcon } from './medicine-icon'; 8 | export { Restaurant } from './restaurant-icon'; 9 | export { Bakery } from './bakery-icon'; 10 | -------------------------------------------------------------------------------- /src/hooks/useCurrentUser.ts: -------------------------------------------------------------------------------- 1 | import { userClient } from '@/services/user.service'; 2 | import { useQuery } from '@tanstack/react-query'; 3 | import { useAtom } from 'jotai'; 4 | 5 | 6 | export function useCurrentUser() { 7 | 8 | const { data, isLoading, error } = useQuery( 9 | ['me'], 10 | userClient.me, 11 | { 12 | retry: false, 13 | } 14 | ); 15 | //TODO: do some improvement here 16 | return { currentUser: data, isLoading, error}; 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/motion/zoom-in-bottom.ts: -------------------------------------------------------------------------------- 1 | export function zoomInBottom (duration:number = 0.2) { 2 | return { 3 | from: { 4 | y: 8, 5 | opacity: 0, 6 | scale: 0.99, 7 | transition: { 8 | type: 'easeOut', 9 | duration: duration, 10 | } 11 | }, 12 | to: { 13 | y: 0, 14 | opacity: 1, 15 | scale: 1, 16 | transition: { 17 | type: 'easeOut', 18 | duration: duration, 19 | } 20 | }, 21 | } 22 | } -------------------------------------------------------------------------------- /src/components/skelaton/product-feed-loader.tsx: -------------------------------------------------------------------------------- 1 | import ProductCardLoader from "./product-card-loader"; 2 | 3 | 4 | interface Props { 5 | limit?: number; 6 | uniqueKey?: string; 7 | } 8 | 9 | const ProductFeedLoader = ({ limit = 5, uniqueKey = "product" }: Props) => { 10 | return ( 11 | <> 12 | {Array.from({ length: limit }).map((_, idx) => ( 13 | 14 | ))} 15 | 16 | ); 17 | }; 18 | 19 | export default ProductFeedLoader; 20 | -------------------------------------------------------------------------------- /src/utils/helper.ts: -------------------------------------------------------------------------------- 1 | export const getErrorMessage = (error: any) => { 2 | let errorMessage; 3 | 4 | if (error) { 5 | if ("status" in error) { 6 | const errMsg = 7 | "error" in error ? error.error : JSON.stringify(error.data); 8 | 9 | errorMessage = errMsg; 10 | } else { 11 | errorMessage = error.message; 12 | } 13 | } else { 14 | errorMessage = "Unable to fetch the data. Please try again later."; 15 | } 16 | 17 | return errorMessage; 18 | }; -------------------------------------------------------------------------------- /src/utils/util.ts: -------------------------------------------------------------------------------- 1 | 2 | type ICalculateDiscountPercentage = { 3 | originalPrice: number; 4 | salePrice: number; 5 | }; 6 | 7 | export const calculateDiscountPercentage = ({ 8 | originalPrice, 9 | salePrice, 10 | }: ICalculateDiscountPercentage) => { 11 | if (originalPrice > 0 && salePrice > 0) { 12 | const discount = ((originalPrice - salePrice) / originalPrice) * 100; 13 | return discount.toFixed(2); // Limiting to two decimal places 14 | } 15 | 16 | return salePrice 17 | }; 18 | 19 | -------------------------------------------------------------------------------- /src/components/common/shared/ClientOnly.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React, { useEffect, useState } from "react"; 4 | 5 | interface ClientOnlyProps { 6 | children: React.ReactNode; 7 | } 8 | 9 | const ClientOnly: React.FC = ({ children }) => { 10 | const [hasMounted, setHasMounted] = useState(false); 11 | 12 | useEffect(() => { 13 | setHasMounted(true); 14 | }, [setHasMounted]); 15 | 16 | if (!hasMounted) return null; 17 | 18 | return <>{children}; 19 | }; 20 | 21 | export default ClientOnly; 22 | -------------------------------------------------------------------------------- /src/app/(public)/cart/page.tsx: -------------------------------------------------------------------------------- 1 | 2 | import Breadcrumb from '@/components/ui/breadcrumb' 3 | import React from 'react' 4 | import CartItemsDetails from './screens/cart-items-details' 5 | import ClientOnly from '@/components/common/shared/ClientOnly' 6 | 7 | const CartPage = async() => { 8 | 9 | return ( 10 |
11 |
12 | 13 |
14 | 15 | 16 | 17 |
18 | ) 19 | } 20 | 21 | export default CartPage -------------------------------------------------------------------------------- /src/hooks/api/question/question.ts: -------------------------------------------------------------------------------- 1 | import { productClient } from "@/services/product.service"; 2 | import { IQuestion, PaginatorInfo } from "@/types"; 3 | import { QuestionsQueryOptionsType } from "@/types/custom.types"; 4 | import { useQuery } from "@tanstack/react-query"; 5 | 6 | 7 | export const useQuestionsQuery = ( 8 | options: Partial 9 | ) => { 10 | return useQuery, Error>( 11 | ["questions", options], 12 | productClient.getQuestions, 13 | { 14 | keepPreviousData: true, 15 | } 16 | ); 17 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn 8 | 9 | .vscode 10 | 11 | # testing 12 | /coverage 13 | 14 | # next.js 15 | /.next/ 16 | /out/ 17 | 18 | # production 19 | /build 20 | 21 | # misc 22 | .DS_Store 23 | *.pem 24 | 25 | # debug 26 | npm-debug.log* 27 | yarn-debug.log* 28 | yarn-error.log* 29 | 30 | # local env files 31 | .env*.local 32 | .env 33 | 34 | # vercel 35 | .vercel 36 | 37 | # typescript 38 | *.tsbuildinfo 39 | next-env.d.ts 40 | -------------------------------------------------------------------------------- /src/hooks/use-token.ts: -------------------------------------------------------------------------------- 1 | import { AUTH_TOKEN_KEY } from '@/constants'; 2 | import Cookies from 'js-cookie'; 3 | 4 | export function useToken() { 5 | return { 6 | setToken(token: string) { 7 | Cookies.set(AUTH_TOKEN_KEY, token, { expires: 1 }); 8 | }, 9 | getToken() { 10 | return Cookies.get(AUTH_TOKEN_KEY); 11 | }, 12 | removeToken() { 13 | Cookies.remove(AUTH_TOKEN_KEY); 14 | }, 15 | hasToken() { 16 | const token = Cookies.get(AUTH_TOKEN_KEY); 17 | if (!token) return false; 18 | return true; 19 | }, 20 | 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/services/group.service.ts: -------------------------------------------------------------------------------- 1 | import { IType } from "@/types"; 2 | import { QueryParamsType, TypesQueryOptionsType } from "@/types/custom.types"; 3 | 4 | import { PaginatorInfo } from "@/types/utils"; 5 | import { API_ENDPOINTS } from "@/utils/api/api-endpoints"; 6 | import { HttpClient } from "@/utils/api/http"; 7 | 8 | export const groupClient = { 9 | 10 | getAllGroups: async () => { 11 | return HttpClient.get(`${API_ENDPOINTS.TYPES}/all`); 12 | }, 13 | 14 | 15 | getGroup: async (slug: string) => { 16 | return HttpClient.get(`${API_ENDPOINTS.TYPES}/${slug}`); 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/cart/empty-cart.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | function EmptyCart() { 4 | 5 | return ( 6 |
7 |
8 | {/* {t('text-empty-cart')} */} 15 |
16 |
17 | Empty Cart 18 |
19 | 20 |
21 | ); 22 | } 23 | 24 | export default EmptyCart; 25 | -------------------------------------------------------------------------------- /src/components/ui/rate-input.tsx: -------------------------------------------------------------------------------- 1 | import Rate from 'rc-rate'; 2 | import { RateProps } from 'rc-rate/es/Rate'; 3 | import 'rc-rate/assets/index.css'; 4 | import { Controller } from 'react-hook-form'; 5 | 6 | interface RateInputProps extends RateProps { 7 | control: any; 8 | name: string; 9 | } 10 | 11 | const RateInput = ({ control, name, ...rateProps }: RateInputProps) => { 12 | return ( 13 | ( 17 | 18 | )} 19 | /> 20 | ); 21 | }; 22 | 23 | export default RateInput; 24 | -------------------------------------------------------------------------------- /src/components/layout/TopBar.tsx: -------------------------------------------------------------------------------- 1 | import { PhoneIcon } from 'lucide-react' 2 | import React from 'react' 3 | 4 | const TopBar = () => { 5 | return ( 6 |
7 |
8 |
9 | 10 | We are available 24/7, Need help? 11 | +8801648138404 12 |
13 |
14 | 15 |
16 |
17 |
18 | ) 19 | } 20 | 21 | export default TopBar -------------------------------------------------------------------------------- /src/hooks/api/category/useGetCategoriesQuery.ts: -------------------------------------------------------------------------------- 1 | import { categoryClient } from "@/services/category.service"; 2 | import { ICategory, IShop, IType } from "@/types"; 3 | import { CategoriesQueryOptionsType } from "@/types/custom.types"; 4 | import { PaginatorInfo } from "@/types/utils"; 5 | import { API_ENDPOINTS } from "@/utils/api/api-endpoints"; 6 | import { useQuery } from "@tanstack/react-query"; 7 | 8 | export const useGetCategoriesQuery = (options: CategoriesQueryOptionsType) => { 9 | return useQuery, Error>( 10 | [API_ENDPOINTS.CATEGORIES, options], 11 | categoryClient.getCategories, 12 | { 13 | keepPreviousData: true, 14 | } 15 | ); 16 | }; -------------------------------------------------------------------------------- /src/components/skelaton/product-card-loader.tsx: -------------------------------------------------------------------------------- 1 | import ContentLoader from "react-content-loader"; 2 | 3 | const ProductCardLoader = (props: any) => ( 4 | 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | 21 | export default ProductCardLoader; 22 | -------------------------------------------------------------------------------- /src/components/ui/active-link.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import React, { Children } from 'react'; 3 | 4 | const ActiveLink = ({ 5 | children, 6 | activeClassName, 7 | href, 8 | ...props 9 | }: any) => { 10 | const child = Children.only(children); 11 | const childClassName = child.props.className || ''; 12 | 13 | const className = 14 | href 15 | ? `${childClassName} ${activeClassName}`.trim() 16 | : childClassName; 17 | 18 | return ( 19 | 20 | {React.cloneElement(child, { 21 | className: className || null, 22 | })} 23 | 24 | ); 25 | }; 26 | 27 | export default ActiveLink; 28 | -------------------------------------------------------------------------------- /src/types/utils.ts: -------------------------------------------------------------------------------- 1 | import { TypeOf } from 'zod'; 2 | 3 | 4 | export interface PaginatorInfo { 5 | docs: T[]; 6 | 7 | totalDocs: number; 8 | 9 | limit: number; 10 | 11 | // * Page info 12 | 13 | page: number; 14 | 15 | totalPages: number; 16 | 17 | hasNextPage: boolean; 18 | 19 | hasPrevPage: boolean; 20 | 21 | nextPage: number; 22 | 23 | prevPage: number; 24 | 25 | pagingCounter: number; 26 | } 27 | 28 | export type IColor = 29 | | "rose" 30 | | "green" 31 | | "blue" 32 | | "yellow" 33 | | "red" 34 | | "gray" 35 | | "purple" 36 | | "indigo" 37 | | "pink" 38 | | "orange" 39 | | "teal" 40 | | "cyan" 41 | | "violet"; 42 | -------------------------------------------------------------------------------- /src/configs/routes.ts: -------------------------------------------------------------------------------- 1 | export const ROUTES = { 2 | HOME: '/grocery', 3 | CHECKOUT: '/checkout', 4 | CHECKOUT_DIGITAL: '/checkout/digital', 5 | GUEST_CHECKOUT: '/checkout/guest', 6 | PROFILE: '/profile', 7 | CHANGE_PASSWORD: '/change-password', 8 | ORDERS: '/orders', 9 | REFUNDS: '/refunds', 10 | HELP: '/help', 11 | LOGOUT: '/logout', 12 | OFFERS: '/offers', 13 | ORDER_RECEIVED: '/order-received', 14 | PRODUCT: '/products', 15 | ORDER: '/order', 16 | PRIVACY: '/privacy', 17 | TERMS: '/terms', 18 | CONTACT: '/contact', 19 | SHOPS: '/shops', 20 | DOWNLOADS: '/downloads', 21 | AUTHORS: '/authors', 22 | MANUFACTURERS: '/manufacturers', 23 | SEARCH: '/search', 24 | }; 25 | -------------------------------------------------------------------------------- /src/hooks/api/user/useMe.ts: -------------------------------------------------------------------------------- 1 | import { userClient } from '@/services/user.service'; 2 | import { API_ENDPOINTS } from '@/utils/api/api-endpoints'; 3 | import { authorizationAtom } from '@/utils/authorization-atom'; 4 | import { useQuery } from '@tanstack/react-query'; 5 | import { useAtom } from 'jotai'; 6 | 7 | 8 | export function useMe() { 9 | const [isAuthorized] = useAtom(authorizationAtom); 10 | 11 | 12 | const { data, isLoading, error } = useQuery( 13 | [API_ENDPOINTS.ME], 14 | userClient.me, 15 | { 16 | enabled: isAuthorized, 17 | retry: false, 18 | } 19 | ); 20 | //TODO: do some improvement here 21 | return { me: data, isLoading, error, isAuthorized }; 22 | } 23 | -------------------------------------------------------------------------------- /src/app/(dashboard)/account/addresses/[id]/AddressEdit.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import AddressEditForm from '@/components/forms/AddressEditForm'; 3 | import { useGetAddress } from '@/hooks/api/addresses/useGetAddresses'; 4 | import React from 'react'; 5 | import AddressLoading from './loading'; 6 | 7 | type addressEditProps = { 8 | addressId: string; 9 | }; 10 | const AddressEdit = ({ addressId }: addressEditProps) => { 11 | const { data, isLoading } = useGetAddress(addressId); 12 | 13 | if(isLoading) { 14 | return AddressLoading() 15 | } 16 | return ( 17 |
18 | 19 |
20 | ); 21 | }; 22 | 23 | export default AddressEdit; 24 | -------------------------------------------------------------------------------- /src/services/upload.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from "@/utils/api/http"; 2 | 3 | export interface IUploadedImage { 4 | img_id: string; 5 | img_url: string; 6 | } 7 | 8 | 9 | export const uploadImage = async (formData: FormData) =>{ 10 | return await HttpClient.post<{image:IUploadedImage}>("/upload/image", formData, { 11 | headers: { 12 | "Content-Type": "multipart/form-data", 13 | }, 14 | }); 15 | 16 | } 17 | 18 | export const uploadImages = async (formData: FormData) =>{ 19 | return await HttpClient.post<{images:IUploadedImage[]}>("/upload/images", formData, { 20 | headers: { 21 | "Content-Type": "multipart/form-data", 22 | }, 23 | }); 24 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /src/components/layout/site-header.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import Header from "./header"; 4 | import MobileHeader from "./MobileHeader"; 5 | 6 | export function SiteHeader() { 7 | return ( 8 |
9 | 10 |
11 |
12 |
13 | 14 |
15 | 16 |
17 | 18 |
19 |
20 |
21 |
22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /src/utils/api/api-endpoints.ts: -------------------------------------------------------------------------------- 1 | export const API_ENDPOINTS = { 2 | USERS: "users", 3 | REGISTER: "register", 4 | PRODUCTS: "products", 5 | TYPES: "types", 6 | POPULAR_PRODUCTS: "popular-products", 7 | COUPONS: "coupons", 8 | ACTIVATE: "activate", 9 | VERIFY_COUPONS: "coupons/verify", 10 | CUSTOMERS: "customers", 11 | TAXES: "taxes", 12 | SHIPPINGS: "shippings", 13 | SETTINGS: "settings", 14 | CATEGORIES: "categories", 15 | LOGOUT: "logout", 16 | LOGIN: "login", 17 | GOOGLE: "google", 18 | ADDRESSES: "addresses", 19 | ME: "me", 20 | TOKEN: "token", 21 | BLOCK_USER: "users/block-user", 22 | CHANGE_PASSWORD: "change-password", 23 | FORGET_PASSWORD: "forget-password", 24 | 25 | RESET_PASSWORD: "reset-password", 26 | }; 27 | -------------------------------------------------------------------------------- /src/hooks/api/addresses/useGetAddresses.ts: -------------------------------------------------------------------------------- 1 | import { addressClient } from '@/services/address.service'; 2 | import { IAddress } from '@/types'; 3 | import { API_ENDPOINTS } from '@/utils/api/api-endpoints'; 4 | import { useQuery } from '@tanstack/react-query'; 5 | 6 | export function useGetAddresses() { 7 | const { data, isLoading, error } = useQuery( 8 | [API_ENDPOINTS.ADDRESSES], 9 | addressClient.getCustomerAddresses 10 | ); 11 | //TODO: do some improvement here 12 | return { data, isLoading, error }; 13 | } 14 | 15 | export function useGetAddress (id: string) { 16 | const { data, isLoading, error } = useQuery( 17 | [API_ENDPOINTS.ADDRESSES, id], 18 | () => addressClient.getAddress(id) 19 | ); 20 | 21 | return { data, isLoading, error }; 22 | } 23 | -------------------------------------------------------------------------------- /src/app/(dashboard)/account/edit/components/ProfileEditComponent.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import ProfileForm from "@/components/forms/ProfileForm"; 3 | import { Card, CardContent } from "@/components/ui/card"; 4 | import React from "react"; 5 | import AvatarEditForm from "./AvatarEditForm"; 6 | import ClientOnly from "@/components/common/shared/ClientOnly"; 7 | 8 | const ProfileEditComponent = () => { 9 | return ( 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ); 21 | }; 22 | 23 | export default ProfileEditComponent; 24 | -------------------------------------------------------------------------------- /src/components/shop/filtered-item.tsx: -------------------------------------------------------------------------------- 1 | import { Icons } from "../ui/icons"; 2 | 3 | 4 | interface Props { 5 | itemKey: string; 6 | itemValue: string; 7 | onClick: () => void; 8 | } 9 | 10 | export const FilteredItem = ({ itemKey, itemValue, onClick }: Props) => { 11 | return ( 12 | 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /src/app/(auth)/signout/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Skeleton } from "@/components/ui/skeleton" 2 | 3 | import { Shell } from "@/components/shells/shell" 4 | import { PageHeader, PageHeaderDescription, PageHeaderHeading } from "@/components/common/shared/page-header" 5 | 6 | export default function SignOutLoading() { 7 | return ( 8 | 9 | 10 | Sign out 11 | 12 | Are you sure you want to sign out? 13 | 14 | 15 |
16 | 17 | 18 |
19 |
20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /src/components/common/shared/tailwind-indicator.tsx: -------------------------------------------------------------------------------- 1 | import { NODE_ENV } from "@/configs/settings" 2 | 3 | 4 | export function TailwindIndicator() { 5 | if (NODE_ENV === "production") return null 6 | 7 | return ( 8 |
9 |
xs
10 |
11 | sm 12 |
13 |
md
14 |
lg
15 |
xl
16 |
2xl
17 |
18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /src/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as LabelPrimitive from "@radix-ui/react-label" 5 | import { cva, type VariantProps } from "class-variance-authority" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const labelVariants = cva( 10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 11 | ) 12 | 13 | const Label = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef & 16 | VariantProps 17 | >(({ className, ...props }, ref) => ( 18 | 23 | )) 24 | Label.displayName = LabelPrimitive.Root.displayName 25 | 26 | export { Label } 27 | -------------------------------------------------------------------------------- /src/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | export interface TextareaProps 6 | extends React.TextareaHTMLAttributes {} 7 | 8 | const Textarea = React.forwardRef( 9 | ({ className, ...props }, ref) => { 10 | return ( 11 |