├── src ├── css │ ├── tailwind │ │ ├── _base.css │ │ ├── _components.css │ │ └── _utilities.css │ └── main.css ├── components │ ├── react-swipeable-views-react-18-fix.d.ts │ ├── GoogleAddress.tsx │ ├── SignWithGoogle.tsx │ ├── ProgressBar.tsx │ ├── ProgressPane.tsx │ ├── WaitingLocker.tsx │ ├── ProgressIndicator.tsx │ ├── PortalConsider.tsx │ ├── Footer.tsx │ ├── NotificationComponent.tsx │ ├── MyTab.tsx │ ├── AlertContainers.tsx │ ├── UploadLogo.tsx │ ├── Login.tsx │ ├── UserInfoAvatar.tsx │ ├── PortalClass.tsx │ ├── Header.tsx │ ├── PortalSummaryB.tsx │ ├── PortalSummaryA.tsx │ ├── Modal.tsx │ └── SignUp.tsx ├── pages │ ├── api │ │ ├── logout.ts │ │ ├── classes.ts │ │ ├── searchkeywords.ts │ │ ├── users.ts │ │ ├── create-checkout-session.ts │ │ ├── login.ts │ │ ├── _testApi │ │ │ ├── testforstrsim.ts │ │ │ └── testsearch.ts │ │ ├── upload.tsx │ │ ├── google.ts │ │ ├── products.ts │ │ ├── chatsocket.ts │ │ └── sendmail.ts │ ├── index.tsx │ ├── adminchat.tsx │ ├── payres │ │ ├── fail.tsx │ │ └── success.tsx │ ├── _document.tsx │ ├── dashboard.tsx │ ├── auth.tsx │ ├── profile.tsx │ ├── adminusers.tsx │ ├── _app.tsx │ ├── consider.tsx │ ├── checkout.tsx │ ├── apply.tsx │ └── summary.tsx ├── models │ ├── keywordsModel.js │ ├── classesModel.js │ ├── productsModel.js │ └── usersModel.js ├── controllers │ ├── products.tsx │ └── users.tsx ├── db │ ├── mongodb.js │ ├── users.ts │ └── mysqldb.js ├── layout │ ├── TMCheckLayout.tsx │ ├── ServerSidePropsAuthorized.ts │ └── ServerSidePropsAdminAuthorized.ts ├── store │ ├── store.tsx │ └── reducer.tsx └── types │ ├── searchs.tsx │ ├── interface.tsx │ └── utils.tsx ├── .eslintrc.json ├── public ├── 01.png ├── 02.png ├── tm.ico ├── alert.png ├── bread.png ├── clock.png ├── nbn.png ├── shoes.png ├── dollar.png ├── google.png ├── message.gif ├── message.png ├── triple.png ├── typing.gif ├── typing2.gif ├── ww-logo.png ├── back-start.jpg ├── design-1.jpg ├── loading0.gif ├── loading1.gif ├── loading2.gif ├── loading3.gif ├── loading4.gif ├── loading5.gif ├── loading6.gif ├── loading7.gif ├── loading8.gif ├── no-avatar.png ├── see-this.jpg ├── see-this.png ├── start_back.jpg ├── back-image.avif ├── back-start-2.jpg ├── down-circle.png ├── syed-mosawi.png ├── blog-recent-2.jpg ├── blog-recent-3.jpg ├── code_developer.jpg ├── icons8-help-94.png ├── trademarktoday.ico ├── trademarktoday.png ├── icons8-popular-94.png ├── trademarktoday-badge.ico ├── trademarktoday_logo.png ├── vercel.svg ├── user-svgrepo-com.svg ├── play-video.svg ├── next.svg ├── exit-logout-svgrepo-com.svg ├── settings-cogwheel-svgrepo-com.svg └── tmchecker.svg ├── postcss.config.js ├── .env.example ├── .gitignore ├── tsconfig.json ├── next.config.mjs ├── tailwind.config.js ├── .all-contributorsrc ├── server.js ├── package.json └── README.md /src/css/tailwind/_base.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | -------------------------------------------------------------------------------- /src/css/tailwind/_components.css: -------------------------------------------------------------------------------- 1 | @tailwind components; 2 | -------------------------------------------------------------------------------- /src/css/tailwind/_utilities.css: -------------------------------------------------------------------------------- 1 | @tailwind utilities; 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /public/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/01.png -------------------------------------------------------------------------------- /public/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/02.png -------------------------------------------------------------------------------- /public/tm.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/tm.ico -------------------------------------------------------------------------------- /public/alert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/alert.png -------------------------------------------------------------------------------- /public/bread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/bread.png -------------------------------------------------------------------------------- /public/clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/clock.png -------------------------------------------------------------------------------- /public/nbn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/nbn.png -------------------------------------------------------------------------------- /public/shoes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/shoes.png -------------------------------------------------------------------------------- /public/dollar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/dollar.png -------------------------------------------------------------------------------- /public/google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/google.png -------------------------------------------------------------------------------- /public/message.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/message.gif -------------------------------------------------------------------------------- /public/message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/message.png -------------------------------------------------------------------------------- /public/triple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/triple.png -------------------------------------------------------------------------------- /public/typing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/typing.gif -------------------------------------------------------------------------------- /public/typing2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/typing2.gif -------------------------------------------------------------------------------- /public/ww-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/ww-logo.png -------------------------------------------------------------------------------- /public/back-start.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/back-start.jpg -------------------------------------------------------------------------------- /public/design-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/design-1.jpg -------------------------------------------------------------------------------- /public/loading0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/loading0.gif -------------------------------------------------------------------------------- /public/loading1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/loading1.gif -------------------------------------------------------------------------------- /public/loading2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/loading2.gif -------------------------------------------------------------------------------- /public/loading3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/loading3.gif -------------------------------------------------------------------------------- /public/loading4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/loading4.gif -------------------------------------------------------------------------------- /public/loading5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/loading5.gif -------------------------------------------------------------------------------- /public/loading6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/loading6.gif -------------------------------------------------------------------------------- /public/loading7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/loading7.gif -------------------------------------------------------------------------------- /public/loading8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/loading8.gif -------------------------------------------------------------------------------- /public/no-avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/no-avatar.png -------------------------------------------------------------------------------- /public/see-this.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/see-this.jpg -------------------------------------------------------------------------------- /public/see-this.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/see-this.png -------------------------------------------------------------------------------- /public/start_back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/start_back.jpg -------------------------------------------------------------------------------- /src/components/react-swipeable-views-react-18-fix.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'react-swipeable-views-react-18-fix'; -------------------------------------------------------------------------------- /public/back-image.avif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/back-image.avif -------------------------------------------------------------------------------- /public/back-start-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/back-start-2.jpg -------------------------------------------------------------------------------- /public/down-circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/down-circle.png -------------------------------------------------------------------------------- /public/syed-mosawi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/syed-mosawi.png -------------------------------------------------------------------------------- /public/blog-recent-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/blog-recent-2.jpg -------------------------------------------------------------------------------- /public/blog-recent-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/blog-recent-3.jpg -------------------------------------------------------------------------------- /public/code_developer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/code_developer.jpg -------------------------------------------------------------------------------- /public/icons8-help-94.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/icons8-help-94.png -------------------------------------------------------------------------------- /public/trademarktoday.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/trademarktoday.ico -------------------------------------------------------------------------------- /public/trademarktoday.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/trademarktoday.png -------------------------------------------------------------------------------- /public/icons8-popular-94.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/icons8-popular-94.png -------------------------------------------------------------------------------- /public/trademarktoday-badge.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/trademarktoday-badge.ico -------------------------------------------------------------------------------- /public/trademarktoday_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcrazysteven/Trade-Mark-Today/HEAD/public/trademarktoday_logo.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | 'postcss-import': {}, 4 | 'postcss-nesting':{}, 5 | tailwindcss: {}, 6 | autoprefixer: {}, 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /src/pages/api/logout.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Request, Response } from "express"; 3 | 4 | export default function handler(req: Request, res: Response) { 5 | // res.clearCookie('token').redirect('/') 6 | res.setHeader('Set-Cookie', 'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;').redirect('/') 7 | } -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | NODE_ENV=development 2 | PORT=80 3 | MONGO_URI= 4 | GMAIL_USER= 5 | GMAIL_AUTH= 6 | NEXT_PUBLIC_CLIENT_ID= 7 | CLIENT_ID= 8 | NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY= 9 | stripeSecretKey= 10 | CLIENT_SECRET= 11 | NEXT_PUBLIC_REDIRECT_URI= 12 | REDIRECT_URI= 13 | NEXT_PUBLIC_GOOGLE_API_KEY='AIzaSyCfqtgxxZEmp4GpPw71497rpF4I9Y6jYh0' -------------------------------------------------------------------------------- /src/models/keywordsModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const keywordsSchema = new mongoose.Schema({ 4 | keyword: { 5 | type: String, 6 | required: true, 7 | }, 8 | }, 9 | { timestamps: false } 10 | ); 11 | const keywordsModel = mongoose.models.keywords || mongoose.model("keywords", keywordsSchema); 12 | 13 | export default keywordsModel -------------------------------------------------------------------------------- /src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'next/router'; 2 | import { useEffect, type ReactElement } from 'react' 3 | import TMCheckLayout from '../layout/TMCheckLayout'; 4 | 5 | const Index = () => { 6 | const router = useRouter(); 7 | 8 | useEffect(() => { 9 | router.push('/start'); 10 | }, []); 11 | 12 | return

This page will be redirected...

; 13 | } 14 | 15 | Index.getLayout = TMCheckLayout; 16 | 17 | export default Index; -------------------------------------------------------------------------------- /src/controllers/products.tsx: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import productsModel from '@/models/productsModel'; 3 | 4 | export const find = async (req: Request, res: Response) => { 5 | const list = await productsModel.find(); 6 | res.status(200).json({ 7 | success: true, 8 | data: list, 9 | }); 10 | } 11 | 12 | export const insert = async (req: Request, res: Response) => { 13 | const user = await productsModel.create(req.body); 14 | res.status(201).json([user]) 15 | } -------------------------------------------------------------------------------- /src/pages/adminchat.tsx: -------------------------------------------------------------------------------- 1 | import TMCheckLayout from '../layout/TMCheckLayout'; 2 | import ChatAdmin from '@/components/ChatAdmin'; 3 | import ServerSidePropsAdminAuthorized from '@/layout/ServerSidePropsAdminAuthorized'; 4 | 5 | const AdminChat = ({ email }: { email: string }) => { 6 | return ( 7 | <> 8 | 9 | 10 | ) 11 | } 12 | 13 | AdminChat.getLayout = TMCheckLayout; 14 | 15 | export const getServerSideProps = ServerSidePropsAdminAuthorized; 16 | 17 | export default AdminChat; -------------------------------------------------------------------------------- /src/models/classesModel.js: -------------------------------------------------------------------------------- 1 | 2 | const mongoose = require("mongoose"); 3 | 4 | const classSchema = new mongoose.Schema({ 5 | class: { 6 | type: Number, 7 | required: true, 8 | }, 9 | description: { 10 | type: String, 11 | required: true, 12 | }, 13 | title: { 14 | type: String, 15 | required: true, 16 | } 17 | }, 18 | { timestamps: false } 19 | ); 20 | 21 | const proclassModel = mongoose.models.classes || mongoose.model("classes", classSchema); 22 | 23 | export default proclassModel; -------------------------------------------------------------------------------- /src/models/productsModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const productsSchema = new mongoose.Schema({ 4 | class: { 5 | type: Number, 6 | required: true, 7 | }, 8 | product: { 9 | type: String, 10 | required: true, 11 | }, 12 | score:Number, 13 | }, 14 | { timestamps: false } 15 | ); 16 | productsSchema.index({ product: 'text' }); 17 | const ProductsModel = mongoose.models.products || mongoose.model("products", productsSchema); 18 | 19 | export default ProductsModel -------------------------------------------------------------------------------- /src/db/mongodb.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const connectToMongodb = async () => { 4 | try { 5 | const database = await mongoose.connect(process.env.MONGO_URI, { 6 | useNewUrlParser: true, 7 | useUnifiedTopology: true, 8 | // useCreateIndex: true, 9 | // useFindAndModify: false, 10 | }); 11 | console.log("MongoDB connected"); 12 | } catch (error) { 13 | console.log(`Error connecting to DB: ${(error).message}`); 14 | process.exit(1); 15 | } 16 | }; 17 | 18 | module.exports = connectToMongodb; -------------------------------------------------------------------------------- /src/layout/TMCheckLayout.tsx: -------------------------------------------------------------------------------- 1 | import type { AppProps } from 'next/app' 2 | import { ReactElement, useEffect } from "react"; 3 | import Header from "../components/Header"; 4 | import Footer from "../components/Footer"; 5 | 6 | const TMCheckLayout = (page: ReactElement, pageProps: AppProps) => { 7 | return ( 8 |
9 |
10 |
11 | {page} 12 |
13 |
14 |
15 | ) 16 | } 17 | 18 | export default TMCheckLayout -------------------------------------------------------------------------------- /.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 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | /public/uploads 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env 29 | .env.example 30 | *.local 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/GoogleAddress.tsx: -------------------------------------------------------------------------------- 1 | import Autocomplete from "react-google-autocomplete"; 2 | 3 | const GOOGLE_API_KEY = process.env.NEXT_PUBLIC_GOOGLE_API_KEY; 4 | 5 | const GoogleAddress = ({ className, onPlaceChange }: { className?: string, onPlaceChange: (_: string) => void }) => { 6 | return ( 7 | <> 8 | onPlaceChange(e.currentTarget.value)} 12 | className={`${className} `} 13 | onPlaceSelected={(place) => onPlaceChange(place)} 14 | /> 15 | 16 | ) 17 | } 18 | 19 | export default GoogleAddress; -------------------------------------------------------------------------------- /src/store/store.tsx: -------------------------------------------------------------------------------- 1 | import { ContextType, PiniaContextType, StateType } from '@/types/interface'; 2 | import { createContext } from 'react'; 3 | export const initialState: StateType = { 4 | otp: false, 5 | code: '', 6 | waiting: false, 7 | formData: { 8 | email: '', 9 | name: '', 10 | password: '', 11 | ACN: '', 12 | address: '', 13 | phone_number: '' 14 | } 15 | } 16 | export const OTPStore = createContext({ 17 | otpState: initialState, 18 | dispatchOtpState: (_: {}) => { } 19 | }); 20 | export const PiniaStore = createContext({ 21 | pinia: {}, 22 | setPinia: (_: {}) => { } 23 | }) -------------------------------------------------------------------------------- /src/models/usersModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const UsersSchema = new mongoose.Schema({ 4 | email: { 5 | type: String, 6 | required: true, 7 | }, 8 | name: { 9 | type: String, 10 | }, 11 | ACN: { 12 | type: String, 13 | }, 14 | phone_number: { 15 | type: String, 16 | }, 17 | address: { 18 | type: String, 19 | }, 20 | password: { 21 | type: String, 22 | }, 23 | given_name: { 24 | type: String, 25 | }, 26 | family_name: { 27 | type: String, 28 | }, 29 | picture: { 30 | type: String, 31 | }, 32 | }, 33 | { timestamps: true } 34 | ); 35 | const UsersModel = mongoose.models.users || mongoose.model('users', UsersSchema); 36 | 37 | export default UsersModel -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./src/*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import('next').NextConfig} 3 | */ 4 | const nextConfig = { 5 | basePath: "",//"/" 6 | // async redirects() { 7 | // return [ 8 | // { 9 | // source: '/', 10 | // destination: '/app', 11 | // basePath: false, 12 | // permanent: false 13 | // } 14 | // ] 15 | // }, 16 | devIndicators: { 17 | autoPrerender: false, 18 | }, 19 | // serverOptions: { 20 | // secure: true, 21 | // key: fs.readFileSync('key.pem'), 22 | // cert: fs.readFileSync('cert.pem'), 23 | // }, 24 | images: { 25 | unoptimized: true, 26 | remotePatterns: [ 27 | { 28 | protocol: 'https', 29 | hostname: 'static.justboil.me', 30 | }, 31 | ], 32 | }, 33 | } 34 | 35 | export default nextConfig -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | mode: 'jit', 4 | // These paths are just examples, customize them to match your project structure 5 | purge: [ 6 | './public/**/*.html', 7 | './src/**/*.{js,jsx,ts,tsx,vue}', 8 | ], 9 | content: [ 10 | './src/pages/**/*.{js,ts,jsx,tsx,mdx}', 11 | './src/components/**/*.{js,ts,jsx,tsx,mdx}', 12 | './src/app/**/*.{js,ts,jsx,tsx,mdx}', 13 | ], 14 | theme: { 15 | extend: { 16 | backgroundImage: { 17 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 18 | 'gradient-conic': 19 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 20 | }, 21 | }, 22 | fontFamily: { 23 | 'mont': ['Montserrat', 'sans-serif'], 24 | }, 25 | }, 26 | plugins: [], 27 | } 28 | -------------------------------------------------------------------------------- /public/user-svgrepo-com.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 10 | -------------------------------------------------------------------------------- /src/components/SignWithGoogle.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import Link from "next/link"; 3 | const SignWithGoogle = () => { 4 | const GOOGLE_AUTH_URL = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${process.env.NEXT_PUBLIC_CLIENT_ID}&response_type=code&scope=https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile&redirect_uri=${process.env.NEXT_PUBLIC_REDIRECT_URI}`; 5 | 6 | return ( 7 | 8 | 12 | 13 | ) 14 | } 15 | export default SignWithGoogle; -------------------------------------------------------------------------------- /src/pages/payres/fail.tsx: -------------------------------------------------------------------------------- 1 | import ServerSidePropsAuthorized from '@/layout/ServerSidePropsAuthorized'; 2 | import Chat from '@/components/Chat'; 3 | import TMCheckLayout from '@/layout/TMCheckLayout'; 4 | import { useRouter } from 'next/router'; 5 | 6 | const Payfail = ({ email }: { email: string }) => { 7 | const router = useRouter(); 8 | const reasonNumber = router.query.reason as string; 9 | return ( 10 | <> 11 |
12 |
13 |

Payment Failed (reasonNumber: {reasonNumber})

14 |

Tell me why I failed to pay.

15 | 16 |
17 |
18 | 19 | ) 20 | } 21 | 22 | Payfail.getLayout = TMCheckLayout; 23 | 24 | export const getServerSideProps = ServerSidePropsAuthorized; 25 | 26 | export default Payfail; -------------------------------------------------------------------------------- /src/layout/ServerSidePropsAuthorized.ts: -------------------------------------------------------------------------------- 1 | import Cookies from 'cookies'; 2 | import jwt from 'jsonwebtoken' 3 | import { JWT_SIGN_KEY } from '@/types/utils'; 4 | import { Context, User } from '@/types/interface'; 5 | 6 | const ServerSidePropsAuthorized = (context: Context) => { 7 | const cookies = new Cookies(context.req, context.res); 8 | const token = cookies.get('token'); 9 | const tokenAsString = token?.toString() ?? ''; 10 | try { 11 | const decodedToken = jwt.verify(tokenAsString, JWT_SIGN_KEY) as { email: string }; 12 | // const user: User = decodedToken.user; // Extract the user object from the decoded token 13 | return { props: { email: decodedToken?.email } }; 14 | } catch (error) { 15 | return { 16 | redirect: { 17 | destination: '/auth', 18 | permanent: false, 19 | }, 20 | }; 21 | } 22 | 23 | } 24 | 25 | export default ServerSidePropsAuthorized -------------------------------------------------------------------------------- /src/pages/api/classes.ts: -------------------------------------------------------------------------------- 1 | 2 | import ClassesModel from "@/models/classesModel"; 3 | import { Request, Response } from "express"; 4 | import connectToMongodb from '@/db/mongodb'; 5 | 6 | export default async function handler(req: Request, res: Response) { 7 | connectToMongodb(); 8 | const { keywords } = req.body; 9 | try { 10 | if (req.method === 'GET') { 11 | const classes = await ClassesModel.find().sort({"class":1}); 12 | res.status(200).json({ 13 | success: true, 14 | data: classes 15 | }) 16 | } else { 17 | res.status(405).json({ 18 | success: false, 19 | data: "Method not allowed." 20 | }) 21 | } 22 | } catch (error) { 23 | console.log("API error", error); 24 | if (!res.headersSent) { 25 | res.status(200).json({ 26 | success: false, 27 | data: "Server error", 28 | }); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /public/play-video.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/css/main.css: -------------------------------------------------------------------------------- 1 | @import "tailwind/_base.css"; 2 | @import "tailwind/_components.css"; 3 | @import "tailwind/_utilities.css"; 4 | 5 | html { 6 | scroll-behavior: smooth; 7 | } 8 | 9 | body { 10 | font-family: Roboto, sans-serif !important; 11 | } 12 | 13 | html, 14 | body, 15 | #__next, 16 | #__next>div { 17 | height: 100%; 18 | } 19 | 20 | @keyframes badgeflowing { 21 | 0% { 22 | top: -8px; 23 | } 24 | 25 | 30% { 26 | top: -8px; 27 | } 28 | 29 | 33% { 30 | top: -64px; 31 | } 32 | 33 | 63% { 34 | top: -64px; 35 | } 36 | 37 | 66% { 38 | top: -124px; 39 | } 40 | 41 | 96% { 42 | top: -124px; 43 | } 44 | 45 | 100% { 46 | top: -176px; 47 | } 48 | } 49 | 50 | 51 | input:invalid { 52 | border: 2px solid red; 53 | outline: none; 54 | } 55 | 56 | .react-tel-input .invalid-number { 57 | border: 1px solid red !important; 58 | } 59 | 60 | ul.country-list { 61 | z-index: 100 !important; 62 | } 63 | 64 | input:disabled, 65 | textarea:disabled { 66 | cursor: not-allowed; 67 | ; 68 | } -------------------------------------------------------------------------------- /src/store/reducer.tsx: -------------------------------------------------------------------------------- 1 | import { ActionType, FormDataType, StateType } from "@/types/interface"; 2 | 3 | const reducer = (state: StateType, action: ActionType): StateType => { 4 | switch (action.type) { 5 | case "CHANGE_FORMDATA": 6 | return { 7 | ...state, 8 | formData: { ...state.formData, ...action.payload.value as { [key: string]: string; } } 9 | }; 10 | case "SET_OTPCODE": 11 | return { 12 | ...state, 13 | code: action.payload.value as string 14 | }; 15 | case "SHOW_OTPCODE": 16 | return { 17 | ...state, 18 | otp: action.payload.value as boolean 19 | }; 20 | case "SET_WAITING": 21 | return { 22 | ...state, 23 | waiting: action.payload.value as boolean 24 | }; 25 | default: 26 | throw new Error(`Unhandled action type: ${action.type}`); 27 | } 28 | } 29 | export default reducer; -------------------------------------------------------------------------------- /src/components/ProgressBar.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import LinearProgress, { LinearProgressProps } from '@mui/material/LinearProgress'; 3 | import Typography from '@mui/material/Typography'; 4 | import Box from '@mui/material/Box'; 5 | 6 | function LinearProgressWithLabel(props: LinearProgressProps & { value: number }) { 7 | return ( 8 | 9 | 10 | 11 | 12 | 13 | {`${Math.round( 14 | props.value, 15 | )}%`} 16 | 17 | 18 | ); 19 | } 20 | 21 | export default function ProgressLinearWithValueLabel({ setVar: { uploadProgress, setUploadProgress } }: { setVar: { uploadProgress: number, setUploadProgress: React.Dispatch> } }) { 22 | return ( 23 | 24 | 25 | 26 | ); 27 | } -------------------------------------------------------------------------------- /src/components/ProgressPane.tsx: -------------------------------------------------------------------------------- 1 | const ProgressPane = ({ className, title }: { 2 | className?: string 3 | title: string 4 | }) => { 5 | return ( 6 | <> 7 | 31 |
32 |

{title}

{/* whitespace-nowrap */} 33 |
34 | 35 | ) 36 | } 37 | 38 | export default ProgressPane -------------------------------------------------------------------------------- /src/pages/api/searchkeywords.ts: -------------------------------------------------------------------------------- 1 | import { getSynonyms, searchSimilarWordsFromKeywords } from "@/types/searchs"; 2 | import { Request, Response } from "express"; 3 | import connectToMongodb from '@/db/mongodb' 4 | 5 | export default async function handler(req: Request, res: Response) { 6 | connectToMongodb(); 7 | const { id, keyword } = req.query; 8 | try { 9 | if (req.method === 'GET') { 10 | let result; 11 | switch (id as string) { 12 | case '1': 13 | result = await searchSimilarWordsFromKeywords(keyword as string); 14 | break; 15 | case '2': 16 | result = await getSynonyms(keyword as string); 17 | break; 18 | default: 19 | break; 20 | } 21 | res.status(200).json(result) 22 | } else { 23 | res.status(405).json({ 24 | success: false, 25 | data: "Method not allowed." 26 | }) 27 | } 28 | } catch (error) { 29 | console.log("API error", error); 30 | if (!res.headersSent) { 31 | res.send(500).json({ 32 | success: false, 33 | data: "Server error", 34 | }); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/layout/ServerSidePropsAdminAuthorized.ts: -------------------------------------------------------------------------------- 1 | import Cookies from 'cookies'; 2 | import jwt from 'jsonwebtoken' 3 | import { ADMIN_LIST, JWT_SIGN_KEY } from '@/types/utils'; 4 | import { Context, User } from '@/types/interface'; 5 | 6 | const ServerSidePropsAdminAuthorized = (context: Context) => { 7 | const cookies = new Cookies(context.req, context.res); 8 | const token = cookies.get('token'); 9 | const tokenAsString = token?.toString() ?? ''; 10 | try { 11 | const decodedToken = jwt.verify(tokenAsString, JWT_SIGN_KEY) as { email: string }; 12 | // const user: User = decodedToken.user; // Extract the user object from the decoded token 13 | 14 | if (ADMIN_LIST.some(em => em === decodedToken?.email)) { 15 | return { props: { email: decodedToken?.email } }; 16 | } else { 17 | return { 18 | redirect: { 19 | destination: '/auth', 20 | permanent: false, 21 | }, 22 | }; 23 | } 24 | } catch (error) { 25 | return { 26 | redirect: { 27 | destination: '/auth', 28 | permanent: false, 29 | }, 30 | }; 31 | } 32 | 33 | } 34 | 35 | export default ServerSidePropsAdminAuthorized -------------------------------------------------------------------------------- /src/components/WaitingLocker.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | const WaitingLocker = ({ waiting, msg = "Waiting" }: { waiting: boolean, msg?: string }) => { 4 | 5 | return ( 6 |
24 |
25 | logo 26 | logo 27 |

{msg}...

28 |
29 |
30 | ) 31 | } 32 | 33 | export default WaitingLocker -------------------------------------------------------------------------------- /src/pages/api/users.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { find, findByEmail, insert, remove, update } from "@/controllers/users"; 3 | import connectToMongodb from '@/db/mongodb' 4 | 5 | export default function handler(req: Request, res: Response) { 6 | connectToMongodb(); 7 | try { 8 | if (req.method === 'GET') { 9 | const { email } = req.query; 10 | const emailAsString = email?.toString() ?? ''; 11 | if (emailAsString === '') { 12 | find(req, res); 13 | // res.status(304).json("Fetching user data not allowed.") 14 | } else { 15 | findByEmail({ req, res }, emailAsString); 16 | } 17 | } 18 | else if (req.method === 'POST') { 19 | insert(req, res); 20 | } else if (req.method === 'PUT') { 21 | update(req, res); 22 | } else if (req.method === 'DELETE') { 23 | remove(req, res); 24 | } else { 25 | res.status(405).json({ 26 | success: false, 27 | data: "Method not allowed." 28 | }) 29 | } 30 | } catch (error) { 31 | console.log("API error", error); 32 | if (!res.headersSent) { 33 | res.send(500).json({ 34 | success: false, 35 | data: "Server error", 36 | }); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/components/ProgressIndicator.tsx: -------------------------------------------------------------------------------- 1 | import ProgressPane from "./ProgressPane"; 2 | 3 | export const TMCheckerElement = () => { 4 | 5 | return ( 6 | 10 | ) 11 | } 12 | const ProgressIndicator = ({ stage }: { stage: number }) => { 13 | 14 | return ( 15 |
16 | 17 | 18 |
19 | = 1 ? "state-active" : ""}`} title="Getting started" /> 20 | = 2 ? "state-active" : ""}`} title="Choose trade mark" /> 21 | = 3 ? "state-active" : ""}`} title="Select goods or services" /> 22 | = 4 ? "state-active" : ""}`} title="Review results" /> 23 |
24 |
25 | ) 26 | } 27 | 28 | export default ProgressIndicator -------------------------------------------------------------------------------- /src/components/PortalConsider.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image" 2 | 3 | const PortalConsider = ({ title, message, category, img = "" }: { 4 | title: string 5 | message: string 6 | category?: string 7 | img?: string 8 | }) => { 9 | 10 | return ( 11 |
12 |
13 |

{title}

14 |

{message}

15 |
16 |
17 |
18 | image 19 |
20 |

Example

21 | {img === "" ? 22 |

{category}

23 | : 24 | image} 25 |
26 |
27 |
28 |
29 | ) 30 | } 31 | 32 | export default PortalConsider -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Footer.tsx: -------------------------------------------------------------------------------- 1 | const Footer = () => { 2 | return ( 3 | <> 4 |
5 | {/* 1D252C 141838 */} 6 |
7 |

Trade Mark Today

8 | 17 |

We acknowledge the traditional owners of the country throughout Australia and their continuing connection to land, sea and community. We pay our respect to them and their cultures and to the elders past and present.

18 |
19 |
20 | 21 | ) 22 | } 23 | export default Footer; -------------------------------------------------------------------------------- /src/components/NotificationComponent.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | 3 | const NotificationComponent = ({ msg }: { msg: string }) => { 4 | 5 | useEffect(() => { 6 | if (!msg) return; 7 | (async () => { 8 | await Notification.requestPermission(); 9 | if (Notification.permission === 'granted') { 10 | (new Notification(msg, { 11 | icon: '/trademarktoday.png', 12 | badge: '/dollar.png', 13 | // tag: 'message-notification', 14 | // data: { messageId: Math.random() * 100 }, 15 | requireInteraction: false, 16 | silent: false, 17 | // actions: [ 18 | // { action: 'reply', title: 'Reply' }, 19 | // { action: 'dismiss', title: 'Dismiss' }, 20 | // ], 21 | })).onclick = () => { 22 | window.focus(); 23 | // let link:any = document.querySelector("link[rel~='icon']"); 24 | // if (!link) { 25 | // // Create a new link element if it doesn't exist 26 | // link = document.createElement('link'); 27 | // link.rel = 'icon'; 28 | // document.head.appendChild(link); 29 | // } 30 | // link.href = '/fav.ico'; 31 | }; 32 | } 33 | })(); 34 | }, [msg]) 35 | return null; 36 | }; 37 | 38 | export default NotificationComponent -------------------------------------------------------------------------------- /src/pages/api/create-checkout-session.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | import stripe from 'stripe'; 3 | 4 | const stripeInstance = new stripe(process.env.stripeSecretKey as string, { apiVersion: "2022-11-15" }); 5 | 6 | export default async function handler(req: Request, res: Response) { 7 | const { price, transactionKey } = req.body; 8 | try { 9 | const session = await stripeInstance.checkout.sessions.create({ 10 | payment_method_types: ['card'], 11 | line_items: [ 12 | { 13 | price_data: { 14 | currency: 'usd', 15 | product_data: { 16 | name: 'Trade Mark Today Subscription', 17 | }, 18 | unit_amount: price * 100, // Amount in cents 19 | }, 20 | quantity: 1, 21 | }, 22 | ], 23 | mode: 'payment', 24 | // success_url: `https://localhost/payres/success?transactionKey=${transactionKey}`, 25 | // cancel_url: 'https://localhost/payres/fail?reason=0', 26 | success_url: `https://trademarktoday.com.au/payres/success?transactionKey=${transactionKey}`, 27 | cancel_url: 'https://trademarktoday.com.au/payres/fail?reason=0', 28 | }); 29 | 30 | res.status(200).json({ id: session.id }); 31 | } catch (error) { 32 | console.error(error); 33 | res.status(500).json({ error: 'An error occurred' }); 34 | } 35 | } -------------------------------------------------------------------------------- /src/controllers/users.tsx: -------------------------------------------------------------------------------- 1 | import usersModel from "@/models/usersModel"; 2 | import { Request, Response } from "express"; 3 | 4 | export const find = async (req: Request, res: Response) => { 5 | const list = await usersModel.find(); 6 | res.status(200).json({ 7 | success: true, 8 | data: list, 9 | }); 10 | } 11 | 12 | export const insert = async (req: Request, res: Response) => { 13 | const user = await usersModel.create(req.body); 14 | res.status(201).json([user]) 15 | } 16 | 17 | export const findByEmail = async ({ req, res }: { req: Request, res: Response }, email: string) => { 18 | const list = await usersModel.find({ email }); 19 | res.status(200).json({ 20 | success: true, 21 | data: list, 22 | }); 23 | } 24 | 25 | export const update = async (req: Request, res: Response) => { 26 | const { email } = req.body 27 | const users = await usersModel.updateOne( 28 | { email: email }, 29 | { 30 | $set: { 31 | ...req.body 32 | } 33 | } 34 | ); 35 | res.status(201).json({ 36 | success: true, 37 | data: users, 38 | }); 39 | } 40 | 41 | export const remove = async (req: Request, res: Response) => { 42 | try { 43 | const result = await usersModel.deleteOne({ email: req.body.email }); 44 | console.log('Model deleted successfully'); 45 | } catch (err) { 46 | console.error('Error deleting model:', err); 47 | } 48 | } -------------------------------------------------------------------------------- /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "commitType": "docs", 8 | "commitConvention": "angular", 9 | "contributors": [ 10 | { 11 | "login": "marksantiago2909", 12 | "name": "Mark Santiago", 13 | "avatar_url": "https://avatars.githubusercontent.com/u/132613676?v=4", 14 | "profile": "https://github.com/marksantiago2909", 15 | "contributions": [ 16 | "code", 17 | "content", 18 | "doc", 19 | "data", 20 | "example", 21 | "ideas", 22 | "projectManagement", 23 | "review", 24 | "tool", 25 | "tutorial", 26 | "video" 27 | ] 28 | }, 29 | { 30 | "login": "imcrazysteven", 31 | "name": "Steven Leal", 32 | "avatar_url": "https://avatars.githubusercontent.com/u/138194633?v=4", 33 | "profile": "https://github.com/imcrazysteven", 34 | "contributions": [ 35 | "code", 36 | "content", 37 | "doc", 38 | "data", 39 | "example", 40 | "ideas", 41 | "projectManagement", 42 | "review", 43 | "tool", 44 | "tutorial", 45 | "video" 46 | ] 47 | } 48 | ], 49 | "contributorsPerLine": 7, 50 | "skipCi": true, 51 | "repoType": "github", 52 | "repoHost": "https://github.com", 53 | "projectName": "trademarktoday-nextjs", 54 | "projectOwner": "imcrazysteven" 55 | } 56 | -------------------------------------------------------------------------------- /src/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import { generateNonce } from '@/types/utils'; 2 | import Document, { Html, Head, Main, NextScript, DocumentProps } from 'next/document'; 3 | 4 | const MyDocument = () => { 5 | const nonce = generateNonce(); 6 | return ( 7 | 8 | 9 | 10 | 13 | {/* */} 16 | 17 | 21 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | ); 32 | } 33 | 34 | export default MyDocument -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const https = require('https'); 3 | const fs = require('fs'); 4 | const next = require('next'); 5 | const dotenv = require("dotenv"); 6 | const morgan = require("morgan"); 7 | const bodyParser = require('body-parser'); 8 | const cors = require("cors"); 9 | const path = require('path'); 10 | const connectToMongodb = require('./src/db/mongodb'); 11 | dotenv.config({ path: "./.env" }); 12 | const dev = process.env.NODE_ENV !== 'production'; 13 | const app = next({ dev }); 14 | const handle = app.getRequestHandler(); 15 | console.log('started') 16 | app.prepare().then(() => { 17 | const server = express(); 18 | server.use(morgan('dev')) 19 | server.use(express.json()); 20 | server.use(cors()); 21 | server.use(bodyParser.json()); 22 | server.use(express.static(path.join(__dirname, 'public'))) 23 | const options = { 24 | key: fs.readFileSync('key.pem'), 25 | cert: fs.readFileSync('cert.pem') 26 | }; 27 | console.error('before connecting...') 28 | connectToMongodb(); 29 | console.error('after connecting...') 30 | console.log('after connecting...') 31 | server.all('*', (req, res) => { 32 | return handle(req, res); 33 | }); 34 | // server.listen(process.env.PORT, (err) => { 35 | // if (err) throw err; 36 | // console.log('> Ready on http://localhost:' + process.env.PORT); 37 | // }); 38 | https.createServer(options, server).listen(443, () => { 39 | console.log('Server running on https://localhost'); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /src/pages/dashboard.tsx: -------------------------------------------------------------------------------- 1 | import TMCheckLayout from '../layout/TMCheckLayout'; 2 | import { Alert3 } from '@/components/AlertContainers'; 3 | import ServerSidePropsAuthorized from '@/layout/ServerSidePropsAuthorized'; 4 | import Link from 'next/link'; 5 | import Image from 'next/image'; 6 | import Chat from '@/components/Chat'; 7 | import { useContext, useEffect } from 'react'; 8 | import { PiniaStore } from '@/store/store'; 9 | import { useRouter } from 'next/router'; 10 | 11 | const Dashboard = ({ email }: { email: string }) => { 12 | const { pinia, setPinia } = useContext(PiniaStore); 13 | const router = useRouter(); 14 | // useEffect(() => { 15 | // if (Object.keys(pinia).length === 0 && pinia.constructor === Object) { 16 | // // router.push('/consider') 17 | // return; 18 | // } 19 | // }, [pinia]) 20 | 21 | useEffect(()=>{ 22 | router.push('/checkout') 23 | },[]) 24 | 25 | return ( 26 | <> 27 |
28 |
29 |

Dashboard Test

30 | 32 | This page is only for testing purpose. You can see this page because you have logged in. 33 | 34 | } /> 35 | 36 |
37 |
38 | 39 | ) 40 | } 41 | 42 | Dashboard.getLayout = TMCheckLayout; 43 | 44 | export const getServerSideProps = ServerSidePropsAuthorized; 45 | 46 | export default Dashboard; -------------------------------------------------------------------------------- /src/types/searchs.tsx: -------------------------------------------------------------------------------- 1 | import stringSimilarity from 'string-similarity' 2 | import natural, { TfIdf, WordNet } from 'natural'; 3 | import keywordsModel from '@/models/keywordsModel'; 4 | // ! Search for similar words from the keywords START 5 | const performSearch = (query: string, processedProductNames: string[]) => { 6 | // Find matches based on string similarity 7 | const matches = stringSimilarity.findBestMatch(query, processedProductNames); 8 | // Get the top matching results 9 | const results = matches.ratings 10 | .filter(({ rating }) => rating > 0.5) // Adjust the threshold as needed 11 | .map(({ target }) => target); 12 | return results; 13 | } 14 | export const searchSimilarWordsFromKeywords = async (query: string) => { 15 | try { 16 | const keywords: string[] = ((await keywordsModel.find()) as { keyword: string }[]).map(row => row.keyword); 17 | const searchResults = performSearch(query, keywords); 18 | return searchResults; 19 | } 20 | catch (error) { 21 | console.log(error); 22 | } 23 | } 24 | // ! Search for similar words from the keywords END 25 | export const getSynonyms = async (inputWord: string) => { 26 | return new Promise((resolve, reject) => { 27 | 9 28 | const wordnet = new WordNet(); 29 | wordnet.lookup(inputWord, (definitions) => { 30 | { 31 | const similarWords = definitions.reduce((words: string[], definition) => { 32 | definition.synonyms.forEach((synonym) => { 33 | if (!words.includes(synonym)) { 34 | words.push(synonym); 35 | } 36 | }); 37 | return words; 38 | }, []); 39 | resolve(similarWords); 40 | } 41 | }); 42 | }); 43 | }; -------------------------------------------------------------------------------- /src/db/users.ts: -------------------------------------------------------------------------------- 1 | import mysqldb from "./mysqldb" 2 | import { Request, Response } from "express" 3 | 4 | export const find = (req: Request, res: Response) => { 5 | // get all users 6 | mysqldb.query('SELECT * FROM users', (err, results) => { 7 | if (err) throw err 8 | res.status(200).json(results) 9 | }) 10 | } 11 | 12 | export const findByEmail = ({ req, res }: { req: Request, res: Response }, email: string) => { 13 | // get all users 14 | mysqldb.query('SELECT * FROM users WHERE email = ?', [email], (err, results, fields) => { 15 | if (err) throw err 16 | res.status(200).json(results) 17 | }) 18 | } 19 | 20 | export const insert = (req: Request, res: Response) => { 21 | // create a new user 22 | const { given_name, family_name, picture, email, name, password } = req.body 23 | mysqldb.query('INSERT INTO users SET ?', { given_name, family_name, picture, email, name, password }, (err, result) => { 24 | if (err) throw err 25 | res.status(201).json([{ given_name, family_name, picture, email, name, password, ID: result.insertId }]) 26 | }) 27 | } 28 | 29 | export const update = (req: Request, res: Response) => { 30 | /// update a user by ID 31 | const { id, name, email } = req.body 32 | mysqldb.query('UPDATE users SET name=?, email=? WHERE id=?', [name, email, id], (err, result) => { 33 | if (err) throw err 34 | res.status(200).json({ message: 'User updated successfully' }) 35 | }) 36 | } 37 | 38 | export const remove = (req: Request, res: Response) => { 39 | // delete a user by ID 40 | const { id } = req.body 41 | mysqldb.query('DELETE FROM users WHERE id=?', id, (err, result) => { 42 | if (err) throw err 43 | res.status(200).json({ message: 'User deleted successfully' }) 44 | }) 45 | } -------------------------------------------------------------------------------- /src/pages/api/login.ts: -------------------------------------------------------------------------------- 1 | import jwt from 'jsonwebtoken' 2 | import bcrypt from 'bcryptjs' 3 | import { AuthStatus, User } from "@/types/interface"; 4 | import { Request, Response } from "express"; 5 | import { JWT_SIGN_KEY } from "@/types/utils"; 6 | import usersModel from '@/models/usersModel'; 7 | import connectToMongodb from '@/db/mongodb' 8 | 9 | export default async function handler(req: Request, res: Response) { 10 | connectToMongodb(); 11 | let authStatus: AuthStatus = "NONE"; 12 | const { email, password } = req.body; 13 | try { 14 | if (req.method === 'POST') { 15 | const results: User[] = await usersModel.find({ email }); 16 | if (results.length === 0) { 17 | authStatus = "UNREGISTER_USER" 18 | } else { 19 | const hashedPassword = results[0].password; 20 | const match = await bcrypt.compare(password, hashedPassword as string); 21 | if (match) { 22 | authStatus = "PASSED"; 23 | // const { name, given_name, family_name, picture, ACN, phone_number, address } = results[0] 24 | const token = jwt.sign({ email }, JWT_SIGN_KEY); 25 | res.setHeader( 26 | "Set-Cookie", 27 | `token=${token}; Path=/; Max-Age=${60 * 60//HttpOnly;SameSite=Strict; 28 | }` 29 | ) 30 | } else { 31 | authStatus = "INVALID_PASSWORD" 32 | } 33 | } 34 | res.status(200).json({ authStatus }) 35 | } else { 36 | res.status(405).json({ message: 'Method not allowed' }) 37 | } 38 | } catch (error) { 39 | console.log("API error", error); 40 | if (!res.headersSent) { 41 | res.send(500).json({ 42 | success: false, 43 | data: "Server error", 44 | }); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/pages/api/_testApi/testforstrsim.ts: -------------------------------------------------------------------------------- 1 | import natural, { TfIdf, WordNet } from 'natural'; 2 | import stringSimilarity from 'string-similarity' 3 | import { Request, Response } from "express"; 4 | import keywordsModel from '@/models/keywordsModel' 5 | 6 | export default async function handler(req: Request, res: Response) { 7 | if (req.method === 'GET') { 8 | 9 | try { 10 | const keywords:string[] = ((await keywordsModel.find()) as {keyword:string}[]).map(row => row.keyword); 11 | const query = req.query.search as string; 12 | const searchResults = performSearch(query, keywords); 13 | console.log(searchResults); 14 | res.status(200).json(searchResults); 15 | } 16 | catch (error) { 17 | console.error(error); 18 | } 19 | } else { 20 | res.status(405).json({ message: 'Method not allowed' }) 21 | } 22 | } 23 | function preprocessProductNames(productNames: string[]) { 24 | const processedNames = productNames.map(name => { 25 | // Remove special characters and convert to lowercase 26 | const processedName = name.replace(/[^\w\s]/gi, '').toLowerCase(); 27 | 28 | // Split into individual words 29 | const words = processedName.split(' '); 30 | 31 | return words; 32 | }); 33 | 34 | return processedNames; 35 | } 36 | 37 | function performSearch(query: string, processedProductNames: string[]) { 38 | // Find matches based on string similarity 39 | const matches = stringSimilarity.findBestMatch(query, processedProductNames); 40 | 41 | // Get the top matching results 42 | const results = matches.ratings 43 | .filter(({ rating }) => rating > 0.5) // Adjust the threshold as needed 44 | .map(({ target }) => target); 45 | 46 | return results; 47 | } -------------------------------------------------------------------------------- /src/pages/api/upload.tsx: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | import multer from 'multer'; 3 | import { NextApiRequest, NextApiResponse } from 'next'; 4 | 5 | const storage = multer.diskStorage({ 6 | destination: function (req, file, cb) { 7 | // Specify the directory where uploaded files will be stored 8 | cb(null, 'public/uploads/'); 9 | }, 10 | filename: async function (req, file, cb) { 11 | const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9); 12 | const originalExtension = file.originalname.split('.').pop(); 13 | const newFileName = file.fieldname + '-' + uniqueSuffix + '.' + originalExtension; 14 | cb(null, newFileName); 15 | } 16 | }); 17 | 18 | const upload = multer({ 19 | storage: storage, 20 | limits: { 21 | fileSize: 10 * 1024 * 1024, // 10 MB in bytes 22 | }, 23 | }); 24 | 25 | export const config = { 26 | api: { 27 | bodyParser: false, 28 | }, 29 | }; 30 | 31 | export default async function handler(req: NextApiRequest, res: NextApiResponse) { 32 | if (req.method === 'POST') { 33 | try { 34 | await new Promise((resolve, reject) => { 35 | upload.single('image')(req as any, res as any, (err: any) => { 36 | console.log(err) 37 | if (err instanceof multer.MulterError) { 38 | return reject(err); 39 | } else if (err) { 40 | return reject(err); 41 | } 42 | if (!(req as any).file) { 43 | return reject(new Error('No file was uploaded.')); 44 | } 45 | 46 | resolve(); 47 | }); 48 | }); 49 | 50 | res.status(200).json({ filename: (req as any).file.filename }); 51 | } catch (error: any) { 52 | res.status(400).json({ error: error.message }); 53 | } 54 | } else { 55 | res.status(405).json({ error: 'Method not allowed' }); 56 | } 57 | } -------------------------------------------------------------------------------- /public/exit-logout-svgrepo-com.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 9 | 15 | 20 | -------------------------------------------------------------------------------- /src/pages/api/google.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | import { OAuth2Client } from 'google-auth-library'; 3 | import axios from 'axios' 4 | import jwt from 'jsonwebtoken' 5 | import { JWT_SIGN_KEY } from '@/types/utils'; 6 | import usersModel from '@/models/usersModel'; 7 | import connectToMongodb from '@/db/mongodb' 8 | 9 | export default async function handler(req: Request, res: Response): Promise { 10 | connectToMongodb(); 11 | const { code } = req.query; 12 | const codeAsString: string = code?.toString() ?? ''; 13 | // Create a new OAuth client instance 14 | const oauth2Client = new OAuth2Client(process.env.CLIENT_ID, process.env.CLIENT_SECRET, process.env.REDIRECT_URI); 15 | 16 | try { 17 | // Verify the authorization code with Google 18 | const { tokens } = await oauth2Client.getToken(codeAsString); 19 | 20 | // Use the access token to get the user's email address 21 | const { data: { given_name, family_name, picture, email, name } } = await axios.get('https://www.googleapis.com/oauth2/v3/userinfo', { 22 | headers: { Authorization: `Bearer ${tokens.access_token}` }, 23 | }); 24 | // let { data } = await axios.get(`/api/users/${encodeURIComponent(email)}`); 25 | const data = await usersModel.find({ email }); 26 | if (data.length === 0) { 27 | // const {data:_data} = await axios.post('/api/users', { given_name, family_name, picture, email, name }) 28 | const _data = await usersModel.create({ given_name, family_name, picture, email, name, ACN: '', phone_number: '', address: '' }); 29 | } 30 | const token = jwt.sign({ email }, JWT_SIGN_KEY); 31 | res.setHeader( 32 | "Set-Cookie", 33 | `token=${token}; Path=/; Max-Age=${60 * 60//HttpOnly;SameSite=Strict; 34 | }` 35 | ).redirect('/dashboard'); 36 | 37 | // res.status(200).json(data).redirect('/summary'); 38 | } catch (error) { 39 | console.error(error); 40 | res.status(500).send('Internal Server Error'); 41 | } 42 | } -------------------------------------------------------------------------------- /src/pages/payres/success.tsx: -------------------------------------------------------------------------------- 1 | import ServerSidePropsAuthorized from '@/layout/ServerSidePropsAuthorized'; 2 | import Chat from '@/components/Chat'; 3 | import bcrypt from 'bcryptjs' 4 | import TMCheckLayout from '@/layout/TMCheckLayout'; 5 | import { useRouter } from 'next/router'; 6 | import { useEffect, useState } from 'react'; 7 | import Image from 'next/image'; 8 | 9 | const Paysuccess = ({ email }: { email: string }) => { 10 | const router = useRouter(); 11 | const transactionKey = router.query.transactionKey as string; 12 | const [waiting, setWaiting] = useState(true); 13 | useEffect(() => { 14 | const hashedTransactionKey = sessionStorage.getItem('transactionKey'); 15 | if (!transactionKey || !hashedTransactionKey) { 16 | router.push('/payres/fail?reason=1') 17 | } 18 | 19 | bcrypt.compare(transactionKey, hashedTransactionKey as string).then((match) => { 20 | if (match) { 21 | //! Add in database here. 22 | //! And then redirect after await. 23 | setWaiting(false); 24 | sessionStorage.removeItem('transactionKey'); 25 | setTimeout(() => { 26 | router.push('/profile') 27 | }, 10000) 28 | } else { 29 | router.push('/payres/fail?reason=2') 30 | } 31 | }).catch((err: any) => { 32 | router.push('/payres/fail?reason=3') 33 | }); 34 | }, []) 35 | 36 | return ( 37 | <> 38 | {waiting ? 39 | <>Processing : 40 |
41 |
42 |

Payment Succeed

43 |

transactionKey:{transactionKey}

44 |

Processing...

45 | logo 46 | 47 |
48 |
} 49 | 50 | ) 51 | } 52 | 53 | Paysuccess.getLayout = TMCheckLayout; 54 | 55 | export const getServerSideProps = ServerSidePropsAuthorized; 56 | 57 | export default Paysuccess; -------------------------------------------------------------------------------- /src/types/interface.tsx: -------------------------------------------------------------------------------- 1 | import { IncomingMessage, ServerResponse } from "http" 2 | export type AuthStatus = "NONE" | "PASSED" | "UNREGISTER_USER" | "INVALID_PASSWORD" 3 | export type User = { 4 | email: string 5 | name: string 6 | password: string 7 | given_name: string 8 | family_name: string 9 | picture: string 10 | ACN: string 11 | phone_number: string 12 | address: string 13 | } 14 | export type Context = { 15 | req: IncomingMessage; // an HTTP incoming message object (e.g., from Node.js http.IncomingMessage) 16 | res: ServerResponse; // an HTTP server response object (e.g., from Node.js http.ServerResponse) 17 | } 18 | export type FormDataType = { 19 | email: string 20 | name: string 21 | password: string 22 | ACN: string 23 | phone_number: string 24 | address: string 25 | } 26 | export interface StateType { 27 | otp: boolean 28 | code: string 29 | waiting: boolean 30 | formData: FormDataType 31 | } 32 | type ClassPinia = { 33 | id: string; 34 | tmClass: string; 35 | description: string; 36 | }; 37 | type ClassPinias = { 38 | [key: string]: ClassPinia[]; 39 | }; 40 | export interface PiniaType { 41 | initiated?: boolean 42 | acceptedTerms?: boolean 43 | markType?: 'Word' | 'Logo' 44 | word?: string 45 | wordContained?: boolean 46 | containedWord?: 'string' 47 | logo?: string 48 | classes?: ClassPinias 49 | } 50 | export interface ActionType { 51 | type: 'CHANGE_FORMDATA' | 'SET_OTPCODE' | 'SHOW_OTPCODE' | 'SET_WAITING'; 52 | payload: { 53 | value: FormDataType | string | boolean | { [key: string]: string } 54 | } 55 | } 56 | export type DispatchType = (action: ActionType) => void; 57 | 58 | export interface ContextType { 59 | otpState: StateType; 60 | dispatchOtpState: DispatchType; 61 | } 62 | export interface PiniaContextType { 63 | pinia: PiniaType; 64 | setPinia: (_: {}) => void; 65 | } 66 | export type Message = { 67 | time?: string 68 | key: string 69 | channel: string 70 | author: string; 71 | message: string; 72 | viewed?: boolean 73 | deliveredToServer?: boolean 74 | deliveredToClient?: boolean 75 | }; -------------------------------------------------------------------------------- /src/types/utils.tsx: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import bcrypt from 'bcryptjs' 3 | import crypto from 'crypto' 4 | import QueryString from 'qs'; 5 | import { v4 as uuidv4 } from 'uuid'; 6 | 7 | export const JWT_SIGN_KEY = 'de98hw9ew0hbmj6v8sd9w'; 8 | export const ADMIN_LIST = ['milkyway464203@gmail.com', 'syedmosawi@gmail.com']; 9 | export function generateNonce() { 10 | return uuidv4(); 11 | } 12 | export const hash = async (password: string) => { 13 | const saltRounds = 10; 14 | const hashedPassword = await bcrypt.hash(password, saltRounds); 15 | return hashedPassword; 16 | } 17 | export const validateEmail = (email: string) => { 18 | const pattern = /^[\w\.-]+@[\w\.-]+\.\w+$/; 19 | return pattern.test(email); 20 | } 21 | export const generateRandomKey = (length: number) => { 22 | return crypto.randomBytes(Math.ceil(length / 2)).toString('hex').slice(0, length); 23 | } 24 | export const getTokenIPAustralia = async () => { 25 | const data = { 26 | grant_type: "client_credentials", 27 | client_id: "P6XvOnJn6FCAjyM1JDYB2Sr5UMGbb5Ob", 28 | client_secret: "L8lIpwQcqliOkyjGF9Nbie-fw3N_v-K-xh-eQlsmATvf2S-O_Pk0-GEZFOdbVvId" 29 | } 30 | const { data: { access_token } } = await axios.post('https://test.api.ipaustralia.gov.au/public/external-token-api/v1/access_token', data, { 31 | headers: { 32 | 'Content-Type': 'application/x-www-form-urlencoded' 33 | } 34 | }) 35 | return access_token; 36 | } 37 | export const quickSearchIPAustralia = async (query: string, token: string) => { 38 | const data = { 39 | changedSinceDate: "2012-01-01", 40 | filters: { 41 | quickSearchType: [ 42 | "WORD" 43 | ], 44 | status: [ 45 | "REGISTERED" 46 | ] 47 | }, 48 | query, 49 | sort: { 50 | direction: "ASCENDING", 51 | field: "NUMBER" 52 | } 53 | } 54 | const { data: { count, trademarkIds } } = await axios.post('https://test.api.ipaustralia.gov.au/public/australian-trade-mark-search-api/v1/search/quick', data, { 55 | headers: { 56 | 'Authorization': `Bearer ${token}`, 57 | 'Content-Type': 'application/json' 58 | } 59 | }) 60 | return { count, trademarkIds } 61 | } -------------------------------------------------------------------------------- /src/pages/auth.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import MyTab from "../components/MyTab"; 3 | import { useContext, useReducer, useState } from "react"; 4 | import Login from "@/components/Login"; 5 | import SignUp from "@/components/SignUp"; 6 | import SignWithGoogle from "@/components/SignWithGoogle"; 7 | import { MessageBoxModal, OTPModal } from "@/components/Modal"; 8 | import { OTPStore, initialState } from "@/store/store"; 9 | import reducer from "@/store/reducer"; 10 | import WaitingLocker from "@/components/WaitingLocker"; 11 | import { useRouter } from "next/router"; 12 | import { verifyToken } from "@/components/Header"; 13 | 14 | const Auth = () => { 15 | const router = useRouter(); 16 | if (verifyToken()) { 17 | router.push('/dashboard') 18 | } 19 | const [otpState, dispatchOtpState] = useReducer(reducer, initialState); 20 | const [value, setValue] = useState(0); 21 | const [msg, setMsg] = useState("Already registered user"); 22 | const [open, setOpen] = useState(false); 23 | return ( 24 | 25 |
26 | 27 | 28 |
29 | router.push('/')} className="cursor-pointer hover:scale-150 transition-all ease-in-out duration-700" src="/trademarktoday_logo.png" alt="logo" priority width={188} height={58} /> 30 |

Login to your account

31 | 32 | 33 | 34 | 35 | 36 |
37 |
38 | 39 | 40 | 41 |
42 | ) 43 | } 44 | 45 | export default Auth; -------------------------------------------------------------------------------- /src/components/MyTab.tsx: -------------------------------------------------------------------------------- 1 | 2 | import { useTheme } from '@mui/material/styles'; 3 | import AppBar from '@mui/material/AppBar'; 4 | import Tabs from '@mui/material/Tabs'; 5 | import Tab from '@mui/material/Tab'; 6 | import Typography from '@mui/material/Typography'; 7 | import Box from '@mui/material/Box'; 8 | import { ReactNode, useState } from 'react'; 9 | import SwipeableViews from 'react-swipeable-views-react-18-fix'; 10 | 11 | interface TabPanelProps { 12 | children?: ReactNode; 13 | dir?: string; 14 | index: number; 15 | value: number; 16 | } 17 | 18 | const a11yProps = (index: number) => { 19 | return { 20 | id: `full-width-tab-${index}`, 21 | 'aria-controls': `full-width-tabpanel-${index}`, 22 | }; 23 | } 24 | 25 | const MyTab = ({ titles, props: { value, setValue }, children }: { 26 | titles: string[], 27 | props: { 28 | value: number, 29 | setValue: React.Dispatch> 30 | }, 31 | children: ReactNode 32 | }) => { 33 | const theme = useTheme(); 34 | const handleChange = (event: React.SyntheticEvent, newValue: number) => { 35 | setValue(newValue); 36 | }; 37 | 38 | const handleChangeIndex = (index: number) => { 39 | setValue(index); 40 | }; 41 | 42 | return ( 43 | <> 44 | {/* */} 45 | {/* */} 46 | 58 | {titles.map((title, index) => ())} 59 | 60 | {/* */} 61 | {/* */} 62 | 68 | {children} 69 | 70 | {/* */} 71 | 72 | ); 73 | } 74 | 75 | export default MyTab -------------------------------------------------------------------------------- /src/components/AlertContainers.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image" 2 | import Link from "next/link" 3 | import { ReactNode } from "react" 4 | 5 | export const AlertErr = ({ showAlert, msg }: { showAlert: boolean, msg: string }) => { 6 | return ( 7 |
8 |
9 | 10 |
11 |

There is a problem

12 |
  • 13 | 14 | {msg} 15 | 16 |
  • 17 |
    18 |
    19 |
    20 | ) 21 | } 22 | 23 | export const Alert2 = ({ msg }: { msg: ReactNode }) => { 24 | return ( 25 |
    26 |
    27 | image 28 |
    29 |

    What you need to know

    30 | {msg} 31 |
    32 |
    33 |
    34 | ) 35 | } 36 | 37 | export const Alert3 = ({ msg }: { msg: ReactNode }) => { 38 | return ( 39 |
    40 |
    41 | image 42 |

    {msg}

    43 |
    44 |
    45 | ) 46 | } 47 | 48 | export const Alert4 = () => { 49 | return ( 50 |
    51 |
    52 | image 53 |
    54 |

    Important

    55 |

    Our automated search has found trade marks that you may consider before proceeding.

    56 |
    57 |
    58 |
    59 | ) 60 | } -------------------------------------------------------------------------------- /src/db/mysqldb.js: -------------------------------------------------------------------------------- 1 | import mysql from 'mysql' 2 | import natural, { TfIdf } from 'natural'; 3 | import stringSimilarity from 'string-similarity'; 4 | 5 | const mysqldb = mysql.createPool({ 6 | connectionLimit: 10, 7 | host: 'localhost', 8 | user: 'root', 9 | password: '', 10 | database: 'trademarktoday' 11 | }) 12 | 13 | export default mysqldb; 14 | 15 | 16 | 17 | 18 | 19 | //!Todo delete 20 | // function intelligentSearch() { 21 | // const tokenizer = new natural.WordTokenizer(); 22 | // const userInputTokens = tokenizer.tokenize(userInput); 23 | 24 | // // Retrieve description data from the database 25 | // const query = 'SELECT product FROM products'; 26 | // db.query(query, (error, rows) => { 27 | // if (error) { 28 | // console.error('Error retrieving data from the database:', error); 29 | // return; 30 | // } 31 | 32 | // // Extract keywords using TF-IDF 33 | // const tfidf = new TfIdf(); 34 | // rows.forEach((row) => { 35 | // const descriptionTokens = tokenizer.tokenize(row.product); 36 | // const addToDoc = descriptionTokens.join(' '); 37 | // tfidf.addDocument(addToDoc); 38 | // }); 39 | 40 | // // Find relevant keywords based on TF-IDF scores 41 | // const relevantKeywords = []; 42 | // tfidf.listTerms(0).forEach((term) => { 43 | // relevantKeywords.push(term.term); 44 | // }); 45 | 46 | // // Perform fuzzy matching with user input 47 | // const matches = stringSimilarity.findBestMatch(userInput, relevantKeywords); 48 | // console.log(matches) 49 | // const matchedKeywords = matches.ratings.filter((match) => match.rating > 0.5).map((match) => match.target); 50 | // if(matchedKeywords.length===0){ 51 | // res.status(204).json([]); 52 | // return; 53 | // } 54 | // // Query the database for matching records 55 | // const searchQuery = ` 56 | // SELECT * FROM products 57 | // WHERE product LIKE '%${matchedKeywords.join("%' OR product LIKE '%")}%' LIMIT 10 58 | // `; 59 | // db.query(searchQuery, (err, results) => { 60 | // if (err) { 61 | // console.error('Error executing search query:', err); 62 | // return; 63 | // } 64 | 65 | // // Process and display the search results 66 | // console.log('Search Results:'); 67 | // results.forEach((result) => { 68 | // console.log(result); 69 | // }); 70 | // return res.status(200).json(results) 71 | // }); 72 | // }); 73 | // } 74 | -------------------------------------------------------------------------------- /src/pages/api/products.ts: -------------------------------------------------------------------------------- 1 | 2 | import ProductsModel from "@/models/productsModel"; 3 | import { Request, Response } from "express"; 4 | import connectToMongodb from '@/db/mongodb' 5 | 6 | export default async function handler(req: Request, res: Response) { 7 | connectToMongodb(); 8 | const { keywords } = req.body; 9 | try { 10 | if (req.method === 'POST') { 11 | // const p_fromDB = await Promise.all(keywords.map(async (keyword: string) => 12 | // (await ProductsModel.find({ product: { $regex: keyword, $options: 'i' } })) 13 | // )); 14 | // const p_merged = p_fromDB.reduce((products: string[], elem: string[]) => 15 | // ([...products, ...elem]), []); 16 | await ProductsModel.createIndexes(); 17 | const p_fromDB = await ProductsModel.find( 18 | { $text: { $search: keywords.join(' ') } }, 19 | { score: { $meta: "textScore" } } 20 | ).limit(1000).sort({ score: { $meta: "textScore" } }).exec(); 21 | const products = p_fromDB.reduce((groups: any, product: any) => { 22 | const { class: productClass } = product; 23 | if (!groups[productClass]) { 24 | groups[productClass] = []; 25 | } 26 | groups[productClass].push(product); 27 | return groups; 28 | }, {}); 29 | const arr_products = Object.keys(products).map(key => ({ _class: key, product: products[key] })); 30 | arr_products.forEach(elem => { 31 | elem.product.sort((a: any, b: any) => (b.score - a.score)) 32 | }) 33 | arr_products.sort((a:any,b:any)=>(b.product[0].score-a.product[0].score)); 34 | 35 | // interface GroupedProduct { 36 | // [key: string]: { product: string; class: string }[]; 37 | // } 38 | 39 | // const groupedArray: { product: string; class: string }[][] = []; 40 | // const groups: GroupedProduct = {}; 41 | 42 | // p_fromDB.forEach((product) => { 43 | // const { class: productClass, ...rest } = product; 44 | 45 | // if (!groups[productClass]) { 46 | // groups[productClass] = [rest];console.log(groups[productClass]) 47 | // groupedArray.push(groups[productClass]); 48 | // } else { 49 | // groups[productClass].push(rest); 50 | // } 51 | // }); 52 | 53 | 54 | res.status(200).json({ 55 | success: true, 56 | data: arr_products 57 | }) 58 | } else { 59 | res.status(405).json({ 60 | success: false, 61 | data: "Method not allowed." 62 | }) 63 | } 64 | } catch (error) { 65 | console.log("API error", error); 66 | if (!res.headersSent) { 67 | res.status(200).json({ 68 | success: false, 69 | data: "Server error", 70 | }); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/pages/profile.tsx: -------------------------------------------------------------------------------- 1 | import TMCheckLayout from '../layout/TMCheckLayout'; 2 | import ServerSidePropsAuthorized from '@/layout/ServerSidePropsAuthorized'; 3 | import Chat from '@/components/Chat'; 4 | import Image from 'next/image'; 5 | import { useEffect, useState } from 'react'; 6 | import { User } from '@/types/interface'; 7 | import axios from 'axios'; 8 | 9 | const Profile = ({ email }: { email: string }) => { 10 | const [user, setUser] = useState() 11 | useEffect(() => { 12 | (async () => { 13 | if (!email) return; 14 | const { data: { data } } = await axios.get(`/api/users?email=${encodeURIComponent(email)}`); 15 | setUser(data[0]) 16 | })() 17 | }, [email]) 18 | return ( 19 | <> 20 |
    21 |

    My profile

    22 |
    23 |
    24 | logo e.currentTarget.src = "/no-avatar.png"} width={150} height={150} /> 25 | 26 |

    {user?.name}

    27 |

    {user?.address}

    28 |
    29 |
    30 |
    31 |
    Applicants
    32 |
    {user?.name}
    33 |
    34 |
    35 |
    Email
    36 |
    {user?.email}
    37 |
    38 |
    39 |
    Phone Number
    40 |
    {user?.phone_number}
    41 |
    42 |
    43 |
    Address
    44 |
    {user?.address}
    45 |
    46 |
    47 |
    ACN
    48 |
    {user?.ACN}
    49 |
    50 |
    51 |
    52 |
    53 | 54 | 55 | ) 56 | } 57 | 58 | Profile.getLayout = TMCheckLayout; 59 | 60 | export const getServerSideProps = ServerSidePropsAuthorized; 61 | 62 | export default Profile; -------------------------------------------------------------------------------- /src/pages/adminusers.tsx: -------------------------------------------------------------------------------- 1 | import TMCheckLayout from '../layout/TMCheckLayout'; 2 | import { User } from '@/types/interface'; 3 | import ChatAdmin from '@/components/ChatAdmin'; 4 | import ServerSidePropsAdminAuthorized from '@/layout/ServerSidePropsAdminAuthorized'; 5 | import { useEffect, useState } from 'react'; 6 | import axios from 'axios'; 7 | import Image from 'next/image'; 8 | 9 | const AdminChat = ({ email }: { email: string }) => { 10 | const [allUsers, setAllUsers] = useState([]); 11 | useEffect(() => { 12 | (async () => { 13 | const { data: { data } } = await axios.get(`/api/users`); 14 | setAllUsers(data) 15 | })() 16 | }, []) 17 | return ( 18 | <> 19 |
    20 | 33 |
    34 |
    35 |
    Applicant(s)
    36 |
    Email
    37 |
    Phone Number
    38 |
    Address
    39 |
    ACN
    40 |
    Given Name
    41 |
    Family Name
    42 |
    43 |
    44 | {allUsers.map((item, i) => 45 |
    46 |
    47 | logo e.currentTarget.src = "/no-avatar.png"} width={100} height={150} /> 48 |
    49 |
    {item.name}
    50 |
    {item.email}
    51 |
    {item.phone_number}
    52 |
    {item.address}
    53 |
    {item.ACN}
    54 |
    {item.given_name}
    55 |
    {item.family_name}
    56 |
    57 | )} 58 |
    59 |
    60 | 61 | ) 62 | } 63 | 64 | AdminChat.getLayout = TMCheckLayout; 65 | 66 | export const getServerSideProps = ServerSidePropsAdminAuthorized; 67 | 68 | export default AdminChat; -------------------------------------------------------------------------------- /src/pages/api/chatsocket.ts: -------------------------------------------------------------------------------- 1 | import { Server, Socket } from "socket.io"; 2 | import { Request, Response } from "express"; 3 | import { DefaultEventsMap } from "socket.io/dist/typed-events"; 4 | let channels: { channel: string, username: string }[] = []; 5 | 6 | function SocketHandler(req: any, res: any) { 7 | // It means that socket server was already initialised 8 | if (res.socket.server.io) { 9 | console.log("Already set up"); 10 | res.end(); 11 | return; 12 | } 13 | 14 | const io = new Server(res.socket.server); 15 | res.socket.server.io = io; 16 | 17 | const onConnection = async (socket: Socket) => { 18 | // const { channel: _chanelArr } = socket.handshake.query; // Extract the channel from the handshake query 19 | // const channels: string[] = JSON.parse(_chanelArr as string); 20 | 21 | //! here to handle START 22 | socket.on("createdMessage", ({ channel, author, message, key }: { channel: string, author: string, message: string, key: string }) => { 23 | socket.to(channel).emit(`newIncomingMessage`, { channel, author, message, key }); 24 | socket.emit('deliveredToServer', { channel, author, message, key }); 25 | }); 26 | socket.on('typing', ({ channel, author, message }: { channel: string, author: string, message: 'start' | 'end' }) => { 27 | socket.to(channel).emit(`newIncomingTyping`, { channel, author, message }); 28 | }) 29 | socket.on('viewed', ({ channel, author, message }: { channel: string, author: string, message: string }) => { 30 | socket.to(channel).emit(`newIncomingViewed`, { channel, author, message }); 31 | }) 32 | socket.on('repeatMsg', ({ channel, author, message, key }: { channel: string, author: string, message: string, key: string }) => { 33 | socket.to(channel).emit(`newIncomingRepeatMsg`, { channel, author, message, key }); 34 | }) 35 | socket.on('joinChannel', ({ channel, username }) => { 36 | socket.join(channel); 37 | if (username !== 'admin' && !(new Set(channels.map(chs => chs.channel))).has(channel)) { 38 | channels = Array.from(new Set([...channels, { channel, username }])); // Add channel to the list only if it's not already present 39 | } 40 | if (username !== 'admin') { 41 | socket.to('admin').emit(`channelCreated`, { channel, username }) 42 | } 43 | // io.emit('updateChannels', channels); // Notify all clients about the updated channel list 44 | if (username === 'admin_initial') { 45 | // socket.to('admin').emit(`updateChannels`, channels) 46 | console.log(channels); 47 | channels.filter(chn => chn.channel !== 'admin').forEach(chn => io.emit(`channelCreated`, { channel: chn.channel, username: chn.username })) 48 | } 49 | console.log('rooms', socket.rooms); 50 | }); 51 | socket.on('disconnect', () => { 52 | console.log(`User disconnected: socket's Id = ${socket.id}`); 53 | }); 54 | socket.emit('updateChannels', channels); 55 | //! here to handle END 56 | }; 57 | 58 | // Define actions inside 59 | io.on("connection", onConnection); 60 | 61 | console.log("Setting up socket"); 62 | res.end(); 63 | } 64 | 65 | export default SocketHandler -------------------------------------------------------------------------------- /src/components/UploadLogo.tsx: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import Image from "next/image"; 3 | import { useEffect, useRef, useState } from "react"; 4 | import ProgressLinearWithValueLabel from "./ProgressBar"; 5 | 6 | const UploadLogo = ({ image: { imageDataUrl, setImageDataUrl } }: { image: { imageDataUrl: string | undefined, setImageDataUrl: React.Dispatch> } }) => { 7 | const ref = useRef(null); 8 | const [uploadProgress, setUploadProgress] = useState(0); 9 | 10 | useEffect(() => { 11 | if (uploadProgress === 100) setUploadProgress(0) 12 | }, [uploadProgress]) 13 | 14 | const handleFileInputChange = async (event: React.ChangeEvent) => { 15 | const file = event.target.files?.[0]; 16 | 17 | if (!file) { 18 | return; 19 | } 20 | const formData = new FormData(); 21 | formData.append('image', file); 22 | try { 23 | const { data: { filename } } = await axios.post('/api/upload', formData, { 24 | onUploadProgress: (progressEvent) => { 25 | const progress = Math.round( 26 | (progressEvent.loaded / (progressEvent.total ? progressEvent.total : 10000000000)) * 100 27 | ); 28 | setUploadProgress(progress); 29 | }, 30 | }); 31 | setImageDataUrl(filename); 32 | // Handle success 33 | } catch (error) { 34 | // Handle error 35 | } 36 | } 37 | 38 | return ( 39 |
    40 |
    41 | { 42 | imageDataUrl ? 43 |
    44 | img 45 | 46 |
    : 47 | uploadProgress === 0 ? 48 |
    { ref.current?.click() }} className="flex flex-col gap-4 items-center self-center cursor-pointer"> 49 |
    50 | 51 |
    52 |
    53 |

    Choose file or drag here

    54 |

    Size limit: 10MB

    55 |
    56 |
    : 57 |
    58 |

    Uploading logo file...

    59 | 60 |
    61 | } 62 |
    63 | 64 |
    65 | ) 66 | } 67 | 68 | export default UploadLogo -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "file-trade-mark", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "node server", 7 | "dev": "next dev", 8 | "build": "next build", 9 | "start": "next start", 10 | "lint": "next lint" 11 | }, 12 | "dependencies": { 13 | "@emotion/react": "^11.11.0", 14 | "@emotion/styled": "^11.11.0", 15 | "@mdi/js": "^7.0.96", 16 | "@mui/icons-material": "^5.11.16", 17 | "@mui/material": "^5.13.3", 18 | "@reduxjs/toolkit": "^1.8.5", 19 | "@stripe/react-stripe-js": "^2.1.1", 20 | "@stripe/stripe-js": "^1.54.1", 21 | "axios": "^1.4.0", 22 | "bcryptjs": "^2.4.3", 23 | "body-parser": "^1.20.2", 24 | "chart.js": "^3.9.1", 25 | "cookies": "^0.8.0", 26 | "cors": "^2.8.5", 27 | "css-loader": "^6.5.2", 28 | "dotenv": "^16.1.4", 29 | "draft-js": "^0.11.7", 30 | "draftjs-to-html": "^0.9.1", 31 | "express": "^4.18.2", 32 | "formik": "^2.2.9", 33 | "fs": "^0.0.1-security", 34 | "google-auth-library": "^8.8.0", 35 | "google-map-react": "^2.2.1", 36 | "https": "^1.0.0", 37 | "js-cookie": "^3.0.5", 38 | "jsonwebtoken": "^8.5.1", 39 | "mini-css-extract-plugin": "^2.7.6", 40 | "mongoose": "^7.2.2", 41 | "morgan": "^1.10.0", 42 | "multer": "^1.4.5-lts.1", 43 | "mysql": "^2.18.1", 44 | "natural": "^6.5.0", 45 | "next": "^13.4.4", 46 | "nodemailer": "^6.9.3", 47 | "nodemon": "^2.0.22", 48 | "nookies": "^2.5.2", 49 | "numeral": "^2.0.6", 50 | "path": "^0.12.7", 51 | "postcss": "^8.4.23", 52 | "postcss-cli": "^10.1.0", 53 | "postcss-import": "^14.1.0", 54 | "postcss-loader": "^6.1.1", 55 | "postcss-nesting": "^11.2.2", 56 | "react": "^18.2.0", 57 | "react-avatar": "^5.0.3", 58 | "react-chartjs-2": "^4.3.1", 59 | "react-dom": "^18.2.0", 60 | "react-draft-wysiwyg": "^1.15.0", 61 | "react-google-autocomplete": "^2.7.3", 62 | "react-icons": "^4.9.0", 63 | "react-phone-input-2": "^2.15.1", 64 | "react-redux": "^8.0.2", 65 | "react-swipeable-views-react-18-fix": "^0.14.1", 66 | "sass": "^1.62.1", 67 | "sass-loader": "^13.3.0", 68 | "socket.io": "^4.7.1", 69 | "socket.io-client": "^4.7.1", 70 | "string-similarity": "^4.0.4", 71 | "stripe": "^12.12.0", 72 | "style-loader": "^3.3.1", 73 | "swr": "^1.3.0", 74 | "uuid": "^9.0.0" 75 | }, 76 | "devDependencies": { 77 | "@tailwindcss/forms": "^0.5.2", 78 | "@types/bcryptjs": "^2.4.2", 79 | "@types/cookies": "^0.7.7", 80 | "@types/express": "^4.17.17", 81 | "@types/jsonwebtoken": "^9.0.2", 82 | "@types/mongodb": "^4.0.7", 83 | "@types/multer": "^1.4.7", 84 | "@types/mysql": "^2.15.21", 85 | "@types/node": "18.7.16", 86 | "@types/nodemailer": "^6.4.8", 87 | "@types/numeral": "^2.0.2", 88 | "@types/react-redux": "^7.1.24", 89 | "@types/react-swipeable-views": "^0.13.2", 90 | "@types/string-similarity": "^4.0.0", 91 | "@types/uuid": "^9.0.2", 92 | "@typescript-eslint/eslint-plugin": "^5.37.0", 93 | "@typescript-eslint/parser": "^5.37.0", 94 | "autoprefixer": "^10.4.0", 95 | "eslint": "^8.23.1", 96 | "eslint-config-next": "^13.0.4", 97 | "eslint-config-prettier": "^8.5.0", 98 | "prettier": "^2.7.1", 99 | "tailwindcss": "^3.3.0", 100 | "typescript": "^4.8.3" 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/components/Login.tsx: -------------------------------------------------------------------------------- 1 | import { AuthStatus } from "@/types/interface"; 2 | import { validateEmail } from "@/types/utils"; 3 | import axios from "axios"; 4 | import { useRouter } from "next/router"; 5 | import { useState } from "react"; 6 | 7 | const Login = ({ openState: { open, setOpen }, setMsg }: { openState: { open: boolean, setOpen: React.Dispatch> }, setMsg: React.Dispatch> }) => { 8 | const router = useRouter() 9 | const [validEmail, setValidEmail] = useState(true); 10 | const [validPassword, setValidPassword] = useState(true); 11 | const [formData, setFormData] = useState({ 12 | email: '', 13 | password: '' 14 | }) 15 | 16 | const handleClick = async () => { 17 | //! Validate 18 | const { email, password } = formData; 19 | setValidEmail(validateEmail(email)); 20 | if (!validateEmail(email)) return; 21 | setValidPassword(password.trim() !== ""); 22 | if (password.trim() === "") return; 23 | if (email.endsWith("@gmail.com")) { 24 | setMsg("Please use Google Sign above."); 25 | setOpen(true); 26 | return; 27 | } 28 | //! Validate 29 | const { data: { authStatus } }: { data: { authStatus: AuthStatus } } = await axios.post('/api/login', formData); 30 | switch (authStatus) { 31 | case "PASSED": 32 | router.push('dashboard'); 33 | break; 34 | case "UNREGISTER_USER": 35 | setMsg("Your email is not registered. Please sign up first.") 36 | setOpen(true); 37 | break; 38 | case "INVALID_PASSWORD": 39 | setMsg("Password is not valid") 40 | setOpen(true); 41 | default: 42 | break; 43 | } 44 | } 45 | const handleChange = (e: React.ChangeEvent) => { 46 | const { name, value } = e.target; 47 | setFormData(prev => ({ ...prev, [name]: value })) 48 | } 49 | return ( 50 |
    51 |
    52 |
    53 | 54 | 55 |
    56 | {!validEmail &&

    *Invalid email type. Please fill in correct type.

    } 57 |
    58 |
    59 |
    60 | 61 | 62 |
    63 | {!validPassword &&

    *Please enter your password correctly.

    } 64 |
    65 |
    Forgot password?
    66 | 67 |
    68 | ) 69 | } 70 | 71 | export default Login -------------------------------------------------------------------------------- /src/components/UserInfoAvatar.tsx: -------------------------------------------------------------------------------- 1 | import { User } from "@/types/interface" 2 | import axios from "axios" 3 | import Image from "next/image" 4 | import { useRouter } from "next/router" 5 | import { useEffect, useState } from "react" 6 | const UserInfoAvatar = ({ email }: { email: string }) => {//{ user }: { user: User } 7 | const router = useRouter(); 8 | const [user, setUser] = useState() 9 | useEffect(() => { 10 | if (email) { 11 | (async () => { 12 | const { data: { data } } = await axios.get(`/api/users?email=${encodeURIComponent(email)}`); 13 | setUser(data[0]) 14 | })() 15 | } else { 16 | setUser(undefined) 17 | return; 18 | } 19 | }, [email]) 20 | const handleLogout = () => { 21 | axios.get('/api/logout'); 22 | router.push('/') 23 | } 24 | return ( 25 |
    26 | { 27 | user ? 28 |
    29 | 30 |
    31 |

    {user.name} { 32 | // JSON.stringify(user) 33 | }

    34 | logo e.currentTarget.src = "/no-avatar.png"} width={40} height={40} /> 35 | 36 |
    37 |
    38 |
    39 |

    router.push('/profile')} className="hover:bg-[#efefef] p-2 rounded-md flex items-center gap-3 transition-all duration-1000 hover:text-[18px] h-44 ease-in-out active:bg-red-700"> 40 | 41 | Profile 42 |

    43 |

    44 | 45 | Setting 46 |

    47 |
    48 |

    49 | 50 | Log out 51 |

    52 |
    53 |
    54 |
    55 | : 56 | 61 | } 62 |
    63 | ) 64 | } 65 | export default UserInfoAvatar; -------------------------------------------------------------------------------- /src/components/PortalClass.tsx: -------------------------------------------------------------------------------- 1 | import { Checkbox, FormControlLabel, FormGroup } from "@mui/material" 2 | import { useContext, useEffect, useRef, useState } from "react"; 3 | import { ClassBadge } from "../pages/classify"; 4 | import { PiniaStore } from "@/store/store"; 5 | 6 | const MyCheckbox = ({ label, handleClick, id, checkedItems }: { label: string, handleClick: (_: { name: string, value: boolean, id: string }) => void, id: string, checkedItems: any[] }) => { 7 | 8 | return ( 9 | item.id === id) : false} onChange={(e: React.ChangeEvent) => handleClick({ 10 | name: label, 11 | value: e.target.checked, 12 | id: id 13 | })} />} label={label} /> 14 | ) 15 | } 16 | 17 | const PortalClass = ({ classNo, products, title, setShowBottomCostBar }: { classNo: string, products: any[], title: string, setShowBottomCostBar: React.Dispatch> }) => { 18 | const { pinia, setPinia } = useContext(PiniaStore); 19 | const [divHeight, setDivHeight] = useState(0); 20 | const contentRef = useRef(null); 21 | 22 | useEffect(() => { 23 | if (contentRef.current) { 24 | setDivHeight(contentRef.current.scrollHeight); 25 | } 26 | }, []); 27 | 28 | const [collapsed, setCollapsed] = useState(true); 29 | const handleCollapse = () => { 30 | setCollapsed(pre => (!pre)); 31 | } 32 | 33 | const handleCheckboxClick = ({ name, value, id }: { name: string, value: boolean, id: string }) => { 34 | const p_classes = pinia.classes ? (pinia.classes[classNo] ? pinia.classes[classNo] : []) : []; console.log(p_classes) 35 | setShowBottomCostBar(true) 36 | setPinia({ 37 | ...pinia, classes: { 38 | ...pinia.classes, 39 | [classNo]: value ? 40 | [...p_classes, { 41 | id: id, 42 | tmClass: classNo, 43 | description: name, 44 | }] : 45 | p_classes.filter(elem => elem.id !== id) 46 | } 47 | }) 48 | } 49 | 50 | return ( 51 |
    52 |
    53 |

    {title}

    54 | 55 |
    56 | 57 | {products && products.slice(0, 5).map((product, index) => )} 58 | 59 | {products.length > 5 && ( 60 | <> 61 |
    62 | 66 |
    67 | 68 | {products && products.slice(5).map((product, index) => )} 69 | 70 |
    71 | 72 | )} 73 |
    74 | ) 75 | } 76 | 77 | export default PortalClass -------------------------------------------------------------------------------- /public/settings-cogwheel-svgrepo-com.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 31 | 32 | 35 | -------------------------------------------------------------------------------- /src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image" 2 | import Link from "next/link"; 3 | import UserInfoAvatar from "./UserInfoAvatar"; 4 | import { useRouter } from "next/router"; 5 | import jwt from 'jsonwebtoken' 6 | import { useEffect, useState } from "react"; 7 | import { User } from "@/types/interface"; 8 | import { parseCookies } from "nookies"; 9 | import { ADMIN_LIST, JWT_SIGN_KEY } from "@/types/utils"; 10 | 11 | export const verifyToken = () => { 12 | let _user_: { email: string } | undefined; 13 | const cookies = parseCookies(); 14 | const token = cookies.token; 15 | try { 16 | _user_ = jwt.verify(token, JWT_SIGN_KEY) as { email: string } 17 | } catch (error) { 18 | _user_ = undefined; 19 | } 20 | return _user_; 21 | } 22 | 23 | const Header = () => { 24 | const [userEmail, setUserEmail] = useState(''); 25 | const router = useRouter(); 26 | const setUseremailFromToken = () => { 27 | const email = verifyToken()?.email; 28 | setUserEmail(email as string) 29 | } 30 | useEffect(() => setUseremailFromToken(), []) 31 | useEffect(() => { 32 | const handleRouteChange = (url: string) => { 33 | setTimeout(() => { setUseremailFromToken() }, 1000); 34 | }; 35 | 36 | router.events.on('routeChangeStart', handleRouteChange); 37 | 38 | return () => { 39 | router.events.off('routeChangeStart', handleRouteChange); 40 | }; 41 | }, []); 42 | 43 | return ( 44 | <> 45 | 46 |
    47 | {/* 373f86 border-b-[5px] border-[#DE4326] */} 48 |
    49 |
    50 | 51 | 52 | 57 |
    58 | {/* */} 59 | 60 |
      61 |
    • About Us
    • 62 |
    • Services
    • 63 |
    • Pricing
    • 64 |
    • Resources
    • 65 |
    • router.push('/checkout')} className="hover:border-b border-black">Apply Filing
    • 66 | {ADMIN_LIST.some(em => em === userEmail) && <> 67 |
    • router.push('/adminchat')} className="hover:border-b border-black text-red-600 font-mont">Chat with users
    • 68 |
    • router.push('/adminusers')} className="hover:border-b border-black text-red-600 font-mont">User manangement
    • 69 | } 70 |
    71 |
    72 | 84 |
    85 |
    86 | 87 | ) 88 | } 89 | 90 | export default Header -------------------------------------------------------------------------------- /src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | import Script from 'next/script' 3 | import type { AppProps } from 'next/app' 4 | import type { ReactElement, ReactNode } from 'react' 5 | import type { NextPage } from 'next' 6 | import Head from 'next/head' 7 | import '../css/main.css' 8 | import { PiniaStore } from '@/store/store' 9 | import MySVG from '../components/svg' 10 | 11 | export type NextPageWithLayout

    , IP = P> = NextPage & { 12 | getLayout?: (page: ReactElement) => ReactNode 13 | } 14 | 15 | type AppPropsWithLayout = AppProps & { 16 | Component: NextPageWithLayout 17 | user?: string 18 | } 19 | 20 | function MyApp({ Component, pageProps }: AppPropsWithLayout) { 21 | // Use the layout defined at the page level, if available 22 | const getLayout = Component.getLayout || ((page) => page) 23 | 24 | const title = `Trademark Today Filing` 25 | const description = 'Trademarktoday supports free initial trade mark check in minutes and registration of your trademark for Australia. Please kick off the process of protecting your brand and have some fun while doing it!' 26 | const imageWidth = '1920' 27 | const imageHeight = '960' 28 | const url = 'https://trademarktoday-nextjs.vercel.app' 29 | const image = 'https://trademarktoday-nextjs.vercel.app/01.png' 30 | const [pinia, setPinia] = useState({}); 31 | 32 | useEffect(() => { 33 | const _pinia = JSON.parse(localStorage.getItem('pinia') as string); 34 | setPinia(_pinia); 35 | }, []) 36 | 37 | useEffect(() => { 38 | localStorage.setItem('pinia', JSON.stringify(pinia)); 39 | }, [pinia]) 40 | 41 | return ( 42 | <> 43 | { 44 | getLayout( 45 | (<> 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | Trade Mark Today for Australia 66 | 67 | 68 | 69 | 82 | 83 | 84 | {/* ****************************************************************** */} 85 | {/*

    86 |
    87 |
    */} 88 | 89 | 90 | 91 | {/*
    92 |
    93 |
    */} 94 | {/* ****************************************************************** */} 95 | 96 | ) 97 | ) 98 | } 99 | 100 | ) 101 | } 102 | 103 | export default MyApp -------------------------------------------------------------------------------- /src/components/PortalSummaryB.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import { ReactNode, useContext, useEffect, useRef, useState } from "react"; 3 | import { ClassBadge } from "../pages/classify"; 4 | import Image from "next/image"; 5 | import { PiniaStore } from "@/store/store"; 6 | 7 | const PortalSummaryB = () => { 8 | const { pinia, setPinia } = useContext(PiniaStore); 9 | const [divHeight, setDivHeight] = useState(0); 10 | const contentRef = useRef(null); 11 | 12 | useEffect(() => { 13 | if (contentRef.current) { 14 | setDivHeight(contentRef.current.scrollHeight); 15 | } 16 | }, [pinia]); 17 | 18 | const [collapsed, setCollapsed] = useState(true); 19 | const handleCollapse = () => { 20 | setCollapsed(pre => (!pre)); 21 | } 22 | 23 | return ( 24 |
    25 |
    26 | 33 |
    34 |
    35 |
    36 |
    37 | { 38 | pinia?.markType === 'Word' ? 39 | {pinia.word} : 40 |
    41 | img e.currentTarget.src = "/no-avatar.png"} width={200} height={200} /> 42 |
    43 | } 44 | Edit 45 |
    46 |
    47 |
    48 |
    49 |
    50 |

    Goods or services

    51 | Total cost is based on how many classes your trade mark contains. 52 |
    53 | Edit 54 |
    55 | {pinia?.classes !== undefined && Object.keys(pinia.classes).map((classKey: string, index: number) => ( 56 |
    57 | {pinia.classes && pinia.classes[classKey] && pinia.classes[classKey].map((item, index) => ( 58 | 59 | {item.description} 60 | 61 | ))} 62 |
    63 | 64 | {index > 0 ?
    $590$490
    : $590} 65 |
    66 |
    67 |
    68 | ))} 69 |
    70 | Total 71 | ${(pinia?.classes !== undefined && !(Object.keys(pinia.classes).length === 0 && pinia.classes.constructor === Object)) ? (Object.keys(pinia.classes).length * 590 - (Object.keys(pinia.classes).length - 1) * 100) : 0} 72 |
    73 |
    74 |
    75 |
    76 |
    77 |
    78 | ) 79 | } 80 | 81 | export default PortalSummaryB -------------------------------------------------------------------------------- /src/pages/consider.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import Checkbox from '@mui/material/Checkbox'; 3 | import PortalConsider from "../components/PortalConsider"; 4 | import ProgressPane from "../components/ProgressPane"; 5 | import { useContext, useEffect, useState } from "react"; 6 | import { useRouter } from "next/router"; 7 | import ProgressIndicator from "../components/ProgressIndicator"; 8 | import { AlertErr } from "../components/AlertContainers"; 9 | import TMCheckLayout from "../layout/TMCheckLayout"; 10 | import { PiniaStore } from "@/store/store"; 11 | import Chat from "@/components/Chat"; 12 | 13 | const Consider = () => { 14 | const { pinia, setPinia } = useContext(PiniaStore); 15 | const router = useRouter(); 16 | const [checked, setChecked] = useState(false); 17 | const [showAlertForCheck, setShowAlertForCheck] = useState(false); 18 | const [showAlert, setShowAlert] = useState(false); 19 | 20 | useEffect(() => { 21 | if (pinia?.acceptedTerms === undefined) return; 22 | setChecked(pinia?.acceptedTerms as boolean) 23 | }, [pinia]) 24 | 25 | const handleClick = () => { 26 | if (!checked) { 27 | setShowAlertForCheck(true) 28 | setShowAlert(true); 29 | window.scrollTo(0, 0) 30 | } else { 31 | router.push("/select") 32 | } 33 | } 34 | 35 | const handleCheck = (e: React.ChangeEvent) => { 36 | setChecked(e.target.checked) 37 | setShowAlertForCheck(!e.target.checked); 38 | setPinia({ ...pinia, acceptedTerms: e.target.checked }) 39 | } 40 | 41 | return ( 42 | <> 43 |
    44 |
    45 | 46 | 47 |
    48 |

    Key things to watch for

    49 | 53 | 57 | 61 | 65 | 69 |
    70 |

    Trade marks can be complex

    71 |

    72 | Results from the free preliminary trade mark search cannot guarantee an outcome if you decide to apply. If you need assistance, consider chatting with one of our   73 | 74 | Australian registered trade marks attorney  75 | 76 | . 77 |

    78 |
    79 |
    80 |
    81 | 82 |

    83 | I have read the 84 | 85 | disclaimer 86 | 87 | and 88 | 89 | privacy notice 90 | . 91 |

    92 |
    93 | {showAlertForCheck &&

    You must acknowledge you have read the disclaimer and privacy notice to continue.

    } 94 |
    95 |
    96 |
    97 |
    98 | 99 |
    100 |
    101 | 102 |
    103 |
    104 | 105 | ) 106 | } 107 | 108 | Consider.getLayout = TMCheckLayout; 109 | 110 | export default Consider; -------------------------------------------------------------------------------- /public/tmchecker.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/pages/api/sendmail.ts: -------------------------------------------------------------------------------- 1 | import Nodemailer, { SentMessageInfo, SendMailOptions } from 'nodemailer'; 2 | import { Request, Response } from 'express'; 3 | 4 | export default function handler(req: Request, res: Response): void { 5 | const { email, code } = req.query; 6 | const transporter = Nodemailer.createTransport({ 7 | // host: 'smtp.gmail.com', 8 | // port: 465, 9 | // service: 'gmail', 10 | // secure: true, 11 | host: "smtp.gmail.com", 12 | port: 587, 13 | secure: false, 14 | auth: { 15 | user: process.env.GMAIL_USER, 16 | pass: process.env.GMAIL_AUTH 17 | } 18 | }); 19 | const mailOptions: SendMailOptions = { 20 | from: process.env.GMAIL_USER, 21 | to: email as string, 22 | subject: 'Trademark today verfication', 23 | html: `
    24 |
    25 | 28 | 29 | 30 | 36 | 37 | 38 | 39 | 42 | 43 | 44 | 54 | 55 | 56 | 62 | 63 | 64 | 69 | 70 | 71 | 72 | 73 | 74 | 76 | 77 | 78 | 87 | 88 | 89 | 90 | 91 | 92 |
    93 |
    ` 94 | }; 95 | transporter.sendMail(mailOptions, (error: Error | null, info: SentMessageInfo) => { 96 | if (error) { 97 | console.log(error); 98 | res.status(200).json({ message: error }) 99 | } else { 100 | console.log('Email sent: ' + info.response); 101 | res.status(200).json({ message: info.response }) 102 | } 103 | }); 104 | //{"message":"250 2.0.0 OK 1687813731 hn8-20020a05600ca38800b003fa722e8b48sm11760285wmb.32 - gsmtp"} 105 | } -------------------------------------------------------------------------------- /src/pages/api/_testApi/testsearch.ts: -------------------------------------------------------------------------------- 1 | import mysqldb from "@/db/mysqldb"; 2 | import natural, { TfIdf, WordNet } from 'natural'; 3 | import stringSimilarity from 'string-similarity'; 4 | import { Request, Response } from "express"; 5 | export default function handler(req: Request, res: Response) { 6 | if (req.method === 'POST') { 7 | 8 | const userInput = req.body.search; 9 | 10 | getSynonyms(userInput) 11 | .then((similarWords) => { 12 | console.log(similarWords); 13 | res.status(200).json(similarWords) 14 | // Use the similar words retrieved from WordNet 15 | }) 16 | .catch((error) => { 17 | console.error(error); 18 | res.status(200).json(error) 19 | // Handle errors 20 | }); 21 | // intelligentSearch(req, res, req.body.search); 22 | } else { 23 | res.status(405).json({ message: 'Method not allowed' }) 24 | } 25 | } 26 | const getSynonyms = (inputWord:string) => { 27 | return new Promise((resolve, reject) => {9 28 | const wordnet = new WordNet(); 29 | wordnet.lookup(inputWord, (definitions) => { 30 | { 31 | const similarWords = definitions.reduce((words:string[], definition) => { 32 | definition.synonyms.forEach((synonym) => { 33 | if (!words.includes(synonym)) 34 | { 35 | words.push(synonym); 36 | } 37 | }); 38 | return words; 39 | }, []); 40 | resolve(similarWords); 41 | } 42 | }); 43 | }); 44 | }; 45 | 46 | //! From here remove it. 47 | // async function intelligentSearch(req: Request, res: Response, userInput: string) { 48 | 49 | 50 | // mysqldb.query('SELECT keyword FROM keywords', (err, results) => { 51 | // if (err) { 52 | // console.error('Error executing search query:', err); 53 | // return; 54 | // } 55 | // const relevantKeywords = results.map(result => result.keyword); 56 | // const matches = stringSimilarity.findBestMatch(userInput, relevantKeywords); 57 | // const matchedKeywords = matches.ratings.filter((match) => match.rating > 0.7).map((match) => match.target); 58 | // console.log(matchedKeywords) 59 | // if (matchedKeywords.length === 0) { 60 | // res.status(204).json([]); 61 | // return; 62 | // } 63 | // // Query the database for matching records 64 | // const searchQuery = ` 65 | // SELECT * FROM products 66 | // WHERE product LIKE '%${matchedKeywords.join("%' OR product LIKE '%")}%' LIMIT 10 67 | // `; 68 | // mysqldb.query(searchQuery, (err, results) => { 69 | // if (err) { 70 | // console.error('Error executing search query:', err); 71 | // return; 72 | // } 73 | 74 | // // Process and display the search results 75 | // console.log('Search Results:'); 76 | // results.forEach((result) => { 77 | // console.log(result); 78 | // }); 79 | // return res.status(200).json(results) 80 | // }); 81 | // }); 82 | // // const tokenizer = new natural.WordTokenizer(); 83 | // // const query = 'SELECT product FROM products'; 84 | // // db.query(query, (error: MysqlError | null, rows: { product: string }[]) => { 85 | // // if (error) { 86 | // // console.error('Error retrieving data from the database:', error); 87 | // // return; 88 | // // } 89 | // // console.log("COUNT: " + rows.length) 90 | // // // Extract keywords using TF-IDF 91 | // // const tfidf = new TfIdf(); 92 | // // rows.forEach((row) => { 93 | // // const descriptionTokens = tokenizer.tokenize(row.product); 94 | // // const addToDoc = descriptionTokens ? descriptionTokens.join(' ') : ''; 95 | // // tfidf.addDocument(addToDoc); 96 | // // }); 97 | // // console.log(tfidf.listTerms(0)) 98 | // // for (let i = 0; i < tfidf.documents.length; i++) { 99 | // // const terms = tfidf.listTerms(i); 100 | 101 | // // terms.forEach((term) => { 102 | // // relevantKeywords.push(term.term); 103 | // // console.log("relevant keywords: " + term.term); 104 | // // }); 105 | // // } 106 | // // fs.writeFile('output.txt', relevantKeywords.join('\r\n'), (err) => { 107 | // // if (err) { 108 | // // console.error('Error writing to file:', err); 109 | // // } else { 110 | // // console.log('Output has been written to output.txt'); 111 | // // } 112 | // // }); 113 | // // const matches = stringSimilarity.findBestMatch(userInput, relevantKeywords); 114 | // // console.log(matches) 115 | // // const matchedKeywords = matches.ratings.filter((match) => match.rating > 0.5).map((match) => match.target); 116 | // // if (matchedKeywords.length === 0) { 117 | // // res.status(204).json([]); 118 | // // return; 119 | // // } 120 | // // // Query the database for matching records 121 | // // const searchQuery = ` 122 | // // SELECT * FROM products 123 | // // WHERE product LIKE '%${matchedKeywords.join("%' OR product LIKE '%")}%' LIMIT 10 124 | // // `; 125 | // // db.query(searchQuery, (err, results) => { 126 | // // if (err) { 127 | // // console.error('Error executing search query:', err); 128 | // // return; 129 | // // } 130 | 131 | // // // Process and display the search results 132 | // // console.log('Search Results:'); 133 | // // results.forEach((result) => { 134 | // // console.log(result); 135 | // // }); 136 | // // return res.status(200).json(results) 137 | // // }); 138 | // // }); 139 | // } 140 | 141 | -------------------------------------------------------------------------------- /src/pages/checkout.tsx: -------------------------------------------------------------------------------- 1 | import TMCheckLayout from '../layout/TMCheckLayout'; 2 | import ServerSidePropsAuthorized from '@/layout/ServerSidePropsAuthorized'; 3 | import Chat from '@/components/Chat'; 4 | import Image from 'next/image'; 5 | import dotenv from 'dotenv' 6 | dotenv.config({ path: "./.env" }); 7 | import { loadStripe } from '@stripe/stripe-js'; 8 | 9 | const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY as string); 10 | 11 | import { useContext, useEffect, useState } from 'react'; 12 | import { PiniaStore } from '@/store/store'; 13 | import axios from 'axios'; 14 | import { ClassBadge } from './classify'; 15 | import { useRouter } from 'next/router'; 16 | import { generateRandomKey, hash } from '@/types/utils'; 17 | 18 | const ChecoutItemA = ({ title, msg }: { title: string, msg: string }) => { 19 | return ( 20 | <> 21 |

    22 | 23 |
    24 |

    {title}

    25 |

    {msg}

    26 |
    27 |

    28 | 29 | ) 30 | } 31 | 32 | const Checkout = ({ email }: { email: string }) => { 33 | const { pinia, setPinia } = useContext(PiniaStore); 34 | const [price, setPrice] = useState(0) 35 | const router = useRouter(); 36 | useEffect(() => { 37 | if ((pinia?.classes !== undefined && !(Object.keys(pinia.classes).length === 0 && pinia.classes.constructor === Object))) { 38 | const price_value = (Object.keys(pinia.classes).length * 590 - (Object.keys(pinia.classes).length - 1) * 100); 39 | if (price_value === 0) { 40 | router.push('/apply'); 41 | } else { 42 | setPrice(price_value) 43 | } 44 | } else { 45 | if (pinia?.initiated) { 46 | router.push('/apply'); 47 | } 48 | } 49 | }, [pinia]) 50 | const handlePay = async () => { 51 | if (!price || price === 0) { 52 | // router.push('/apply'); 53 | return; 54 | } 55 | const stripe = await stripePromise; 56 | const transactionKey = generateRandomKey(16); 57 | sessionStorage.setItem('transactionKey', await hash(transactionKey)); 58 | const { data: { id } } = await axios.post('/api/create-checkout-session', { price: price + 200, transactionKey }); console.log(id) 59 | // const session = await response.json(); console.log(session) 60 | const result = await stripe?.redirectToCheckout({ sessionId: id }); 61 | 62 | if (result?.error) { 63 | // Handle error 64 | console.error(result.error.message); 65 | } 66 | }; 67 | 68 | return ( 69 | <> 70 |
    71 |
    72 |
    73 | img e.currentTarget.src = "/no-avatar.png"} width={600} height={200} /> 74 |
    75 |

    {(price + 200).toLocaleString('en-US', { style: 'currency', currency: 'USD' })}

    76 |

    For Trade Mark Filing

    77 |
    78 | 79 |
    80 |
    81 | {pinia?.classes !== undefined && Object.keys(pinia.classes).map((classKey: string, index: number) => ( 82 |
    83 |
    84 | Class {classKey} 85 | {index > 0 ?
    $590$490
    : $590} 86 |
    87 | {/*
    88 | {pinia?.classes !== undefined && pinia.classes[classKey] && pinia.classes[classKey].map((item, index_inner) => ( 89 | 92 | ))} 93 |
    94 |
    95 | */} 96 |
    97 | ))} 98 |
    99 | Sub Total 100 | ${(pinia?.classes !== undefined && !(Object.keys(pinia.classes).length === 0 && pinia.classes.constructor === Object)) ? (Object.keys(pinia.classes).length * 590 - (Object.keys(pinia.classes).length - 1) * 100) : 0} 101 |
    102 |
    103 |
    104 | 105 | 106 | 107 |
    108 | 109 |
    110 |
    111 |
    112 |
    113 | 114 | 115 | ) 116 | } 117 | 118 | Checkout.getLayout = TMCheckLayout; 119 | 120 | export const getServerSideProps = ServerSidePropsAuthorized; 121 | 122 | export default Checkout; -------------------------------------------------------------------------------- /src/pages/apply.tsx: -------------------------------------------------------------------------------- 1 | import { useContext, useEffect, useState } from "react"; 2 | import WaitingLocker from "../components/WaitingLocker"; 3 | import { TMCheckerElement } from "../components/ProgressIndicator"; 4 | import Link from "next/link"; 5 | import { TimeBarAs } from "../components/PortalSummaryA"; 6 | import { Checkbox } from "@mui/material"; 7 | import { useRouter } from "next/router"; 8 | import { AlertErr } from "../components/AlertContainers"; 9 | import { ConfirmSignForApplyModal } from "../components/Modal"; 10 | import TMCheckLayout from "../layout/TMCheckLayout"; 11 | import Chat from "@/components/Chat"; 12 | import { PiniaStore } from "@/store/store"; 13 | import { verifyConsider } from "./select"; 14 | import { verifySelect } from "./classify"; 15 | import { verifyClassify } from "./summary"; 16 | import { verifyToken } from "@/components/Header"; 17 | 18 | const Apply = () => { 19 | const { pinia, setPinia } = useContext(PiniaStore); 20 | useEffect(() => { 21 | if (Object.keys(pinia).length === 0 && pinia.constructor === Object) { 22 | // router.push('/consider') 23 | return; 24 | } 25 | if (!verifyConsider(pinia)) { 26 | router.push('/consider') 27 | } else if (!verifySelect(pinia)) { 28 | router.push('/select') 29 | } else if (!verifyClassify(pinia)) { 30 | router.push('/classify') 31 | } 32 | }, [pinia]) 33 | const [waiting, setWaiting] = useState(false); 34 | const [checked, setChecked] = useState(false); 35 | const [open, setOpen] = useState(false); 36 | const [showAlertForCheck, setShowAlertForCheck] = useState(false); 37 | const [showAlert, setShowAlert] = useState(false); 38 | const router = useRouter(); 39 | const handleClick = () => { 40 | if (!checked) { 41 | setShowAlertForCheck(true) 42 | setShowAlert(true); 43 | window.scrollTo(0, 0) 44 | } else { 45 | if (verifyToken()) { 46 | router.push('/checkout') 47 | } else { 48 | setOpen(true) 49 | } 50 | } 51 | } 52 | const handleCheck = (e: React.ChangeEvent) => { 53 | setChecked(e.target.checked) 54 | setShowAlertForCheck(!e.target.checked); 55 | } 56 | return ( 57 | <> 58 |
    59 |
    60 | 61 | 62 |
    63 |

    Trade mark application

    64 |

    This process should take a couple of minutes to complete.

    65 |
    66 |

    What you'll need

    67 |
    68 |
    69 | 70 |

    Sign up with Trade Mark Today

    71 |
    72 |
    73 |
    74 |
    75 | 76 |

    Trade mark owner details

    77 |
    78 |
    79 |
    80 |
    81 | 82 |

    Payment method

    83 |
    84 |
    85 |
    86 |
    87 | 88 |

    89 | For more information, read our 90 | 91 | FAQ on applying. 92 | 93 |

    94 |
    95 |
    96 |
    97 |

    Application Process and Costs

    98 | 99 |
    100 |
    101 | 102 |

    I acknowledge that the outcome of this application will be determined by the Examiner at IP Australia

    103 |
    104 | {showAlertForCheck &&

    You must acknowledge your understanding to continue.

    } 105 |
    106 |
    107 |
    108 | 109 |
    110 | 111 |
    112 |
    113 | 117 | 118 | 122 | 123 | 124 |
    125 |
    126 | 127 | ) 128 | } 129 | Apply.getLayout = TMCheckLayout; 130 | 131 | export default Apply; -------------------------------------------------------------------------------- /src/components/PortalSummaryA.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode, useContext, useEffect, useRef, useState } from "react"; 2 | import { BootstrapTooltip } from "../pages/classify"; 3 | import { PiniaStore } from "@/store/store"; 4 | import Image from "next/image"; 5 | 6 | const WrapTimeBar = ({ showBar = true, children }: { showBar?: boolean, children: ReactNode }) => { 7 | return ( 8 | <> 9 |
    10 |
    11 | {/*
    */} 12 | image 13 | {showBar &&
    } 14 |
    15 |
    16 | {children} 17 |
    18 |
    19 | 20 | ) 21 | } 22 | 23 | const TimeBarA = ({ title, description, feeType, fee, tooltip, showBar = true }: { title: string, description: string, feeType?: string, fee?: string, tooltip: ReactNode, showBar?: boolean }) => { 24 | return ( 25 | 26 |

    {title}

    27 |
    28 |

    {description}

    29 | 30 |
    31 | 32 |
    33 |
    34 |
    35 | {feeType &&

    {feeType}

    } 36 | {fee &&

    {fee}

    } 37 |
    38 | ) 39 | } 40 | 41 | export const TimeBarAs = () => { 42 | const { pinia, setPinia } = useContext(PiniaStore); 43 | 44 | return ( 45 |
    46 | 52 | 53 |

    The results of your free check need to be reviewed by an examiner to assess whether your request meets certain legal requirements that are described in the Trade Marks Act 1995.

    54 |
    55 |

    They'll reach out within 5 working days. If there are issues, the examiner will let you know your options for fixing them.

    56 | 57 | } 58 | /> 59 | 63 | 64 |

    *Examination
    65 | During the Examination period, the Examiner may issue an Adverse Examination Report. If an Adverse Report is issued, further costs will be incurred for reporting and filing a response. The costs can vary, depending on the type and number of objections. 66 |

    67 | 68 | } 69 | /> 70 | 74 | 75 |

    International agreements require us to ensure people who file a trade mark in participating countries have six months to apply in Australia. While it is rare for a similar trade mark to be filed during the same time period, the agreements help protect business operators from potential IP Rights conflicts.

    76 |
    77 |

    Each trade mark undergoes a two-month opposition period where others can challenge its registration. Refer to frequently asked questions for additional details.

    78 | 79 | } 80 | /> 81 | 85 | 86 |

    Once registered you can add the registered symbol to all instances of your trade mark. You can legally challenge comparable marks with similar goods and services. It is your responsibility to enforce your rights and use your trade mark correctly on the goods and services you listed for registration.

    87 | 88 | } 89 | /> 90 |
    91 | ) 92 | } 93 | 94 | const PortalSummaryA = () => { 95 | const [divHeight, setDivHeight] = useState(0); 96 | const contentRef = useRef(null); 97 | 98 | useEffect(() => { 99 | if (contentRef.current) { 100 | setDivHeight(contentRef.current.scrollHeight); 101 | } 102 | }, []); 103 | 104 | const [collapsed, setCollapsed] = useState(true); 105 | const handleCollapse = () => { 106 | setCollapsed(pre => (!pre)); 107 | } 108 | 109 | return ( 110 |
    111 |
    112 | 116 |
    117 |
    118 | 119 |
    120 |
    121 |
    122 | ) 123 | } 124 | 125 | export default PortalSummaryA -------------------------------------------------------------------------------- /src/components/Modal.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import Box from '@mui/material/Box'; 3 | import jwt from 'jsonwebtoken' 4 | import { setCookie } from 'nookies'; 5 | 6 | import { JWT_SIGN_KEY, hash } from '@/types/utils'; 7 | import Modal from '@mui/material/Modal'; 8 | import { useRouter } from 'next/router'; 9 | import { OTPStore, PiniaStore } from '@/store/store'; 10 | import axios from 'axios'; 11 | 12 | type ModalType = { 13 | openState: 14 | { 15 | open: boolean, 16 | setOpen: React.Dispatch> 17 | }, 18 | children?: React.ReactNode 19 | } 20 | const style = { 21 | position: 'absolute' as 'absolute', 22 | top: '50%', 23 | left: '50%', 24 | transform: 'translate(-50%, -50%)', 25 | width: 500, 26 | bgcolor: 'background.paper', 27 | border: '2px solid #000', 28 | boxShadow: 24, 29 | p: 4, 30 | } 31 | 32 | const ModalContainer = ({ openState: { open, setOpen }, children, title, msg }: ModalType & { title: string, msg: string }) => { 33 | return ( 34 | setOpen(false)} 37 | aria-labelledby="modal-modal-title" 38 | aria-describedby="modal-modal-description" 39 | > 40 | 41 |
    42 |
    43 |

    {title}

    44 | 47 |
    48 |

    {msg}

    49 | {children} 50 |
    51 |
    52 |
    53 | ) 54 | } 55 | 56 | export const ConfirmStartAgainModal = ({ openState: { open, setOpen }, children }: ModalType) => { 57 | const { pinia, setPinia } = React.useContext(PiniaStore); 58 | const handleOpen = () => setOpen(true); 59 | const handleClose = () => setOpen(false); 60 | const router = useRouter(); 61 | const handleStartAgain = () => { 62 | setPinia({}); 63 | router.push('/select') 64 | } 65 | 66 | return ( 67 |
    68 | {children} 69 | 70 |
    71 | 74 | 77 |
    78 |
    79 |
    80 | ); 81 | } 82 | 83 | export const ConfirmSignForApplyModal = ({ openState: { open, setOpen }, children }: ModalType) => { 84 | const handleOpen = () => setOpen(true); 85 | const handleClose = () => setOpen(false); 86 | const router = useRouter(); 87 | return ( 88 |
    89 | {children} 90 | 91 |
    92 | 95 | 98 |
    99 |
    100 |
    101 | ); 102 | } 103 | 104 | export const OTPModal = ({ openState: { open, setOpen }, setMsg }: { openState: { open: boolean, setOpen: React.Dispatch> }, setMsg: React.Dispatch> }) => { 105 | const { otpState, dispatchOtpState } = React.useContext(OTPStore); 106 | const [code, setCode] = React.useState(''); 107 | const handleChange = (e: React.ChangeEvent) => setCode(e.target.value); 108 | const router = useRouter(); 109 | const onConfirm = async (c: string) => { 110 | if (otpState.code === c) { 111 | const { email, name, password, ACN, address, phone_number } = otpState.formData; 112 | const token = jwt.sign({ email, name, picture: '', ACN, address, phone_number }, JWT_SIGN_KEY); 113 | const { data: _data } = await axios.post('/api/users', { email, name, picture: '', ACN, address, phone_number, password: await hash(password) }) 114 | setCookie(null, 'token', token, { 115 | maxAge: 60 * 60, 116 | path: '/', 117 | }); 118 | router.push('/dashboard'); 119 | } else { 120 | setMsg("Verification code not matching") 121 | setOpen(true); 122 | } 123 | } 124 | 125 | return ( 126 | <> 127 |
    128 |
    129 | 132 |

    Enter verification code

    133 | 134 |
    135 | 136 | 137 |
    138 | 139 |
    140 |
    141 | 142 | ); 143 | } 144 | 145 | export const MessageBoxModal = ({ openState: { open, setOpen }, title, msg }: ModalType & { title: string, msg: string }) => { 146 | return ( 147 | setOpen(false)} 150 | aria-labelledby="modal-modal-title" 151 | aria-describedby="modal-modal-description" 152 | > 153 | 154 |
    155 |
    156 |

    {title}

    157 | 160 |
    161 |

    {msg}

    162 |
    163 | 166 |
    167 |
    168 |
    169 |
    170 | ) 171 | } -------------------------------------------------------------------------------- /src/components/SignUp.tsx: -------------------------------------------------------------------------------- 1 | import { Checkbox } from "@mui/material"; 2 | import axios from "axios"; 3 | import { useRouter } from "next/router"; 4 | import React, { useContext, useEffect, useState } from "react"; 5 | import GoogleAddress from "./GoogleAddress"; 6 | import PhoneInput from 'react-phone-input-2' 7 | import 'react-phone-input-2/lib/style.css' 8 | import { MessageBoxModal, OTPModal } from "./Modal"; 9 | import WaitingLocker from "./WaitingLocker"; 10 | import { OTPStore } from "@/store/store"; 11 | import { validateEmail } from "@/types/utils"; 12 | 13 | interface MyObject { 14 | [key: string]: string | number; 15 | } 16 | 17 | export const queryBuilder = (data: MyObject) => Object.keys(data).map(key => `${key}=${encodeURIComponent(data[key])}`).join('&') 18 | 19 | const genCode = () => { 20 | const randomNumber = Math.floor(Math.random() * 900000) + 100000; 21 | return randomNumber.toString(); 22 | } 23 | 24 | const SignUp = ({ value, openState: { open, setOpen }, setMsg }: { value: number, openState: { open: boolean, setOpen: React.Dispatch> }, setMsg: React.Dispatch> }) => { 25 | const { otpState, dispatchOtpState } = useContext(OTPStore); 26 | const [checked, setChecked] = useState(false); 27 | const router = useRouter(); 28 | 29 | const handleChange = (e: React.ChangeEvent) => { 30 | const { name, value } = e.target; 31 | dispatchOtpState({ type: 'CHANGE_FORMDATA', payload: { value: { [name]: value } } })//({ ...prev, [name]: value }) 32 | } 33 | 34 | const handlePlaceChange = (place: any) => { 35 | console.log(place) 36 | const address = place.name ? place.name : place.formatted_address; 37 | dispatchOtpState({ type: 'CHANGE_FORMDATA', payload: { value: { address } } }) 38 | } 39 | 40 | const handlePhoneChage = (phone: string, cc: any, __: any, phoneformat: string) => { 41 | dispatchOtpState({ type: 'CHANGE_FORMDATA', payload: { value: { phone_number: phoneformat } } }) 42 | } 43 | 44 | //! Validate 45 | const [validEmail, setValidEmail] = useState(true); 46 | const [validPassword, setValidPassword] = useState(true); 47 | const [validName, setValidName] = useState(true); 48 | const [validAddress, setValidAddress] = useState(true); 49 | 50 | const handleClick = async () => { 51 | const { email, name, password, ACN, address, phone_number } = otpState.formData; 52 | setValidEmail(validateEmail(email)); 53 | setValidPassword(password.trim() !== ""); 54 | setValidName(name.trim() !== "") 55 | setValidAddress(address.trim() !== "") 56 | if (!validateEmail(email)) return; 57 | if ([password, name, address, phone_number].some(item => item.trim() === "")) return; 58 | if (email.endsWith("@gmail.com")) { 59 | setMsg("Please use Google Sign above."); 60 | setOpen(true); 61 | return; 62 | } 63 | //! Validate 64 | dispatchOtpState({ type: "SET_WAITING", payload: { value: true } }) 65 | const { data: { data } } = await axios.get(`/api/users?email=${encodeURIComponent(email)}`); 66 | dispatchOtpState({ type: "SET_WAITING", payload: { value: false } }) 67 | if (data.length > 0) { 68 | setMsg("Already registered user") 69 | setOpen(true); 70 | } else { 71 | const code = genCode() 72 | dispatchOtpState({ type: "SET_WAITING", payload: { value: true } }) 73 | dispatchOtpState({ type: 'SET_OTPCODE', payload: { value: code } }) 74 | const { data: { message: _msg } }: { data: { message: string | object } } = await axios.get(`/api/sendmail?${queryBuilder({ email: email, code: code })}`) 75 | 76 | dispatchOtpState({ type: "SET_WAITING", payload: { value: false } }) 77 | if (typeof _msg === "string") {// && _msg.startsWith("250") 78 | dispatchOtpState({ type: "SET_WAITING", payload: { value: false } }) 79 | dispatchOtpState({ type: "SHOW_OTPCODE", payload: { value: true } }); 80 | } else { 81 | setMsg("Error occured while processing information") 82 | setOpen(true); 83 | } 84 | } 85 | } 86 | 87 | return ( 88 |
    89 |
    90 |
    91 | 92 | 93 |
    94 | {!validEmail &&

    *Invalid email type. Please fill in correct type.

    } 95 |
    96 |
    97 |
    98 | 99 | 100 |
    101 | {!validName &&

    *Your applicant information is not valid.

    } 102 |
    103 |
    104 |
    105 | 106 | 107 |
    108 | {!validPassword &&

    *Please enter your password correctly.

    } 109 |
    110 |
    111 |
    112 | 113 | 114 |
    115 | 116 |
    117 |
    118 |
    119 | 120 | 121 |
    122 | {!validAddress &&

    *Please enter your address correctly.

    } 123 |
    124 |
    125 | { 127 | if (value.length < 9) return 'Wrong number.' 128 | if (value.match(/12345/)) { 129 | const countryName = (country as { name: string }).name; 130 | return 'Invalid number in ' /* + value + ', '*/ + countryName; 131 | } else if (value.match(/1234/)) { 132 | return false; 133 | } else { 134 | return true; 135 | } 136 | }} 137 | placeholder='+61 (12) 345 6789' 138 | onChange={handlePhoneChage} 139 | // onChange={e => setCustomer(prev => ({ ...prev, Phone: e }))} 140 | // value={''} 141 | inputStyle={{ width: "100%", }} 142 | country={'au'} 143 | 144 | /> 145 |
    146 | 147 |
    148 | setChecked(e.target.checked)} size="small" /> 149 | I agree to Trade Mark Today's privacy notice and terms and conditions. 150 |
    151 | 152 | 153 | 154 |
    155 | ) 156 | } 157 | 158 | export default SignUp -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

    2 | Trade-Mark-Today - v1.2 3 |

    4 | Open Source? Yes! 5 | nodejs 6 | nodejs 7 | nodejs 8 | nodejs 9 | nodejs 10 | nodejs 11 | nodejs 12 | nodejs 13 | nodejs 14 | nodejs 15 |

    16 |

    17 | 18 |
    19 | 20 |
    21 | 22 |

    Steven Leal(imcrazysteven)

    23 |

    24 | Trademarktoday supports free initial trade mark check in minutes and registration of your trademark for Australia. Please kick off the process of protecting your brand and have some fun while doing it! 25 |
    26 | This project is maintained by @imcrazysteven 27 |
    28 | Don't forget to star ⭐ this repository. 29 |
    30 | Explore the docs » 31 |
    32 |
    33 | Visit Site 34 | · 35 | Report Bug 36 | · 37 | Request Feature 38 |

    39 |

    40 | nodejs 41 | nodejs 42 | nodejs 43 | nodejs 44 | nodejs 45 | nodejs 46 | nodejs 47 |

    48 |
    49 | 50 |
    51 | 52 | This is for trademarktoday.com.au 53 | 54 | 56 | ![Trademarktoday](https://github.com/imcrazysteven/trademarktoday-nextjs/blob/master/public/01.png?raw=true) 57 | ![Trademarktoday](https://github.com/imcrazysteven/trademarktoday-nextjs/blob/master/public/02.png?raw=true) 58 | 59 | ## Built With :package: 60 |

    61 | Node.js 62 | Next.js 63 | Next.js 64 | Next.js 65 | Next.js 66 | Next.js 67 | Github 68 |

    69 | 70 |

    71 | Open Source? Yes! 72 | Next.js 73 | Next.js 74 | Next.js 75 | Next.js 76 |

    77 | 78 | ## How to run locally? :dart: 79 | 80 | Make sure you have [Nodejs](https://nodejs.org/en/download) installed. 81 | 82 | ```bash 83 | node --version 84 | ``` 85 | 86 | - Clone the repository : 87 | - With HTTPS: 88 | ```bash 89 | git clone https://github.com/imcrazysteven/Trade-Mark-Today.git 90 | ``` 91 | - With SSH: 92 | ```bash 93 | git@github.com:imcrazysteven/Trade-Mark-Today.git 94 | ``` 95 | 96 | - Navigate to working Directory and **master** branch 97 | 98 | ```bash 99 | cd Trade-Mark-Today 100 | ``` 101 | 102 | - Install the dependencies: 103 | 104 | ```bash 105 | npm install 106 | ``` 107 | - Installs all the dependencies required by the project. 108 | 109 | - Run Server 110 | 111 | ```bash 112 | npm run serve 113 | ``` 114 | 115 | 116 | 117 | - To contribute, make pull request for your own branch: 118 | 119 | ```bash 120 | git add . 121 | git commit -m "" 122 | git push origin 123 | ``` 124 | 125 | 126 | ## 🤝 Contributing 127 | 128 | Contributions, Issues and Feature requests are Welcome! 129 | 130 | Feel free to check the [Issues page](https://github.com/imcrazysteven/Trade-Mark-Today/issues/). 131 | 132 | 133 | ## Contributors ✨ 134 | 135 | [![All Contributors](https://img.shields.io/badge/all_contributors-2-orange.svg?style=flat-square)](#contributors-) 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 |
    Steven Leal
    Steven Leal

    💻 🖋 📖 🔣 💡 🤔 📆 👀 🔧 📹
    marksantiago2909
    Epic Dev

    💻 🖋 📖 🔣 💡 🤔 📆 👀 🔧 📹
    149 | 150 | 151 | 152 | 153 | 154 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 155 | 156 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 157 | 158 | 159 | ## 📝 License 160 | 161 | This project is [MIT](https://opensource.org/licenses/MIT) licensed.
    162 | Copyright © 2023. All rights reserved. 163 | -------------------------------------------------------------------------------- /src/pages/summary.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode, useContext, useEffect, useState } from "react"; 2 | import WaitingLocker from "../components/WaitingLocker"; 3 | import { useRouter } from "next/router"; 4 | import ProgressIndicator from "../components/ProgressIndicator"; 5 | import Link from "next/link"; 6 | import Image from "next/image"; 7 | import PortalSummaryA from "../components/PortalSummaryA"; 8 | import PortalSummaryB from "../components/PortalSummaryB"; 9 | import { ConfirmStartAgainModal } from "../components/Modal"; 10 | import { Alert2, Alert4 } from "../components/AlertContainers"; 11 | import TMCheckLayout from "../layout/TMCheckLayout"; 12 | import { PiniaStore } from "@/store/store"; 13 | import Chat from "@/components/Chat"; 14 | import { verifyConsider } from "./select"; 15 | import { verifySelect } from "./classify"; 16 | import { PiniaType } from "@/types/interface"; 17 | 18 | const CardContainer = ({ children }: { children: ReactNode }) => { 19 | return ( 20 | 21 |
    22 | #1 23 |
    24 | Details 25 | 26 |
    27 |
    28 | {children} 29 |
    30 | ) 31 | } 32 | const CardWord = () => { 33 | return ( 34 | 35 |
    36 | Word MonkeyB 37 |
    38 |
    39 | ) 40 | } 41 | 42 | const CardLogo = () => { 43 | return ( 44 | 45 |
    46 | img 47 |
    48 |
    49 | ) 50 | } 51 | 52 | const CardARow = () => { 53 | return ( 54 |
    55 | 56 | 57 | 58 | 59 | 60 |
    61 | ) 62 | } 63 | 64 | export const verifyClassify = (pinia: PiniaType): boolean => { 65 | return !(pinia?.classes === undefined || 66 | (Object.keys(pinia?.classes).length === 0 && pinia?.classes.constructor === Object)); 67 | } 68 | 69 | const Summary = () => { 70 | const { pinia, setPinia } = useContext(PiniaStore); 71 | useEffect(() => { 72 | if (Object.keys(pinia).length === 0 && pinia.constructor === Object) { 73 | // router.push('/consider') 74 | return; 75 | } 76 | if (!verifyConsider(pinia)) { 77 | router.push('/consider') 78 | } else if (!verifySelect(pinia)) { 79 | router.push('/select') 80 | } else if (!verifyClassify(pinia)) { 81 | router.push('/classify') 82 | } 83 | }, [pinia]) 84 | const router = useRouter(); 85 | const [open, setOpen] = useState(false); 86 | const [waiting, setWaiting] = useState(false); 87 | const [portfolX, setPortfolX] = useState(0); 88 | 89 | return ( 90 | <> 91 |
    92 |
    93 | 94 |
    95 |

    Review results

    96 | 97 |
    98 | Please review 99 |

    Check for distinctiveness

    100 |
    101 | img e.currentTarget.src = "/no-avatar.png"} loading="lazy" width={200} height={200} /> 102 |
    103 |
    104 |
    105 |

    What to do

    106 | 109 |
    110 |

    Your trade mark may contain some of the following:

    111 |
    112 |
  • Descriptive words
  • 113 |
  • Geographic places
  • 114 |
  • Common surnames
  • 115 |
    116 |

    Make sure your trade mark contains something unique that other people in your industry would not need to use. You can still apply if you feel like your trade mark is distinctive enough. 117 | 118 | Read more about distinctiveness. 119 | 120 |

    121 |
    122 |
    123 |

    Help video

    124 | 128 |
    129 |
    130 |
    131 |
    132 | Please review 133 |

    Check for similarity

    134 |
    135 |
    136 | 137 | 138 | 139 | 140 |
    141 |
    142 |

    We found 20 matches that may be similar to yours.

    143 |
    144 | 145 |
    146 | 149 | 11-15 150 | 153 |
    154 |
    155 |
    156 |
    157 |
    158 |
    159 |

    What to do

    160 | 163 |
    164 |

    Check if these are similar in terms of:

    165 |
    166 |
  • The way they look
  • 167 |
  • Sound or pronunciation
  • 168 |
  • Goods or services
  • 169 |
    170 |

    You can still apply if you believe your trade mark and your goods and or services are distinguishable from those identified in the search result. 171 |

    172 | 173 | Read more about similarity. 174 | 175 |

    176 |
    177 |
    178 |

    Help video

    179 | 183 |
    184 |
    185 |
    186 |
    187 |

    Applying for this trade mark

    188 |
    189 | 191 |
  • These results are generated by our automated checking service to help inform your decision.
  • 192 |
  • If you decide to apply, the next step is a detailed human check, see fees and timeline below.
  • 193 |
    194 | } /> 195 | 196 | 197 | 198 | 199 | 200 |
    201 | 202 |
    203 |
    204 | 208 | 209 | 213 | 214 | 218 |
    219 |
    220 | 221 | ) 222 | } 223 | 224 | Summary.getLayout = TMCheckLayout; 225 | 226 | export default Summary; --------------------------------------------------------------------------------