This commit is contained in:
Rahul 2024-02-29 09:33:34 +01:00
parent 501d8a8d8e
commit 3226975910
76 changed files with 48623 additions and 3401 deletions

43
.dockerignore Normal file
View file

@ -0,0 +1,43 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
node_modules
.pnp
.pnp.js
# testing
coverage
# next.js
.next/
out/
build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local
/test-results/
/playwright-report/
/playwright/.cache/
/.npm-only-allow
Dockerfile
.dockerignore
npm-debug.log
README.md
.next
.git

View file

@ -29,8 +29,11 @@ module.exports = {
"sort-imports": [
"error",
{
ignoreCase: true,
ignoreDeclarationSort: true,
ignoreCase: false,
ignoreDeclarationSort: true, // don"t want to sort import lines, use eslint-plugin-import instead
ignoreMemberSort: false,
memberSyntaxSortOrder: ["none", "all", "multiple", "single"],
allowSeparatedGroups: true,
},
],
"tailwindcss/classnames-order": "off",
@ -65,6 +68,13 @@ module.exports = {
},
],
},
settings: {
"import/resolver": {
typescript: {
project: "./tsconfig.json",
},
},
},
}
function getDirectoriesToSort() {

View file

@ -1,5 +1,12 @@
{
"editor.formatOnSave": false,
"eslint.validate": [
"typescript"
],
"editor.codeActionsOnSave": {
"source.fixAll": "explicit"
},
"tailwindCSS.experimental.classRegex": [
["cva(?:<[^>]*>)?(([^)]*))", "[\"'`]([^\"'`]*).*?[\"'`]", "(?:twMerge|twJoin)\\(([^\\);]*)[\\);]"]
]
}
}

67
Dockerfile Normal file
View file

@ -0,0 +1,67 @@
FROM node:21-alpine as base
# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED 1
RUN yarn build
# If using npm comment out above and use below instead
# RUN npm run build
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# COPY --from=builder /app/public ./public
# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
# set hostname to localhost
ENV HOSTNAME "0.0.0.0"
# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
CMD ["node", "server.js"]

View file

@ -301,3 +301,10 @@ This project is licensed under the MIT License. For more information, see the [L
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
Techniques used
CSR - Client side rendering for data
useSWR hook for data fetching
SSR - from authorization

16
api/route.js Normal file
View file

@ -0,0 +1,16 @@
// export const dynamic = 'force-dynamic' // defaults to auto
// export async function GET(request) {}
export default async function handler(req, res) {
const session = await getSession(req)
// Check if the user is authenticated
if (!session) {
res.status(401).json({
error: "User is not authenticated",
})
return
}
console.log("_____________________________________________")
// Proceed with the route for authorized users
// ... implementation of the API Route
}

View file

@ -1,3 +0,0 @@
export async function GET() {
return Response.json({ status: "ok" })
}

View file

@ -1,9 +0,0 @@
import "styles/tailwind.css"
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}

View file

@ -1,65 +0,0 @@
import { Metadata } from "next"
import { Button } from "components/Button/Button"
import { LP_GRID_ITEMS } from "lp-items"
export const metadata: Metadata = {
title: "Next.js Enterprise Boilerplate",
twitter: {
card: "summary_large_image",
},
openGraph: {
url: "https://next-enterprise.vercel.app/",
images: [
{
width: 1200,
height: 630,
url: "https://raw.githubusercontent.com/Blazity/next-enterprise/main/project-logo.png",
},
],
},
}
export default function Web() {
return (
<>
<section className="bg-white dark:bg-gray-900">
<div className="mx-auto grid max-w-screen-xl px-4 py-8 text-center lg:py-16">
<div className="mx-auto place-self-center">
<h1 className="mb-4 max-w-2xl text-4xl font-extrabold leading-none tracking-tight dark:text-white md:text-5xl xl:text-6xl">
Next.js Enterprise Boilerplate
</h1>
<p className="mb-6 max-w-2xl font-light text-gray-500 dark:text-gray-400 md:text-lg lg:mb-8 lg:text-xl">
Jumpstart your enterprise project with our feature-packed, high-performance Next.js boilerplate!
Experience rapid UI development, AI-powered code reviews, and an extensive suite of tools for a smooth and
enjoyable development process.
</p>
<Button href="https://github.com/Blazity/next-enterprise" className="mr-3">
Get started
</Button>
<Button
href="https://vercel.com/new/git/external?repository-url=https://github.com/Blazity/next-enterprise"
intent="secondary"
>
Deploy Now
</Button>
</div>
</div>
</section>
<section className="bg-white dark:bg-gray-900">
<div className="mx-auto max-w-screen-xl px-4 py-8 sm:py-16 lg:px-6">
<div className="justify-center space-y-8 md:grid md:grid-cols-2 md:gap-12 md:space-y-0 lg:grid-cols-3">
{LP_GRID_ITEMS.map((singleItem) => (
<div key={singleItem.title} className="flex flex-col items-center justify-center text-center">
<div className="mb-4 flex h-10 w-10 items-center justify-center rounded-full bg-primary-100 p-1.5 text-blue-700 dark:bg-primary-900 lg:h-12 lg:w-12">
{singleItem.icon}
</div>
<h3 className="mb-2 text-xl font-bold dark:text-white">{singleItem.title}</h3>
<p className="text-gray-500 dark:text-gray-400">{singleItem.description}</p>
</div>
))}
</div>
</div>
</section>
</>
)
}

View file

@ -1,31 +0,0 @@
import type { Meta, StoryObj } from "@storybook/react"
import { Button } from "./Button"
const meta: Meta<typeof Button> = {
title: "Button",
component: Button,
args: {
intent: "primary",
underline: false,
children: "Button",
size: "lg",
},
argTypes: {
intent: {
options: ["primary", "secondary"],
control: { type: "select" },
},
size: {
options: ["sm", "lg"],
control: { type: "select" },
},
},
}
type Story = StoryObj<typeof Button>
export const Default: Story = {
render: (args) => <Button {...args} />,
}
export default meta

View file

@ -1,47 +0,0 @@
import { cva, type VariantProps } from "class-variance-authority"
import { twMerge } from "tailwind-merge"
const button = cva(
[
"justify-center",
"inline-flex",
"items-center",
"rounded-xl",
"text-center",
"border",
"border-blue-400",
"transition-colors",
"delay-50",
],
{
variants: {
intent: {
primary: ["bg-blue-400", "text-white", "hover:enabled:bg-blue-700"],
secondary: ["bg-transparent", "text-blue-400", "hover:enabled:bg-blue-400", "hover:enabled:text-white"],
},
size: {
sm: ["min-w-20", "h-full", "min-h-10", "text-sm", "py-1.5", "px-4"],
lg: ["min-w-32", "h-full", "min-h-12", "text-lg", "py-2.5", "px-6"],
},
underline: { true: ["underline"], false: [] },
},
defaultVariants: {
intent: "primary",
size: "lg",
},
}
)
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLAnchorElement>, VariantProps<typeof button> {
underline?: boolean
href: string
}
export function Button({ className, intent, size, underline, ...props }: ButtonProps) {
return (
<a className={twMerge(button({ intent, size, className, underline }))} {...props}>
{props.children}
</a>
)
}

View file

@ -1,73 +0,0 @@
import * as RadixTooltip from "@radix-ui/react-tooltip"
import { cva, VariantProps } from "class-variance-authority"
import React from "react"
import { twMerge } from "tailwind-merge"
const tooltipContent = cva([], {
variants: {
intent: {
primary: ["rounded-0.5md", "bg-zinc-700", "font-open-sans", "text-white"],
},
size: {
md: ["px-4", "py-2.5", "text-2xs"],
},
},
defaultVariants: {
intent: "primary",
size: "md",
},
})
const tooltipArrow = cva([], {
variants: {
intent: {
primary: ["fill-zinc-700"],
},
size: {
md: ["w-4", "h-2"],
},
},
defaultVariants: {
intent: "primary",
size: "md",
},
})
export interface TooltipProps extends VariantProps<typeof tooltipContent>, RadixTooltip.TooltipProps {
explainer: React.ReactElement | string
children: React.ReactElement
className?: string
withArrow?: boolean
side?: "top" | "right" | "bottom" | "left"
}
export function Tooltip({
children,
explainer,
open,
defaultOpen,
onOpenChange,
intent,
size,
side = "top",
className,
withArrow,
}: TooltipProps) {
return (
<RadixTooltip.Provider>
<RadixTooltip.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange} delayDuration={200}>
<RadixTooltip.Trigger asChild>{children}</RadixTooltip.Trigger>
<RadixTooltip.Portal>
<RadixTooltip.Content
side={side}
sideOffset={5}
className={twMerge(tooltipContent({ intent, size, className }))}
>
{explainer}
{withArrow ? <RadixTooltip.Arrow className={twMerge(tooltipArrow({ intent, size, className }))} /> : null}
</RadixTooltip.Content>
</RadixTooltip.Portal>
</RadixTooltip.Root>
</RadixTooltip.Provider>
)
}

9
components/button.js Normal file
View file

@ -0,0 +1,9 @@
import { Button } from "@chakra-ui/react"
export default function MyButton(props) {
return (
<Button href="/about" color="green.500" _hover={{ color: "blue.500" }} align="center">
About
</Button>
)
}

View file

@ -0,0 +1,44 @@
import { Box, Flex, FormLabel, Input, Spacer } from "@chakra-ui/react"
import { Hide, Show } from "@chakra-ui/react"
import React, { useEffect, useState } from "react"
/**
* Component used to generate a form input
* props -
* label
* inputtype
* placeholder
* onChange = the handler function to get the changed data
*/
export default function FormLabelInput(props) {
const [data, setData] = React.useState("")
const handlepassChange = (data) => {
props.onChange(data)
}
useEffect(() => {
handlepassChange(data)
})
return (
<Flex direction={["column", "column", "row", "row"]} alignItems="center" marginY={5}>
<Box flexBasis={0} flexGrow={1}>
<Hide below="md">
<FormLabel margin={"auto"} whiteSpace={"nowrap"} textAlign={"left"}>
{props.label}
</FormLabel>
</Hide>
</Box>
<Box flexBasis={0} flexGrow={1}>
<Input
type={props.inputtype}
placeholder={props.placeholder}
bgColor={"white"}
value={data}
onChange={(e) => {
setData(e.target.value)
}}
/>
</Box>
</Flex>
)
}

157
components/headbar.js Normal file
View file

@ -0,0 +1,157 @@
import { Box, Button, Flex, Link, Stack, Text } from "@chakra-ui/react"
import { useDisclosure } from "@chakra-ui/react"
import {
Drawer,
DrawerBody,
DrawerCloseButton,
DrawerContent,
DrawerFooter,
DrawerHeader,
DrawerOverlay,
Input,
} from "@chakra-ui/react"
import { Icon } from "@radix-ui/react-select"
import React from "react"
import Logo from "./logo"
function DrawerExample() {
const { isOpen, onOpen, onClose } = useDisclosure()
const btnRef = React.useRef()
return (
<>
<Button ref={btnRef} colorScheme="teal" onClick={onOpen}>
<Icon />
</Button>
<Drawer isOpen={isOpen} placement="left" onClose={onClose} finalFocusRef={btnRef}>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader>Create your account</DrawerHeader>
<DrawerBody>
<Input placeholder="Type here..." />
</DrawerBody>
<DrawerFooter>
<Button variant="outline" mr={3} onClick={onClose}>
Cancel
</Button>
<Button colorScheme="blue">Save</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>
</>
)
}
const NavBar = (props) => {
const [isOpen, setIsOpen] = React.useState(false)
const toggle = () => setIsOpen(!isOpen)
return (
<NavBarContainer {...props} h={["10%", "100%", "10%", "100%"]}>
<DrawerExample />
<LogoItem />
<Button
size="sm"
rounded="md"
color={["primary.500", "primary.500", "white", "white"]}
bg={["white", "white", "primary.500", "primary.500"]}
_hover={{
bg: ["primary.100", "primary.100", "primary.600", "primary.600"],
}}
>
Create Account
</Button>
<MenuToggle toggle={toggle} isOpen={isOpen} />
<MenuLinks isOpen={isOpen} />
</NavBarContainer>
)
}
const CloseIcon = () => (
<svg width="24" viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg">
<title>Close</title>
<path
fill="white"
d="M9.00023 7.58599L13.9502 2.63599L15.3642 4.04999L10.4142 8.99999L15.3642 13.95L13.9502 15.364L9.00023 10.414L4.05023 15.364L2.63623 13.95L7.58623 8.99999L2.63623 4.04999L4.05023 2.63599L9.00023 7.58599Z"
/>
</svg>
)
const MenuIcon = () => (
<svg width="24px" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" fill="white">
<title>Menu</title>
<path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z" />
</svg>
)
const MenuToggle = ({ toggle, isOpen }) => {
return (
<Box display={{ base: "block", md: "none" }} onClick={toggle}>
{isOpen ? <CloseIcon /> : <MenuIcon />}
</Box>
)
}
const LogoItem = () => {
return (
<Link href={"/home"}>
<Logo w="100px" color={["white", "white", "primary.500", "primary.500"]}></Logo>
</Link>
)
}
const MenuItem = ({ children, isLast, to = "/", ...rest }) => {
return (
<Link href={to}>
<Text display="block" {...rest} align={"center"} paddingTop={["15px", "15px", "10px", "10px"]}>
{children}
</Text>
</Link>
)
}
const MenuLinks = ({ isOpen }) => {
return (
<Box display={{ base: isOpen ? "block" : "none", md: "block" }} flexBasis={{ base: "100%", md: "auto" }}>
<Stack
spacing={[6, 8, 10]}
align="center"
justify={["flex-end", "flex-end", "center", "center"]}
direction={["column", "column", "row", "row"]}
pt={[0, 0, 0, 0]}
>
<MenuItem to="/home">Home</MenuItem>
<MenuItem to="/how">How It works </MenuItem>
<MenuItem to="/pricing">Pricing </MenuItem>
</Stack>
</Box>
)
}
const NavBarContainer = ({ children, ...props }) => {
return (
<Flex
as="nav"
align="center"
justify="space-between"
wrap="wrap"
w="100%"
mb={8}
p={[4, 6, 6, 6]}
top={0}
position="sticky"
zIndex={10}
bgGradient="linear(to-b, green.200, green.100)"
color={["white", "white", "primary.700", "primary.700"]}
{...props}
>
{children}
</Flex>
)
}
export default NavBar

14
components/layout.js Normal file
View file

@ -0,0 +1,14 @@
import Head from "next/head"
import Header from "../components/headbar"
export default function Layout({ children }) {
return (
<>
<Head>
<title>Learning bee</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<Header />
<main>{children}</main>
</>
)
}

View file

@ -0,0 +1,252 @@
import {
Box,
Button,
Flex,
FormControl,
FormErrorMessage,
FormHelperText,
FormLabel,
Input,
Link,
Stack,
} from "@chakra-ui/react"
import { getAuth, isSignInWithEmailLink, sendSignInLinkToEmail, signInWithEmailLink } from "firebase/auth"
import { useRouter } from "next/router"
import React, { Component, useContext, useState } from "react"
import FormLabelInput from "./formlabelinput"
import { geturlFormdata } from "../constants"
import { AuthContext } from "../context"
// import Login from "../googlelogin";
export default function Logincomponent(props) {
const auth = getAuth()
//for emaillink auth
const [email, setEmail] = useState("")
const [linksent, setLinksent] = useState(false)
//for email password auth
const [password, setPassword] = useState("")
const authContext = useContext(AuthContext)
const router = useRouter()
const [isloaded, setIsloaded] = useState(false)
const [emailselect, setEmailselect] = useState(false)
React.useEffect(() => {
if (!isloaded) {
setIsloaded(true)
}
})
// function validateForm() {
// return email.length > 0 && password.length > 0
// }
// //for email password authentication
// async function handleSubmit(event) {
// event.preventDefault()
// var urlForm = geturlFormdata("user", "login")
// console.log(email, password)
// await getTokens(urlForm.url, email, password).then((value) => {
// var idtype = null
// if (email.includes("@")) {
// idtype = "email"
// } else {
// idtype = "phone"
// }
// // getuserdata(idtype , email).then((value)=>{
// // router.push(`/home`)
// // })
// })
// }
const onSignInSubmit = () => {}
const onEmailSubmit = () => {
setEmailselect(true)
}
/////////////////////////////
//email link auth
const actionCodeSettings = {
// URL you want to redirect back to. The domain (www.example.com) for this
// URL must be in the authorized domains list in the Firebase Console.
// url: `${siterooturl}login`,
url: `http://localhost:3000/login`,
// // This must be true.
handleCodeInApp: true,
// iOS: {
// bundleId: 'com.example.ios'
// },
// android: {
// packageName: 'com.example.android',
// installApp: true,
// minimumVersion: '12'
// },
// dynamicLinkDomain: 'example.page.link'
}
const sighinWithCreds = async (email, password) => {
const response = await fetch("/api/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
})
console.log(response.ok)
if (response.ok) {
router.push("/home")
} else {
// Handle errors
}
}
const signinWithLink = async () => {
console.log(auth, email, actionCodeSettings)
await sendSignInLinkToEmail(auth, email, actionCodeSettings)
.then(() => {
// The link was successfully sent. Inform the user.
// Save the email locally so you don't need to ask the user for it again
// if they open the link on the same device.
setLinksent(true)
// ...
})
.catch((error) => {
console.log(error)
console.log("error sending link")
const errorCode = error.code
const errorMessage = error.message
// ...
})
}
if (isloaded && isSignInWithEmailLink(auth, window.location.href)) {
// Additional state parameters can also be passed via URL.
// This can be used to continue the user's intended action before triggering
// the sign-in operation.
// Get the email if available. This should be available if the user completes
// the flow on the same device where they started it.
console.log(email)
if (!email) {
// User opened the link on a different device. To prevent session fixation
// attacks, ask the user to provide the associated email again. For example:
// email = window.prompt('Please provide your email for confirmation');
}
// The client SDK will parse the code from the link for you.
signInWithEmailLink(auth, email, window.location.href)
.then((result) => {
// Clear email from storage.
console.log("logged in")
// result.user.providerData
onSuccess(result)
// window.localStorage.removeItem('emailForSignIn');
//router.push('/home')
// You can access the new user via result.user
// Additional user info profile not available via:
// result.additionalUserInfo.profile == null
// You can check if the user is new or existing:
// result.additionalUserInfo.isNewUser
})
.catch((error) => {
console.log(error)
onFailure()
// Some error occurred, you can inspect the code: error.code
// Common errors could be invalid email and invalid or expired OTPs.
})
}
const onSuccess = (res) => {
console.log(res)
// verifyonServer(res._tokenResponse.idToken, "email", res.user.email, res)
}
const onFailure = () => {
alert(`Something went Wrong. Try again `)
}
const confirmCode = (code) => {
// confirmationResult.confirm(code).then((result) => {
// // User signed in successfully.
// const user = result.user;
// // ...
// }).catch((error) => {
// // User couldn't sign in (bad verification code?)
// // ...
// });
}
const handleEmailChange = (val) => {
setEmail(val)
}
const handlePasswordChange = (val) => {
setPassword(val)
}
console.log(password)
return (
<Box
w={["80%", "60%", "40%"]}
align="center"
bgGradient="linear(to-b, blue.200, blue.500)"
padding={10}
borderRadius={10}
margin="auto"
>
{!linksent && (
<>
<FormLabel margin={"auto"} padding={"auto"} textAlign={"center"}>
Log in
</FormLabel>
<FormControl className={"form-group"}>
<FormLabelInput
inputtype="email"
label="Email*"
placeholder="abc@xyz.uvw"
onChange={(e) => handleEmailChange(e)}
/>
<FormLabelInput
inputtype="password"
label="Password"
placeholder="type your password"
onChange={(e) => handlePasswordChange(e)}
/>
</FormControl>
<Button className="btn" onClick={() => sighinWithCreds(email, password)}>
Log in
</Button>
<p>--- or ---</p>
<Button className="btn" onClick={signinWithLink}>
Continue with signin link
</Button>
{/* <p >Sign in with</p> */}
{/* <Login /> */}
</>
)}
{linksent && (
<>
<h4>Signin Link sent</h4>
<div className={"form-group"}>
<div style={{ marginBlock: "10%" }}>Check your provided email , And Click on the Link to verify </div>
<h3>WE are already waiting for you</h3>
</div>
</>
)}
</Box>
)
}

12
components/logo.js Normal file
View file

@ -0,0 +1,12 @@
import { Box, Text } from "@chakra-ui/react"
import React from "react"
export default function Logo(props) {
return (
<Box {...props}>
<Text fontSize="lg" fontWeight="bold">
Logo
</Text>
</Box>
)
}

39
components/menuitem.js Normal file
View file

@ -0,0 +1,39 @@
import { Card, CardBody, CardFooter, CardHeader } from "@chakra-ui/react"
import { Heading, Image, Stack, Text } from "@chakra-ui/react"
import { useRouter } from "next/router"
import React, { useContext, useEffect, useState } from "react"
export default function MenuItem(props) {
//define states here
const [isloaded, setIsLoaded] = React.useState(false)
//router
const router = useRouter()
useEffect(() => {
if (!isloaded) {
console.log("isloaded called")
setIsLoaded(true)
}
})
//function when clicked
const handleOnClick = (e) => {
router.push(`/learningpath/${props.id}`)
}
return (
<Card onClick={handleOnClick}>
<CardBody>
<Image src={props.image_url} alt={props.image_desc} borderRadius="lg" />
<Stack mt="6" spacing="3">
<Heading size="md">{props.title}</Heading>
<Text>{props.summary}</Text>
</Stack>
</CardBody>
</Card>
)
}

View file

@ -0,0 +1,125 @@
import {
Box,
Button,
Flex,
FormControl,
FormErrorMessage,
FormHelperText,
FormLabel,
Input,
Link,
Stack,
} from "@chakra-ui/react"
import { useRouter } from "next/router"
import React, { useState } from "react"
import FormLabelInput from "./formlabelinput"
import { geturlFormdata, siterooturl } from "../constants"
export default function Signupcomponent(props) {
const [email, setEmail] = React.useState("")
const [phone, setPhone] = React.useState("")
const [password, setPassword] = React.useState("")
const [confirm_password, setConfirmPassword] = React.useState("")
const router = useRouter()
const [show, setShow] = useState(true)
const validateForm = () => {
return email.length > 0 && (phone.length >= 10 || phone.length == 0) && password.length > 0
}
const handleSubmit = (event) => {
console.log(email, password, confirm_password, phone)
if (phone.length > 0 && phone.length < 10) {
//popup
}
event.preventDefault()
var urlForm
if (email.length == 0) {
urlForm = geturlFormdata("user", "signup", {}, { phone: phone, password: password })
} else if (phone.length == 0) {
urlForm = geturlFormdata("user", "signup", {}, { mail: email, password: password })
} else {
urlForm = geturlFormdata("user", "signup", {}, { mail: email, phone: phone, password: password })
}
if (password !== confirm_password) {
setShow(true)
return
}
try {
// postsignup(urlForm.url, urlForm.formdata).then(() => {
// router.push("/info")
// })
} catch (e) {}
}
const handleEmailChange = (val) => {
setEmail(val)
}
const handlePhoneChange = (val) => {
setPhone(val)
}
const handlePasswordChange = (val) => {
setPassword(val)
}
const handleConfirmPasswordChange = (val) => {
setConfirmPassword(val)
}
return (
<Box
w="50%"
align="center"
bgGradient="linear(to-b, blue.200, blue.500)"
padding={10}
borderRadius={10}
margin="auto"
>
<FormControl onSubmit={handleSubmit} align="center">
<FormLabel margin={"auto"} padding={"auto"} textAlign={"center"}>
Register
</FormLabel>
<FormLabelInput
inputtype="email"
label="Email*"
placeholder="abc@xyz.uvw"
onChange={(e) => handleEmailChange(e)}
/>
<FormLabelInput
inputtype="number"
label="Phone"
placeholder="XXXXXXXXXX"
onChange={(e) => handlePhoneChange(e)}
/>
<FormLabelInput
inputtype="password"
label="Password"
placeholder="type your password"
onChange={(e) => handlePasswordChange(e)}
/>
<FormLabelInput
inputtype="password"
label="Confirm Password"
placeholder="type your password again"
onChange={(e) => handleConfirmPasswordChange(e)}
/>
<Button type="submit" margin="auto" marginY="10px" disabled={!validateForm()} onClick={handleSubmit}>
Register
</Button>
<FormLabel margin={"auto"} align="center" textAlign={"center"}>
Already registered?{" "}
<Link href={`${siterooturl}login`} color="black.500" _hover={{ color: "blue.800", fontSize: "130%" }}>
log in
</Link>
</FormLabel>
</FormControl>
</Box>
)
}

36
constants.js Normal file
View file

@ -0,0 +1,36 @@
//here we can define all the things that we can keep in the cache database and remove it after some time
//getting the type of endpoint at one point
export const geturlFormdata = (data, reqtype, queryoptions, formdataoptions) => {
var rooturl = "https://api.smorentel.com/"
var allurl = rooturl + `${data}/${reqtype}?`
var queryparam = new String()
for (const property in queryoptions) {
queryparam += `${property}=${queryoptions[property]}&`
}
var formdata = new FormData()
for (const formproperty in formdataoptions) {
formdata.set(formproperty, formdataoptions[formproperty])
}
return { url: allurl + queryparam.slice(0, queryparam.length - 1), formdata: formdata }
}
export const workstatus_dict = { 1: "progress", 2: "created", 3: "done" }
export const onRefresh = (authContext) => {
try {
if (typeof window !== "undefined") {
if (localStorage.getItem("refresh_token") != undefined) {
authContext.login()
}
} else {
authContext.login()
}
} catch (e) {
console.log(e)
}
}

29
context.js Normal file
View file

@ -0,0 +1,29 @@
import router from "next/router"
import { createContext } from "react"
import { getlocal, storelocal } from "./localstore"
export const AuthContext = createContext({
isLoggedIn: true,
accounttype: true,
firebase: null,
premium: false,
modelopen: false,
setModel: () => {},
changeaccount: () => {
accounttype = !accounttype
storelocal("accounttype", accounttype)
},
checkType: async () => {
var at = getlocal("accounttype")
accounttype = at
},
login: () => {
isLoggedIn = true
},
logout: () => {
localStorage.removeItem("access_token")
localStorage.removeItem("refresh_token")
localStorage.removeItem("userdata")
isLoggedIn = false
},
})

33
datafetch/datafetch.js Normal file
View file

@ -0,0 +1,33 @@
import useSWR from "swr"
const fetcher = (...args) => fetch(...args).then((res) => res.json())
export function menuitemfetcher(url) {
const { data, error, isLoading } = useSWR("https://jsonplaceholder.typicode.com/posts", fetcher)
return {
data: data,
isLoading,
isError: error,
}
}
export function learningitemfetcher(url) {
const { data, error, isLoading } = useSWR("https://jsonplaceholder.typicode.com/posts", fetcher)
return {
data: data,
isLoading,
isError: error,
}
}
export function learningpodfetcher() {
const { data, error, isLoading } = useSWR("https://jsonplaceholder.typicode.com/posts", fetcher)
return {
data: data,
isLoading,
isError: error,
}
}

28
docker-compose.yaml Normal file
View file

@ -0,0 +1,28 @@
version: '3.8'
services:
nextjs:
build:
context: .
dockerfile: Dockerfile.nextjs
restart: always
pm2:
build:
context: .
dockerfile: Dockerfile.pm2
volumes:
- ./pm2.config.js:/pm2/pm2.config.js
restart: always
depends_on:
- nextjs
nginx:
build:
context: .
dockerfile: Dockerfile.nginx
ports:
- "80:80"
restart: always
depends_on:
- pm2

51
localstore.js Normal file
View file

@ -0,0 +1,51 @@
export const storeobjlocal = (key, value) => {
localStorage.setItem(key, JSON.stringify(value))
}
export const getobjlocal = (key) => {
return JSON.parse(localStorage.getItem(key))
}
export const storelocal = (key, value) => {
localStorage.setItem(key, value)
}
export const getlocal = (key) => {
return localStorage.getItem(key)
}
export const localkeys = {
access_token: "",
refresh_token: "",
user: { customer: {}, worker: {} },
settings: {},
}
export const stateobj = {
user: {},
}
/**
* what are the filter options -
* 1 place ==> filter_place
* 2 price range
* 3 location
* 4 distance
* 5 tags
* 6 categories
* 7 sub categories
*/
/**
* user infos -
* 1 access_token
* 2 refresh_token
* 3 user_data -> json -> (user_key) ->
*/
/**
* single page data -
* items
* bookings
* bookingreqs
*/

73
middleware.js Normal file
View file

@ -0,0 +1,73 @@
import { NextRequest, NextResponse } from "next/server"
import { refreshAccessToken } from "./utils/auth"
import { jwtVerify } from "jose"
const secretKey = new TextEncoder().encode("Swe4g7c?UBm5Nrd96vhsVDtkyJFbqKMTm!TMw5BDRLtaCFAXNvbq?s4rGKQSZnUP")
const verifyJWT = async (token) => {
const { payload, protectedHeader } = await jwtVerify(token, secretKey)
return payload
}
export default async function middleware(req, res) {
// Extract token from request headers or cookies or wherever it's stored
const token = req.cookies.get("token")
if (!token || token.value == "") {
if (req.url == "http://localhost:3000/login") {
} else {
return NextResponse.redirect(new URL("/login", req.url))
}
} else {
if (req.url == "http://localhost:3000/login") {
return NextResponse.redirect("http://localhost:3000/home")
}
}
try {
// Verify the token
console.log("ASdasdasssssssssssss")
console.log(token.value)
const payload = await verifyJWT(token.value)
// Attach the decoded user object to the request
// req.user = decoded.user;
// return NextResponse.redirect(new URL( req.url, '/home'))
// Validate if the user is the one that is present in cookie
} catch (error) {
if (error.name === "JWTExpired") {
console.log(error)
//delete the token from cookie
console.log("deleting the token")
//renew the token
// console.log(req.cookies.get('rtoken'));
const rtoken = req.cookies.get("rtoken")
if (rtoken == undefined) {
console.log("undefined")
}
console.log("defined")
const newtoken = await refreshAccessToken(rtoken)
if (newtoken == undefined) {
const res = NextResponse.redirect(new URL("/login", req.url)) // creates an actual instance
res.cookies.set("token", newtoken)
return res
}
console.log("defined")
const res = NextResponse.next() // creates an actual instance
res.cookies.set("token", newtoken)
return res
}
console.log(error)
// Handle other JWT errors
// return Response.json({ message: 'Unauthorized' }, { status: 401 });
// const res = NextResponse.redirect(new URL( '/login',req.url)) // creates an actual instance
// res.cookies.delete('token') // can be called on an instance
// return res
}
}
export const config = {
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
}

View file

@ -1,22 +0,0 @@
import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"
export function middleware(request: NextRequest) {
// TODO: Feel free to remove this block
if (request.headers?.get("host")?.includes("next-enterprise.vercel.app")) {
return NextResponse.redirect("https://blazity.com/open-source/nextjs-enterprise-boilerplate", { status: 301 })
}
}
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - api (API routes)
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
*/
"/((?!api|_next/static|_next/image|favicon.ico).*)",
],
}

View file

@ -2,9 +2,12 @@ import withBundleAnalyzer from "@next/bundle-analyzer"
import withPlugins from "next-compose-plugins"
import { env } from "./env.mjs"
/**
* @type {import('next').NextConfig}
*/
const config = withPlugins([[withBundleAnalyzer({ enabled: env.ANALYZE })]], {
reactStrictMode: true,
experimental: { instrumentationHook: true },

14
next.config.js Normal file
View file

@ -0,0 +1,14 @@
// next.config.js
module.exports = {
// ... rest of the configuration.
output: "standalone",
async redirects() {
return [
{
source: "/",
destination: "/home",
permanent: true,
},
]
},
}

39577
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -23,6 +23,12 @@
"coupling-graph": "npx madge --extensions js,jsx,ts,tsx,css,md,mdx ./ --exclude '.next|tailwind.config.js|reset.d.ts|prettier.config.js|postcss.config.js|playwright.config.ts|next.config.js|next-env.d.ts|instrumentation.ts|e2e/|README.md|.storybook/|.eslintrc.js' --image graph.svg"
},
"dependencies": {
"@auth/core": "^0.26.2",
"@chakra-ui/next-js": "^2.2.0",
"@chakra-ui/react": "^2.8.2",
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"@headlessui/react": "^1.7.18",
"@next/bundle-analyzer": "^14.0.3",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-checkbox": "^1.0.4",
@ -47,13 +53,25 @@
"@semantic-release/release-notes-generator": "^12.1.0",
"@t3-oss/env-nextjs": "^0.7.1",
"@vercel/otel": "^0.3.0",
"bcryptjs": "^2.4.3",
"class-variance-authority": "^0.7.0",
"cookie-parser": "^1.4.6",
"eslint-import-resolver-typescript": "^3.6.1",
"firebase": "^10.8.0",
"framer-motion": "^11.0.3",
"jose": "^5.2.2",
"jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21",
"melonjs": "^16.1.1",
"next": "^14.0.3",
"next-auth": "^4.24.5",
"next-compose-plugins": "^2.2.1",
"react": "^18.2.0",
"react-bootstrap": "^2.10.0",
"react-dom": "^18.2.0",
"swr": "^2.2.4",
"tailwind-merge": "^2.0.0",
"webcrypto": "^0.1.1",
"zod": "^3.22.4"
},
"devDependencies": {

102
pages/_app.js Normal file
View file

@ -0,0 +1,102 @@
import { initializeApp } from "firebase/app"
import React, { useContext, useEffect, useState } from "react"
//Auth imports
import { AuthContext } from "../context"
import "firebase/auth"
import { getAuth } from "firebase/auth"
//server side rendring things
import { SSRProvider } from "react-bootstrap"
import { ChakraProvider } from "@chakra-ui/react"
import customTheme from "../utils/themes"
function MyApp({ Component, pageProps }) {
/**Initailize the states
* Important for keeping data over pages
*/
const [modelopen, setModelopen] = React.useState(false)
const [loggedIn, setLoggedIn] = React.useState(false)
const [acctype, setAcctype] = React.useState(false)
const [loaded, setLoaded] = React.useState(false)
///**This place is for firebase Auth */
//initialize firebase
const firebaseConfig = {
apiKey: "AIzaSyARcLufTeUZbGue0-k9iZJVxmKlp0l0HQU",
authDomain: "freebees-24743.firebaseapp.com",
projectId: "freebees-24743",
storageBucket: "freebees-24743.appspot.com",
messagingSenderId: "1084271040061",
appId: "1:1084271040061:web:91df1dc11b58f5a4807c54",
measurementId: "G-6Z61GFCN05",
}
const app = initializeApp(firebaseConfig)
const auth = getAuth()
const setModel = (data) => {
setModelopen(data)
}
const login = () => {
setLoggedIn(true)
}
const logout = () => {
setLoggedIn(false)
auth.signOut().then(() => {
console.log("successfully signed out")
})
localStorage.clear()
}
const checkType = () => {
console.log("check")
if (typeof window != undefined) {
}
}
/////////
/**
* useEffect has been uesd to take actions on the first rendering
*/
useEffect(() => {
const app = initializeApp(firebaseConfig)
if (!loaded) {
console.log("1st check", firebaseConfig)
setLoaded(true)
}
})
///// Manual test with console
const getLayout = Component.getLayout ?? ((page) => page)
return (
<SSRProvider>
<ChakraProvider theme={customTheme}>
<AuthContext.Provider
value={{
isLoggedIn: loggedIn,
firebase: app,
login: login,
logout: logout,
accounttype: acctype,
modelopen: modelopen,
setModel: setModel,
checkType: checkType,
}}
>
{getLayout(<Component {...pageProps} />)}
</AuthContext.Provider>
</ChakraProvider>
</SSRProvider>
)
}
export default MyApp

38
pages/api/login.js Normal file
View file

@ -0,0 +1,38 @@
import { createTokens, hashPassword, verifyPassword } from "../../utils/auth"
export default async function handler(req, res) {
if (req.method !== "POST") {
return res.status(405).json({ message: "Method Not Allowed" })
}
const { email, password } = req.body
console.log(password)
// You'd need to fetch user details from your database or any data source
//fetch data from postgres database where we store password as hash
// Here, for demonstration, let's assume a hardcoded user
const user = {
id: 1,
email: "user@example.com",
passwordHash: "$2a$10$Zy/TYg6WwOOctCQ6e/KOXebvH3AliSDjdopPxrIUWELVJBf/KE.iq", // hashed password: "password123"
}
const isValid = await verifyPassword(password, user.passwordHash)
if (!isValid) {
return res.status(401).json({ message: "Invalid credentials" })
}
const token = await createTokens(user.id)
res.setHeader("Set-Cookie", [
`token=${token.accessToken}; Path=/; HttpOnly`,
`rtoken=${token.refreshToken}; Path=/; HttpOnly`,
])
return res.status(200).json({ token })
}
//user@example.com
//password123

7
pages/api/logout.js Normal file
View file

@ -0,0 +1,7 @@
export default async function handler(req, res) {
// if (req.method === 'POST') {
// cookies().delete('token');
// } else {
// throw new NotFoundError();
// }
}

35
pages/api/refreshtoken.js Normal file
View file

@ -0,0 +1,35 @@
import { issueAccessToken, verifyRefreshToken } from "../../utils/auth"
// Example middleware to attach access token to outgoing requests
async function attachAccessToken(req, res, next) {
const accessToken = req.cookies.accessToken
if (!accessToken) {
return res.status(401).json({ message: "Access token missing" })
}
// You might want to check token expiration here and refresh if necessary
req.headers.Authorization = `Bearer ${accessToken}`
next()
}
export default async function handler(req, res) {
if (req.method !== "POST") {
return res.status(405).json({ message: "Method Not Allowed" })
}
const { refreshToken } = req.body
try {
const decoded = await verifyRefreshToken(refreshToken.value)
// Check if refresh token is valid, then issue a new access token
const accessToken = await issueAccessToken(decoded.userId)
console.log("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
res.setHeader("Set-Cookie", [`token=${accessToken}; Path=/; HttpOnly`])
return res.status(200).json({ accessToken })
} catch (error) {
console.error("Error refreshing token:", error)
return res.status(401).json({ message: "Invalid refresh token" })
}
}

35
pages/content.js Normal file
View file

@ -0,0 +1,35 @@
import Head from "next/head"
import React, { useContext, useEffect, useState } from "react"
import MyButton from "../components/button"
import Header from "../components/headbar"
import Logincomponent from "../components/logincomponent"
import Signupcomponent from "../components/signupcomponent"
export default function Content(props) {
const [isloaded, setIsLoaded] = React.useState(false)
useEffect(() => {
if (!isloaded) {
console.log("isloaded called")
setIsLoaded(true)
}
})
return (
<>
<Header />
</>
)
}
/**This place should be used to get any information from the server side
* example : we need to get the session token
* or any thing related to the page */
export async function getServerSideProps() {
const data = await fetch("https://jsonplaceholder.typicode.com/todos").then((response) => {
response.json()
})
return { props: { title: "rahul" } }
}

37
pages/home.js Normal file
View file

@ -0,0 +1,37 @@
import { useRouter } from "next/router"
import React, { useContext, useEffect, useState } from "react"
import Layout from "../components/layout"
export default function Home(props) {
const [isloaded, setIsLoaded] = React.useState(false)
useEffect(() => {
if (!isloaded) {
console.log("isloaded called")
setIsLoaded(true)
}
})
const router = useRouter()
return (
<>
<button onClick={() => router.push("/menu")}>Click here to read menu</button>
</>
)
}
/**This place should be used to get any information from the server side
* example : we need to get the session token
* or any thing related to the page */
export async function getServerSideProps() {
const data = await fetch("https://jsonplaceholder.typicode.com/todos").then((response) => {
response.json()
})
return { props: { title: "rahul" } }
}
Home.getLayout = function getLayout(page) {
return <Layout>{page}</Layout>
}

30
pages/index.js Normal file
View file

@ -0,0 +1,30 @@
import { Box, Center, Flex, Heading, Text } from "@chakra-ui/react"
import React, { useEffect } from "react"
function App() {
const [isloaded, setIsLoaded] = React.useState(false)
useEffect(() => {
if (!isloaded) {
console.log("isloaded called")
setIsLoaded(true)
}
})
return (
<Center bg="gray.200" height="100vh">
<Box textAlign="center">
<Heading size="4xl" color={"blue.500"}>
Coming Soon
</Heading>
<Text fontSize="2xl" mt="4">
⚠ We are working on it! ⚠
</Text>
<Flex justifyContent="center" mt="8"></Flex>
</Box>
</Center>
)
}
export default App

View file

@ -0,0 +1,28 @@
import * as me from "melonjs"
import { useRouter } from "next/router"
import React, { useContext, useEffect, useState } from "react"
import Layout from "../../components/layout"
export default function Page(props) {
const [isloaded, setIsLoaded] = React.useState(false)
useEffect(() => {
if (!isloaded) {
console.log("isloaded called")
setIsLoaded(true)
}
})
const router = useRouter()
return <></>
}
/**This place should be used to get any information from the server side
* example : we need to get the session token
* or any thing related to the page */
Page.getLayout = function getLayout(page) {
return <Layout>{page}</Layout>
}

View file

@ -0,0 +1,77 @@
import { Button, Error, Grid, Spinner } from "@chakra-ui/react"
import { useRouter } from "next/router"
import React, { useContext, useEffect, useState } from "react"
import Layout from "../../components/layout"
import { learningitemfetcher } from "../../datafetch/datafetch"
/**
* params -
* length of path - plength ( the number of tasks )
* structure of the path - DAG
* type of path to be formed - pathtype
*/
function Menubox(props) {
const { data, isLoading, isError } = learningitemfetcher()
const [showedcount, setShowedcount] = React.useState(40)
const router = useRouter()
if (isLoading) return <Spinner />
if (isError) return <Error />
const container = (
<>
<Grid templateColumns="repeat(10, 1fr)" padding="70" gap={10}>
{data.slice(0, showedcount).map((item) => {
if ([1, 22, 3, 24, 5, 26].includes(item.id)) {
return (
<div
key={item.id}
style={{ backgroundColor: "red", height: 100 }}
onClick={() => {
router.push(`/learningpage/${item.id}`)
}}
></div>
)
}
return <div key={100} style={{ backgroundColor: "white", height: 100 }}></div>
})}
</Grid>
</>
)
return container
}
export default function LearningPath(props) {
const [isloaded, setIsLoaded] = React.useState(false)
useEffect(() => {
if (!isloaded) {
console.log("isloaded called")
setIsLoaded(true)
}
})
return (
<>
<Menubox />
</>
)
}
/**This place should be used to get any information from the server side
* example : we need to get the session token
* or any thing related to the page */
export async function getServerSideProps() {
const data = await fetch("https://jsonplaceholder.typicode.com/todos").then((response) => {
response.json()
})
return { props: { title: "rahul" } }
}
LearningPath.getLayout = function getLayout(page) {
return <Layout>{page}</Layout>
}

41
pages/login.js Normal file
View file

@ -0,0 +1,41 @@
import { useRouter } from "next/router"
import React, { useContext, useEffect, useState } from "react"
import Layout from "../components/layout"
import Logincomponent from "../components/logincomponent"
import Signupcomponent from "../components/signupcomponent"
export default function Login(props) {
const [isloaded, setIsLoaded] = React.useState(false)
useEffect(() => {
if (!isloaded) {
console.log("isloaded called")
setIsLoaded(true)
}
})
const router = useRouter()
return (
<>
<Logincomponent />
<button onClick={() => router.push("/menu")}>Click here to read menu</button>
</>
)
}
/**This place should be used to get any information from the server side
* example : we need to get the session token
* or any thing related to the page */
export async function getServerSideProps() {
const data = await fetch("https://jsonplaceholder.typicode.com/todos").then((response) => {
response.json()
})
return { props: { title: "rahul" } }
}
Login.getLayout = function getLayout(page) {
return <Layout>{page}</Layout>
}

67
pages/menu.js Normal file
View file

@ -0,0 +1,67 @@
import { Button, Error, Grid, Spinner } from "@chakra-ui/react"
import React, { useContext, useEffect, useState } from "react"
import Layout from "../components/layout"
import MenuItem from "../components/menuitem"
import { menuitemfetcher } from "../datafetch/datafetch"
function Menubox(props) {
const { data, isLoading, isError } = menuitemfetcher()
const [showedcount, setShowedcount] = React.useState(40)
if (isLoading) return <Spinner />
if (isError) return <Error />
const container = (
<>
<Grid
templateColumns={["repeat(1, 1fr)", "repeat(1, 1fr)", "repeat(2, 1fr)", "repeat(3, 1fr)", "repeat(4, 1fr)"]}
padding={["4%", "5%", "6%", "7%"]}
gap={6}
>
{data.slice(1, showedcount).map((item) => (
<MenuItem
key={item.id}
id={item.id}
itemid={item.userId}
title={item.title}
summary={item.body}
image_url="https://example.com/image1.jpg"
/>
))}
</Grid>
<Button onClick={() => setShowedcount(showedcount + 40)}></Button>
</>
)
return container
}
export default function MenuPage(props) {
const [isloaded, setIsLoaded] = React.useState(false)
useEffect(() => {
if (!isloaded) {
console.log("isloaded called")
setIsLoaded(true)
}
})
return <Menubox />
}
/**This place should be used to get any information from the server side
* example : we need to get the session token
* or any thing related to the page */
export async function getServerSideProps() {
const data = await fetch("https://jsonplaceholder.typicode.com/todos").then((response) => {
response.json()
})
return { props: { title: "rahul" } }
}
MenuPage.getLayout = function getLayout(page) {
return <Layout>{page}</Layout>
}

17
pm2.config.js Normal file
View file

@ -0,0 +1,17 @@
module.exports = {
apps: [
{
name: "nextjs-app",
script: "npm",
args: "start",
instances: "max", // or specify the number of instances you want
autorestart: true,
watch: false,
max_memory_restart: "1G",
env: {
NODE_ENV: "production",
},
},
// You can add more apps as needed for other services you want to manage with PM2
],
}

BIN
public/SMOR-192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

BIN
public/SMOR-256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/SMOR-384.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
public/SMOR-512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,62 @@
// Give the service worker access to Firebase Messaging.
// Note that you can only use Firebase Messaging here. Other Firebase libraries
// are not available in the service worker.
importScripts("https://www.gstatic.com/firebasejs/9.2.0/firebase-app-compat.js")
importScripts("https://www.gstatic.com/firebasejs/9.2.0/firebase-messaging-compat.js")
// Initialize the Firebase app in the service worker by passing in
// your app's Firebase config object.
// https://firebase.google.com/docs/web/setup#config-object
const firebaseConfig = {
apiKey: "AIzaSyARcLufTeUZbGue0-k9iZJVxmKlp0l0HQU",
authDomain: "freebees-24743.firebaseapp.com",
projectId: "freebees-24743",
storageBucket: "freebees-24743.appspot.com",
messagingSenderId: "1084271040061",
appId: "1:1084271040061:web:91df1dc11b58f5a4807c54",
measurementId: "G-6Z61GFCN05",
}
// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const app = firebase.initializeApp(firebaseConfig)
const messaging = firebase.messaging(app)
// If you would like to customize notifications that are received in the
// background (Web app is closed or not in browser focus) then you should
// implement this optional method.
// Keep in mind that FCM will still show notification messages automatically
// and you should use data messages for custom notifications.
// For more info see:
// https://firebase.google.com/docs/cloud-messaging/concept-options
messaging.onBackgroundMessage((payload) => {
console.log("[firebase-messaging-sw.js] Received background message ", payload)
// Customize notification here
const Title = payload.data.title
const Options = {
body: payload.data.body,
icon: "/images/SMOR-192.png",
}
self.registration.showNotification(Title, Options)
})
self.addEventListener("notificationclick", function (event) {
event.notification.close()
event.waitUntil(
clients.matchAll({ type: "window", includeUncontrolled: true }).then(function (clientList) {
if (clientList.length > 0) {
let client = clientList[0]
for (let i = 0; i < clientList.length; i++) {
if (clientList[i].focused) {
client = clientList[i]
}
}
return client.focus()
}
return clients.openWindow("/")
})
)
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

BIN
public/icon-192x192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
public/icon-256x256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
public/icon-384x384.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
public/icon-512x512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
public/images/SMOR-192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

BIN
public/images/SMOR-256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/images/SMOR-384.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
public/images/SMOR-512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
public/images/no-image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

4
public/images/vercel.svg Normal file
View file

@ -0,0 +1,4 @@
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

30
public/manifest.json Normal file
View file

@ -0,0 +1,30 @@
{
"name": "PWA App",
"short_name": "App",
"icons": [
{
"src": "/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/icon-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"gcm_sender_id": "1084271040061",
"theme_color": "#007",
"background_color": "#007",
"start_url": "/",
"display": "standalone",
"orientation": "portrait"
}

BIN
public/marker-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

267
public/sw.js Normal file
View file

@ -0,0 +1,267 @@
if (!self.define) {
let e,
s = {}
const t = (t, c) => (
(t = new URL(t + ".js", c).href),
s[t] ||
new Promise((s) => {
if ("document" in self) {
const e = document.createElement("script")
;(e.src = t), (e.onload = s), document.head.appendChild(e)
} else (e = t), importScripts(t), s()
}).then(() => {
let e = s[t]
if (!e) throw new Error(`Module ${t} didn’t register its module`)
return e
})
)
self.define = (c, n) => {
const i = e || ("document" in self ? document.currentScript.src : "") || location.href
if (s[i]) return
let a = {}
const l = (e) => t(e, i),
u = { module: { uri: i }, exports: a, require: l }
s[i] = Promise.all(c.map((e) => u[e] || l(e))).then((e) => (n(...e), a))
}
}
define(["./workbox-1846d813"], function (e) {
"use strict"
importScripts("worker-WcZyltu4AIEZdlepY3Peo.js"),
self.skipWaiting(),
e.clientsClaim(),
e.precacheAndRoute(
[
{ url: "/SMOR-192.png", revision: "694a5d68bb01b831f6c9b5c7d43f0c27" },
{ url: "/SMOR-256.png", revision: "93baa0d7792e6776ccfbb917ed8fb1e8" },
{ url: "/SMOR-384.png", revision: "c0ef024f0903ba73d308e2dee7889bf9" },
{ url: "/SMOR-512.png", revision: "243de524262c12c7e00403a4b5dc14c5" },
{ url: "/_next/static/WcZyltu4AIEZdlepY3Peo/_buildManifest.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/WcZyltu4AIEZdlepY3Peo/_middlewareManifest.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/WcZyltu4AIEZdlepY3Peo/_ssgManifest.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/0b7b90cd.23a679f790af5ada.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/1120-4b6c01efbb660cb0.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/1443-c9911baf6aa6969d.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/1857-4a754531d0dc3ce7.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/1944-1172cffe798b2d2d.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/1bfc9850-a5e52aab60a2bf09.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/2022-0b1731e5d5e56391.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/252f366e-25667f96c249ca01.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/3516-4d6afd5e3449cb6f.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/3761-100286903250d54e.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/4067.cc92d8e1edb00a0b.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/4321-45e31c436c8cb7a8.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/4355-471e0659b91aaa0f.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/4356-91fe2cc212fb70f3.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/5302-b90e4a54f702b9b8.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/5365-49d12afab2725ba2.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/5575-2326a978162761c3.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/5979-6f2587baf37a9775.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/6046-38951b11790c6f85.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/6220-3632eefa25b908ea.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/6602-15be9cec14ac902e.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/7005-d08d38268c11f695.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/7019-594327e28c484778.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/7164.b91874f80a184dd3.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/7238-8610a6af415f8caf.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/7259-0a5f5ceb4cbcd248.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/7411-111c6e401cb97781.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/8423-fc8e044710f19317.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/8608-e397dfae632fb839.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/9651.5057209db3881ec8.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/framework-428dc724d9086efb.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/main-04e4151d30f71ab2.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/_app-d8b8016d7bea506b.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/_error-0b1a861ffa2edde1.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/address-b7eca4e9b569fd1c.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/bookingreqpage-e8e1a6f68f8bb6c4.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/dashboard-1bdf95290ba665cd.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/home-6ee91d9bf555a563.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/index-ffda4f32514d6aa0.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/info-5a0660f1bea67378.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/itempage-69d6598aef5ec5da.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{
url: "/_next/static/chunks/pages/itempage/%5Bitemkey%5D-c2f6ebad6a59057d.js",
revision: "WcZyltu4AIEZdlepY3Peo",
},
{
url: "/_next/static/chunks/pages/items/%5Buser_lender%5D-33ac1a4b581b143a.js",
revision: "WcZyltu4AIEZdlepY3Peo",
},
{ url: "/_next/static/chunks/pages/itemswindow-706741772e4ee171.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/login-df75183f3fdaf6f4.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/mappage-95b6b631665d0b5d.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/newItem-76961819cc2fa4f2.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/orders-5637e34fa4aeb00c.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/privacypolicy-fea0a9e36d408ce0.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/profile-d750e0bec23d4699.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/searchpage-a20e60074cffe8c4.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/settings-fdcc39f57cd60718.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/signup-56863616abb5769b.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/splash-4020a016f3a18b60.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/taskpage-c2cea2257c510db0.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/welcome-b00b5fc8b217a709.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/wishlist-d8d72984251367c7.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/pages/workpage-dd025f82110469c5.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/polyfills-5cd94c89d3acac5f.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/chunks/webpack-bde62137e53dadca.js", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/css/4ac61f15fc19c268.css", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/css/6c1a23dd8a183dbb.css", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/media/layers-2x.9859cd12.png", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/media/layers.ef6db872.png", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/_next/static/media/marker-icon.d577052a.png", revision: "WcZyltu4AIEZdlepY3Peo" },
{ url: "/favicon.ico", revision: "666586677e60428aa5e58d13871736c7" },
{ url: "/firebase-messaging-sw.js", revision: "e387921962396472d67f290af1777d55" },
{ url: "/freebessimagelight.png", revision: "7e742e758c9028e8bd0c4345655e93c4" },
{ url: "/icon-192x192.png", revision: "ed26a1bbca33bba35e0e25bccec594f1" },
{ url: "/icon-256x256.png", revision: "ed2c6547ed3aeea9df44fe44bc30007f" },
{ url: "/icon-384x384.png", revision: "22a4a4214cd9cfa1b401091618ca0ac9" },
{ url: "/icon-512x512.png", revision: "562865edb386df86d7c72587c9096528" },
{ url: "/images/SMOR-192.png", revision: "3023f02d03ea538d8e3c39bdf0de383d" },
{ url: "/images/SMOR-512.png", revision: "c446f4acb68301e0d833488005e82085" },
{ url: "/images/no-image.png", revision: "12f9ee78f32722610c775ca7375c0c11" },
{ url: "/images/vercel.svg", revision: "26bf2d0adaf1028a4d4c6ee77005e819" },
{ url: "/manifest.json", revision: "d42be44d1990847c3d9aab15fbefdc00" },
{ url: "/marker-icon.png", revision: "3023f02d03ea538d8e3c39bdf0de383d" },
{ url: "/vercel.svg", revision: "26bf2d0adaf1028a4d4c6ee77005e819" },
],
{ ignoreURLParametersMatching: [] }
),
e.cleanupOutdatedCaches(),
e.registerRoute(
"/",
new e.NetworkFirst({
cacheName: "start-url",
plugins: [
{
cacheWillUpdate: async ({ request: e, response: s, event: t, state: c }) =>
s && "opaqueredirect" === s.type
? new Response(s.body, { status: 200, statusText: "OK", headers: s.headers })
: s,
},
],
}),
"GET"
),
e.registerRoute(
/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,
new e.CacheFirst({
cacheName: "google-fonts-webfonts",
plugins: [new e.ExpirationPlugin({ maxEntries: 4, maxAgeSeconds: 31536e3 })],
}),
"GET"
),
e.registerRoute(
/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,
new e.StaleWhileRevalidate({
cacheName: "google-fonts-stylesheets",
plugins: [new e.ExpirationPlugin({ maxEntries: 4, maxAgeSeconds: 604800 })],
}),
"GET"
),
e.registerRoute(
/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,
new e.StaleWhileRevalidate({
cacheName: "static-font-assets",
plugins: [new e.ExpirationPlugin({ maxEntries: 4, maxAgeSeconds: 604800 })],
}),
"GET"
),
e.registerRoute(
/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,
new e.StaleWhileRevalidate({
cacheName: "static-image-assets",
plugins: [new e.ExpirationPlugin({ maxEntries: 64, maxAgeSeconds: 86400 })],
}),
"GET"
),
e.registerRoute(
/\/_next\/image\?url=.+$/i,
new e.StaleWhileRevalidate({
cacheName: "next-image",
plugins: [new e.ExpirationPlugin({ maxEntries: 64, maxAgeSeconds: 86400 })],
}),
"GET"
),
e.registerRoute(
/\.(?:mp3|wav|ogg)$/i,
new e.CacheFirst({
cacheName: "static-audio-assets",
plugins: [new e.RangeRequestsPlugin(), new e.ExpirationPlugin({ maxEntries: 32, maxAgeSeconds: 86400 })],
}),
"GET"
),
e.registerRoute(
/\.(?:mp4)$/i,
new e.CacheFirst({
cacheName: "static-video-assets",
plugins: [new e.RangeRequestsPlugin(), new e.ExpirationPlugin({ maxEntries: 32, maxAgeSeconds: 86400 })],
}),
"GET"
),
e.registerRoute(
/\.(?:js)$/i,
new e.StaleWhileRevalidate({
cacheName: "static-js-assets",
plugins: [new e.ExpirationPlugin({ maxEntries: 32, maxAgeSeconds: 86400 })],
}),
"GET"
),
e.registerRoute(
/\.(?:css|less)$/i,
new e.StaleWhileRevalidate({
cacheName: "static-style-assets",
plugins: [new e.ExpirationPlugin({ maxEntries: 32, maxAgeSeconds: 86400 })],
}),
"GET"
),
e.registerRoute(
/\/_next\/data\/.+\/.+\.json$/i,
new e.StaleWhileRevalidate({
cacheName: "next-data",
plugins: [new e.ExpirationPlugin({ maxEntries: 32, maxAgeSeconds: 86400 })],
}),
"GET"
),
e.registerRoute(
/\.(?:json|xml|csv)$/i,
new e.NetworkFirst({
cacheName: "static-data-assets",
plugins: [new e.ExpirationPlugin({ maxEntries: 32, maxAgeSeconds: 86400 })],
}),
"GET"
),
e.registerRoute(
({ url: e }) => {
if (!(self.origin === e.origin)) return !1
const s = e.pathname
return !s.startsWith("/api/auth/") && !!s.startsWith("/api/")
},
new e.NetworkFirst({
cacheName: "apis",
networkTimeoutSeconds: 10,
plugins: [new e.ExpirationPlugin({ maxEntries: 16, maxAgeSeconds: 86400 })],
}),
"GET"
),
e.registerRoute(
({ url: e }) => {
if (!(self.origin === e.origin)) return !1
return !e.pathname.startsWith("/api/")
},
new e.NetworkFirst({
cacheName: "others",
networkTimeoutSeconds: 10,
plugins: [new e.ExpirationPlugin({ maxEntries: 32, maxAgeSeconds: 86400 })],
}),
"GET"
),
e.registerRoute(
({ url: e }) => !(self.origin === e.origin),
new e.NetworkFirst({
cacheName: "cross-origin",
networkTimeoutSeconds: 10,
plugins: [new e.ExpirationPlugin({ maxEntries: 32, maxAgeSeconds: 3600 })],
}),
"GET"
)
})

4
public/vercel.svg Normal file
View file

@ -0,0 +1,4 @@
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

1068
public/workbox-1846d813.js Normal file

File diff suppressed because it is too large Load diff

0
styles/Home.module.css Normal file
View file

143
styles/globals.css Normal file
View file

@ -0,0 +1,143 @@
html,
body {
padding: 0;
margin: 0;
/* background-color: #1f2833; */
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}
a {
color: inherit;
text-decoration: none;
}
@media all and (min-width: 680px) {
.Login {
padding: 60px 0;
}
.Login form {
margin: 0 auto;
max-width: 320px;
}
}
* {
box-sizing: border-box;
}
body {
/* display: flex; */
font-weight: 400;
font-family: sans-serif;
/*background: #12c2e9; /* fallback for old browsers */
/*background: -webkit-linear-gradient(to right, #f64f59, #c471ed, #12c2e9); /* Chrome 10-25, Safari 5.1-6 */
/*background: linear-gradient(to right, #f64f59, #c471ed, #12c2e9); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
}
body, html, .App, #root, .outer {
width: 100%;
min-height: 100%;
}
.navbar-light {
background-color: #ffffff;
box-shadow: 0px 14px 80px rgba(34, 35, 58, 0.2);
}
.outer {
display: flex;
/* justify-content: center; */
flex-direction: column;
/* margin: auto; */
text-align: left;
}
inner {
margin: auto;
background: #ffffff;
box-shadow: 0px 14px 80px rgba(34, 35, 58, 0.2);
padding: 40px 30px 45px 30px;
border-radius: 15px;
transition: all .3s;
}
.outer .form-control:focus {
border-color: #167bff;
box-shadow: none;
}
.outer h3 {
text-align: center;
margin: 0;
line-height: 1;
padding-bottom: 20px;
}
.custom-control-label {
font-weight: 400;
}
.forgot-password,
.forgot-password a {
text-align: right;
font-size: 13px;
padding-top: 10px;
color: #7f7d7d;
margin: 0;
}
.forgot-password a {
color: #167bff;
}
.nav{
border: 1 solid #45a29e !important;
}
.nav-link {
color: aqua !important;
border-bottom: 1px solid #45a29e !important;
}
.nav-link.active {
color:#1f2833 !important;
border-width: 0 !important;
}
@keyframes spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.loading-spinner {
width: 50px;
height: 50px;
border: 10px solid #66fcf1; /* Light grey */
border-top: 10px solid #45a29e; /* Black */
border-radius: 50%;
animation: spinner 1.5s linear infinite;
}
::-webkit-scrollbar {
display: none;
}

View file

@ -15,6 +15,12 @@ module.exports = {
"./src/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
screens: {
sm: "480px",
md: "768px",
lg: "976px",
xl: "1440px",
},
extend: {
colors: {
primary: {

252
testdata/items.json vendored Normal file
View file

@ -0,0 +1,252 @@
[
{
"title": "Lorem Ipsum 1",
"image_url": "https://example.com/image1.jpg",
"summary": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"title": "Lorem Ipsum 2",
"image_url": "https://example.com/image2.jpg",
"summary": "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
},
{
"title": "Lorem Ipsum 3",
"image_url": "https://example.com/image3.jpg",
"summary": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
},
{
"title": "Lorem Ipsum 4",
"image_url": "https://example.com/image4.jpg",
"summary": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
},
{
"title": "Lorem Ipsum 5",
"image_url": "https://example.com/image5.jpg",
"summary": "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
{
"title": "Lorem Ipsum 6",
"image_url": "https://example.com/image6.jpg",
"summary": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"title": "Lorem Ipsum 7",
"image_url": "https://example.com/image7.jpg",
"summary": "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
},
{
"title": "Lorem Ipsum 8",
"image_url": "https://example.com/image8.jpg",
"summary": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
},
{
"title": "Lorem Ipsum 9",
"image_url": "https://example.com/image9.jpg",
"summary": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
},
{
"title": "Lorem Ipsum 10",
"image_url": "https://example.com/image10.jpg",
"summary": "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
{
"title": "Lorem Ipsum 11",
"image_url": "https://example.com/image11.jpg",
"summary": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"title": "Lorem Ipsum 12",
"image_url": "https://example.com/image12.jpg",
"summary": "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
},
{
"title": "Lorem Ipsum 13",
"image_url": "https://example.com/image13.jpg",
"summary": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
},
{
"title": "Lorem Ipsum 14",
"image_url": "https://example.com/image14.jpg",
"summary": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
},
{
"title": "Lorem Ipsum 15",
"image_url": "https://example.com/image15.jpg",
"summary": "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
{
"title": "Lorem Ipsum 16",
"image_url": "https://example.com/image16.jpg",
"summary": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"title": "Lorem Ipsum 17",
"image_url": "https://example.com/image17.jpg",
"summary": "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
},
{
"title": "Lorem Ipsum 18",
"image_url": "https://example.com/image18.jpg",
"summary": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
},
{
"title": "Lorem Ipsum 19",
"image_url": "https://example.com/image19.jpg",
"summary": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
},
{
"title": "Lorem Ipsum 20",
"image_url": "https://example.com/image20.jpg",
"summary": "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
{
"title": "Lorem Ipsum 21",
"image_url": "https://example.com/image21.jpg",
"summary": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"title": "Lorem Ipsum 22",
"image_url": "https://example.com/image22.jpg",
"summary": "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
},
{
"title": "Lorem Ipsum 23",
"image_url": "https://example.com/image23.jpg",
"summary": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
},
{
"title": "Lorem Ipsum 24",
"image_url": "https://example.com/image24.jpg",
"summary": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
},
{
"title": "Lorem Ipsum 25",
"image_url": "https://example.com/image25.jpg",
"summary": "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
{
"title": "Lorem Ipsum 26",
"image_url": "https://example.com/image26.jpg",
"summary": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"title": "Lorem Ipsum 27",
"image_url": "https://example.com/image27.jpg",
"summary": "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
},
{
"title": "Lorem Ipsum 28",
"image_url": "https://example.com/image28.jpg",
"summary": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
},
{
"title": "Lorem Ipsum 29",
"image_url": "https://example.com/image29.jpg",
"summary": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
},
{
"title": "Lorem Ipsum 30",
"image_url": "https://example.com/image30.jpg",
"summary": "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
{
"title": "Lorem Ipsum 31",
"image_url": "https://example.com/image31.jpg",
"summary": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"title": "Lorem Ipsum 32",
"image_url": "https://example.com/image32.jpg",
"summary": "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
},
{
"title": "Lorem Ipsum 33",
"image_url": "https://example.com/image33.jpg",
"summary": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
},
{
"title": "Lorem Ipsum 34",
"image_url": "https://example.com/image34.jpg",
"summary": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
},
{
"title": "Lorem Ipsum 35",
"image_url": "https://example.com/image35.jpg",
"summary": "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
{
"title": "Lorem Ipsum 36",
"image_url": "https://example.com/image36.jpg",
"summary": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"title": "Lorem Ipsum 37",
"image_url": "https://example.com/image37.jpg",
"summary": "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
},
{
"title": "Lorem Ipsum 38",
"image_url": "https://example.com/image38.jpg",
"summary": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
},
{
"title": "Lorem Ipsum 39",
"image_url": "https://example.com/image39.jpg",
"summary": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
},
{
"title": "Lorem Ipsum 40",
"image_url": "https://example.com/image40.jpg",
"summary": "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
{
"title": "Lorem Ipsum 41",
"image_url": "https://example.com/image41.jpg",
"summary": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"title": "Lorem Ipsum 42",
"image_url": "https://example.com/image42.jpg",
"summary": "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
},
{
"title": "Lorem Ipsum 43",
"image_url": "https://example.com/image43.jpg",
"summary": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
},
{
"title": "Lorem Ipsum 44",
"image_url": "https://example.com/image44.jpg",
"summary": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
},
{
"title": "Lorem Ipsum 45",
"image_url": "https://example.com/image45.jpg",
"summary": "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
{
"title": "Lorem Ipsum 46",
"image_url": "https://example.com/image46.jpg",
"summary": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"title": "Lorem Ipsum 47",
"image_url": "https://example.com/image47.jpg",
"summary": "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
},
{
"title": "Lorem Ipsum 48",
"image_url": "https://example.com/image48.jpg",
"summary": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
},
{
"title": "Lorem Ipsum 49",
"image_url": "https://example.com/image49.jpg",
"summary": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
},
{
"title": "Lorem Ipsum 50",
"image_url": "https://example.com/image50.jpg",
"summary": "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
}
]

39
themes.js Normal file
View file

@ -0,0 +1,39 @@
// export const CLR_HEAD = '#ffffff' ;
// export const CLR_RCARD1 = 'orange';
// export const CLR_RCARD2 = 'orange';
// export const CLR_RCARD3 = '#ffffff';
// export const CLR_RCARD4 = '#ffffff';
// export const CLR_FBAR = '#ffffff';
////////////////////////////////////////////////////////
// export const CLR_HEAD = '#1f2833' ;
// export const CLR_HEAD1 = '#1f2833' ;// 1f2833
// export const CLR_RCARD1 = '#45a29e'; //1F2833
// export const CLR_RCARD2 = '#66fcf1';
// export const CLR_RCARD3 = '#c5c6c7';
// export const CLR_FBAR = '#0b0c10';
////////////////////////////////////////
export const CLR_HEAD = "#1f2833"
export const CLR_HEAD1 = "#1f2833" // 1f2833
export const CLR_RCARD1 = "#45a29e" //1F2833
export const CLR_RCARD2 = "#66fcf1"
export const CLR_RCARD3 = "#c5c6c7"
export const CLR_FBAR = "#0b0c10"

View file

@ -25,6 +25,6 @@
}
]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.mjs", "jest.config.js", ".next/types/**/*.ts"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.mjs", "jest.config.js", ".next/types/**/*.ts", "next.config.js", "next.config.js"],
"exclude": ["node_modules"]
}

111
utils/auth.js Normal file
View file

@ -0,0 +1,111 @@
// utils/auth.js
import bcrypt from "bcryptjs"
import { jwtVerify, SignJWT } from "jose"
const secret = new TextEncoder().encode("Swe4g7c?UBm5Nrd96vhsVDtkyJFbqKMTm!TMw5BDRLtaCFAXNvbq?s4rGKQSZnUP")
///
async function generateToken(payload, expiresIn) {
const algo = "HS256"
const t = await new SignJWT(payload)
.setProtectedHeader({ alg: algo })
.setIssuedAt()
.setExpirationTime(expiresIn)
.sign(secret)
console.log(t)
return t
}
// Function to create both access and refresh tokens
export async function createTokens(userId) {
const accessTokenPayload = {
userId: userId,
// exp: Math.floor(Date.now() / 1000) + (15 * 60), // Access token expires in 15 minutes
// iss: 'your_issuer_here', // Replace with your actual issuer
// aud: 'your_audience_here', // Replace with your actual audience
purpose: "access", // Indicate the purpose of this token
}
const refreshTokenPayload = {
userId: userId,
// exp: Math.floor(Date.now() / 1000) + (7 * 24 * 60 * 60), // Refresh token expires in 7 days
// iss: 'your_issuer_here', // Replace with your actual issuer
// aud: 'your_audience_here', // Replace with your actual audience
purpose: "refresh", // Indicate the purpose of this token
}
const accessToken = await generateToken(accessTokenPayload, "15m") // 15 minutes expiry
const refreshToken = await generateToken(refreshTokenPayload, "2d") // 2 days expiry
return { accessToken, refreshToken }
}
///
export const hashPassword = async (password) => {
const salt = await bcrypt.genSalt(10)
return bcrypt.hash(password, salt)
}
export const verifyPassword = async (password, hashedPassword) => {
return bcrypt.compare(password, hashedPassword)
}
export const issueAccessToken = async (userId) => {
const algo = "HS256"
const accessTokenPayload = {
userId: userId,
// exp: Math.floor(Date.now() / 1000) + (15 * 60), // Access token expires in 15 minutes
// iss: 'your_issuer_here', // Replace with your actual issuer
// aud: 'your_audience_here', // Replace with your actual audience
purpose: "access", // Indicate the purpose of this token
}
const accessToken = await generateToken(accessTokenPayload, "1m") // 15 minutes expiry
return accessToken
}
// This function verifies a refresh token using a shared secret key
export async function verifyRefreshToken(refreshToken) {
try {
// Verify the refresh token using the shared secret key
const { payload, protectedHeader } = await jwtVerify(refreshToken, secret)
console.log(payload)
// Ensure the token has necessary fields and is not expired
if (!payload.userId) {
throw new Error("Invalid token format")
}
// Optionally, you can also check if the token is intended for refresh purposes only
if (payload.purpose !== "refresh") {
throw new Error("Invalid token purpose")
}
// Token is valid, return the decoded token
return payload
} catch (error) {
console.log(error)
throw new Error("Invalid refresh token")
}
}
export async function refreshAccessToken(refreshToken) {
try {
const response = await fetch("http://localhost:3000/api/refreshtoken", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ refreshToken }),
})
const data = await response.json()
return data.accessToken
} catch (error) {
console.error("Error refreshing access token:", error)
throw new Error("Failed to refresh access token")
}
}

567
utils/categories.js Normal file
View file

@ -0,0 +1,567 @@
export const categoriesjson = [
{
category: "Clothes men",
subcategories: [
{
item: "suits",
hassub: 0,
},
],
},
{
category: "Cookwares",
subcategories: [
{
item: "Kadhai",
hassub: 0,
},
{
item: "Tawa",
hassub: 0,
},
{
item: "Mixer",
hassub: 0,
},
],
},
{
category: "Kitchen Equipments",
subcategories: [
{
item: "Fryer",
hassub: 0,
},
{
item: "Oven",
hassub: 0,
},
{
item: "Minifridge",
hassub: 0,
},
],
},
{
category: "Holidays & travel",
subcategories: [
{
item: "Camping",
hassub: 1,
subs: ["Tents", "Camping Chairs", "Cooking Equipment", "Other Camping Equipments"],
},
{
item: "Luggage",
hassub: 1,
subs: ["Suitcases", "Travellers Backpacks", "Backpacks", "Other Luggage"],
},
{
item: "Pool/Sea Toys",
hassub: 0,
},
{
item: "Other Holiday & Travel",
hassub: 0,
},
],
},
{
category: "Party & events",
subcategories: [
{
item: "Special Effects",
hassub: 1,
subs: ["Disco Lighting, Lasers & Strobe", "Bubble Machines", "Smoke MAchines", "Other Special Effects"],
},
{
item: "Staging",
hassub: 0,
},
{
item: "Entertainment",
hassub: 1,
subs: ["Karaoke Equipment", "Photo Booths", "Adult Party Games", "Other Event Entertainment"],
},
{
item: "Catering Equipment",
hassub: 1,
subs: [
"Display Cabinets / Fridges",
"Hot Plates",
"Walk-in Fridge Trailers",
"Cooking Equipment",
"Cutlery, Crockery & Glassware",
"Other CAtering Equipment",
],
},
{
item: "Special Effects",
hassub: 1,
subs: ["Wedding Decorations", "Christmas Decorations", "Centerpieces", "Other Decorations"],
},
{
item: "Portaloos",
hassub: 0,
},
{
item: "Event Furniture",
hassub: 1,
subs: [
"Seating",
"Bars",
"Smoke MAchines",
"LED furniture",
"Tables",
"Furniture Accessories",
"Other Furniture",
],
},
{
item: "Tents & Marquees",
hassub: 1,
subs: ["Gazebose", "Marquees", "MArquee Accessories"],
},
{
item: "Event Lighting",
hassub: 1,
subs: [
"DJ, Disco & Stage Lights",
"Fairy & Festoon Lights",
"Light-up Numbers & Letters",
"Other Event Lighting",
],
},
{
item: "Party Package Deals",
hassub: 0,
},
{
item: "Other PArty",
hassub: 0,
},
],
},
{
category: "Film & Photography",
subcategories: [
{
item: "Cameras",
hassub: 1,
subs: [
"DSLR Cameras",
"Digital Cinema Cameras",
"Camcorders",
"GoPros & Headcams",
"Film Cameras",
"Polaroid",
"360 Cameras",
"Mirrorless Cameras",
"Other Cameras",
],
},
{
item: "Lenses",
hassub: 1,
subs: [
"Cinema Prime Lenses",
"DLSR Lenses",
"Medium Format Lenses",
"Mirrorless Lenses",
"Lens Accessories",
"Other Lenses",
],
},
{
item: "Accessories",
hassub: 1,
subs: [
"Tripods & Heads",
"Rigs / Stabiliserws / Gimbals",
"Bags and Storage",
"Dollies / Sliders",
"Grips / Stands / Clamps",
"Flashes",
"Follow Focus & Lens Support",
"Other Accessories",
],
},
{
item: "Lighting",
hassub: 1,
subs: [
"Continuous Lighting",
"Backgrounds & Supports",
"Stands , Mounts & Accessories",
"Otehr Film & Photography Lighting",
],
},
{
item: "Cameras With Operators",
hassub: 0,
},
{
item: "Photography Studios",
hassub: 0,
},
{
item: "Camera Package Deals / Kits",
hassub: 0,
},
{
item: "Other Film & Photography",
hassub: 0,
},
],
},
{
category: "Drones",
subcategories: [
{
item: "DJI Drones",
hassub: 1,
subs: [
"Spark Series",
"Mavic Series",
"Phantom Series",
"Inspire Series",
"Industrial Drones",
"Other DJI Drones",
],
},
{
item: "Drones With Operators",
hassub: 0,
subs: [],
},
{
item: "Drone Accessories",
hassub: 1,
subs: ["Cases & Bags", "Batteries", "Other Drone Accessories"],
},
{
item: "Drone PAckage Deals",
hassub: 0,
subs: [],
},
{
item: "Other Drones",
hassub: 0,
subs: [],
},
],
},
{
category: "Sports",
subcategories: [
{
item: "Racket Sports",
hassub: 1,
subs: ["Squash", "Tennis", "Badminton", "Table Tennis", "Other Racket Sport Equipment"],
},
{
item: "Gym Equipment",
hassub: 1,
subs: ["Free Weights", "Gym MAchines", "Other Gym Equipments"],
},
{
item: "Water Sports",
hassub: 1,
subs: [
"Swimming Goggles",
"Wetsuits",
"Snorkelling Equipment",
"Kiteboarding Equipment",
"Sailing & Boats",
"Kayak & Canoes",
"Surfboards",
"Windsurfing Equipment",
"Jet Skis",
],
},
{
item: "Winter Sports",
hassub: 1,
subs: [
"Skis",
"Snowboards",
"Ski Boots",
"Snowboard Boots",
"Ski & Snowboard Clothing",
"Ski & Snowboard Accessories",
],
},
{
item: "Outdoor Sports",
hassub: 1,
subs: ["Golf", "Rugby", "Cricket", "Football", "Triathalon", "Hiking", "Surfboards", "Other Outdoor Sports"],
},
{
item: "Gym Equipment",
hassub: 1,
subs: ["Free Weights", "Gym MAchines", "Other Gym Equipments"],
},
{
item: "Country Sports",
hassub: 1,
subs: ["Fishing Equipment", "Horse Riding Equipment", "Shooting Equipment"],
},
{
item: "Sports Package Deals",
hassub: 0,
},
{
item: "Other Sports",
hassub: 0,
},
],
},
{
category: "Kids",
subcategories: [
{
item: "Babies & Toddlers",
hassub: 1,
subs: [
"Baby Car Seats",
"Booster Seats",
"Baby Carriers & Backpacks",
"Prams & Pushchairs",
"Highchairs",
"Bouncers / Swings",
"Breast Pumps",
"Cots",
"Baby Monitors",
"Play Pens",
"Bottle Sterilisers",
"Baby Toys",
"Baby Toys",
"Other Babies & Toddlers",
],
},
{
item: "Kids",
hassub: 1,
subs: [
"Hoverboards, Scooters & Rollerblades",
"Water Toys",
"Bikes",
"Beanbags",
"Other Toys",
"Lawn Toys",
"Other Kids",
],
},
{
item: "Kids Parties",
hassub: 1,
subs: ["Bouncy Castles", "Inflatables", "Soft Play", "Other Kids Parties"],
},
{
item: "Kids & Baby Package Deals",
hassub: 0,
},
{
item: "Other Kids & Baby",
hassub: 0,
},
],
},
{
category: "Audio Visual Equipment",
subcategories: [
{
item: "PA Systems",
hassub: 1,
subs: ["Small Venues (<100 people)", "Medium Venues (100-300 people)", "Large Venues (300+ people)"],
},
{
item: "Speakers",
hassub: 1,
subs: ["Speaker Systems", "Portable Speakers", "Moniter Systems", "Other Speakers"],
},
{
item: "Microphones",
hassub: 1,
subs: [
"Recording Mics",
"Wireless Mics / Systems",
"Condenser Mics",
"Condenser Mics",
"USB Mics",
"Standard Mics",
"Other Mics",
],
},
{
item: "Recording Equipment",
hassub: 1,
subs: [
"Recorders",
"Studio, Samplers & Sequencers",
"Interfaces, Consoles & Controllers",
"Headphones",
"Sound Blimps",
"Other Recording Equipment",
],
},
{
item: "Recording Studios",
hassub: 0,
},
{
item: "Audio Visual PAckage Deals",
hassub: 0,
},
{
item: "Other Audio Visual",
hassub: 0,
},
],
},
{
category: "Dj Equipment",
subcategories: [
{
item: "Decks & Turntables",
hassub: 0,
},
{
item: "Mixers",
hassub: 0,
},
{
item: "Controllers",
hassub: 0,
},
{
item: "DJ Equipment with Operator",
hassub: 0,
},
{
item: "DJ Equipment Package Deals",
hassub: 0,
},
{
item: "Other DJ Equipment",
hassub: 0,
},
],
},
{
category: "Electronics",
subcategories: [
{
item: "Computer",
hassub: 1,
subs: [
"Laptops",
"Ipads & Tablets",
"Desktops",
"PC Moniters",
"Printers & Scanners",
"Servers",
"Computer Accessories",
"Other Computer",
],
},
{
item: "Entertainment & Gaming",
hassub: 1,
subs: [
"TVs",
"TV Accessories",
"Kindles",
"Xbox Consoles & Games",
"Playstation Consoles & Games",
"Nintendo Consoles & Games",
"Other Entertainment & Gaming",
],
},
{
item: "Virtual Reality",
hassub: 1,
subs: ["Headsets", "Games", "Other Virtual Reality"],
},
{
item: "Personal Electronics",
hassub: 1,
subs: [
"Mobile Phones",
"Smartwatches",
"Headphones",
"Fitbits & Fitness Electronics",
"Other Personal Electronics",
],
},
{
item: "Electronics Package Deals",
hassub: 0,
},
{
item: "Other Electronics",
hassub: 0,
},
],
},
{
category: "Musical Instrument",
subcategories: [
{
item: "Guitars",
hassub: 1,
subs: ["Acoustic", "Bass", "Electric", "Pedals", "Guitar Accessories", "Other Guitars"],
},
{
item: "Amps",
hassub: 1,
subs: ["Guitar Amps", "Bass Amps", "Piano Amps", "Other Amps"],
},
{
item: "Keyboards & Synthesisers",
hassub: 1,
subs: ["Electric Keyboards", "Synthesisers", "Pianos", "Other Keyboards"],
},
{
item: "String Instruments",
hassub: 1,
subs: ["Violins", "Double Bass", "Banjos", "Ouds", "Mandolins", "Ukuele", "Other String Instruments"],
},
{
item: "Brass",
hassub: 1,
subs: ["Trumpet", "Trombone", "Cornet", "Other Brass"],
},
{
item: "Woodwind",
hassub: 1,
subs: ["Saxophone", "Fluter", "Carinet", "Recorders", "Other Woodwind"],
},
{
item: "Percussion",
hassub: 1,
subs: ["Drums", "Cymbals", "Other Percussion"],
},
{
item: "Instrument Accessories",
hassub: 0,
},
{
item: "Musical Instruments Deals",
hassub: 0,
},
{
item: "Other Musical Instrument",
hassub: 0,
},
],
},
{
category: "Others",
subcategories: [
{
item: "Other things",
hassub: 0,
},
],
},
]

28
utils/themes.js Normal file
View file

@ -0,0 +1,28 @@
import { extendTheme } from "@chakra-ui/react"
const colors = {
primary: {
100: "#B5FCF1",
200: "#27EF96",
300: "#10DE82",
400: "#0EBE6F",
500: "#0CA25F",
600: "#0A864F",
700: "#086F42",
800: "#075C37",
900: "#064C2E",
},
}
const breakpoints = {
base: "0em", // 0px
sm: "30em", // ~480px. em is a relative unit and is dependant on the font size.
md: "48em", // ~768px
lg: "62em", // ~992px
xl: "80em", // ~1280px
"2xl": "96em", // ~1536px
}
const customTheme = extendTheme({ colors, breakpoints })
export default customTheme

0
worker/index.js Normal file
View file

8007
yarn.lock

File diff suppressed because it is too large Load diff