Compare commits
10 Commits
c105fcddac
...
3f8135bdbe
Author | SHA1 | Date |
---|---|---|
mehedi-hasan | 3f8135bdbe | |
mehedi-hasan | cd68d6f64c | |
mehedi-hasan | 645f731a74 | |
mehedi-hasan | 64be0f87b1 | |
mehedi-hasan | 65ea9e5681 | |
mehedi-hasan | c4c8c34579 | |
mehedi-hasan | 40265d8c72 | |
mehedi-hasan | a7049fc9e2 | |
mehedi-hasan | 4e75d7eea5 | |
mehedi-hasan | 349381f7a2 |
|
@ -44,15 +44,18 @@
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
|
"cmdk": "^1.0.0",
|
||||||
"contentlayer": "^0.3.4",
|
"contentlayer": "^0.3.4",
|
||||||
"eslint": "8.48.0",
|
"eslint": "8.48.0",
|
||||||
"eslint-config-next": "^14.0.1",
|
"eslint-config-next": "^14.0.1",
|
||||||
|
"geonames.js": "^3.0.6",
|
||||||
"gray-matter": "^4.0.3",
|
"gray-matter": "^4.0.3",
|
||||||
"lucide-react": "^0.291.0",
|
"lucide-react": "^0.291.0",
|
||||||
"monaco-jsx-highlighter": "^2.77.77",
|
"monaco-jsx-highlighter": "^2.77.77",
|
||||||
"monaco-themes": "^0.4.4",
|
"monaco-themes": "^0.4.4",
|
||||||
"next": "^14.0.1",
|
"next": "^14.0.1",
|
||||||
"next-mdx-remote": "^4.4.1",
|
"next-mdx-remote": "^4.4.1",
|
||||||
|
"next-nprogress-bar": "^2.3.11",
|
||||||
"next-themes": "^0.2.1",
|
"next-themes": "^0.2.1",
|
||||||
"postcss": "8.4.28",
|
"postcss": "8.4.28",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
@ -61,6 +64,7 @@
|
||||||
"react-error-boundary": "^4.0.13",
|
"react-error-boundary": "^4.0.13",
|
||||||
"react-error-overlay": "^6.0.11",
|
"react-error-overlay": "^6.0.11",
|
||||||
"react-hook-form": "^7.47.0",
|
"react-hook-form": "^7.47.0",
|
||||||
|
"react-phone-number-input": "^3.4.0",
|
||||||
"react-resizable-panels": "^2.0.16",
|
"react-resizable-panels": "^2.0.16",
|
||||||
"rehype-pretty-code": "^0.13.1",
|
"rehype-pretty-code": "^0.13.1",
|
||||||
"sharp": "^0.32.5",
|
"sharp": "^0.32.5",
|
||||||
|
@ -4414,6 +4418,11 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/classnames": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
|
||||||
|
},
|
||||||
"node_modules/client-only": {
|
"node_modules/client-only": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
||||||
|
@ -4515,6 +4524,19 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cmdk": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-dialog": "1.0.5",
|
||||||
|
"@radix-ui/react-primitive": "1.0.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18.0.0",
|
||||||
|
"react-dom": "^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/color": {
|
"node_modules/color": {
|
||||||
"version": "4.2.3",
|
"version": "4.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
||||||
|
@ -4646,6 +4668,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/country-flag-icons": {
|
||||||
|
"version": "1.5.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/country-flag-icons/-/country-flag-icons-1.5.11.tgz",
|
||||||
|
"integrity": "sha512-B+mvFywunkRJs270k7kCBjhogvIA0uNn6GAXv6m2cPn3rrwqZzZVr2gBWcz+Cz7OGVWlcbERlYRIX0S6OGr8Bw=="
|
||||||
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
|
@ -6152,6 +6179,23 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/geonames.js": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/geonames.js/-/geonames.js-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-iDnDEzknKB7RXunjwYNgWg8ZbxjJhO9ChauXjo3njcsqhpHp3rpssqJLhATEp6T6NIybWlT/V3i6dxw+kFcICA==",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.21.0",
|
||||||
|
"qs": "^6.9.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/geonames.js/node_modules/axios": {
|
||||||
|
"version": "0.21.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||||
|
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/get-caller-file": {
|
"node_modules/get-caller-file": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
|
@ -6947,6 +6991,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz",
|
||||||
"integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q=="
|
"integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q=="
|
||||||
},
|
},
|
||||||
|
"node_modules/input-format": {
|
||||||
|
"version": "0.3.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/input-format/-/input-format-0.3.10.tgz",
|
||||||
|
"integrity": "sha512-5cFv/kOZD7Ch0viprVkuYPDkAU7HBZYBx8QrIpQ6yXUWbAQ0+RQ8IIojDJOf/RO6FDJLL099HDSK2KoVZ2zevg==",
|
||||||
|
"dependencies": {
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/internal-slot": {
|
"node_modules/internal-slot": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
|
||||||
|
@ -7572,6 +7624,11 @@
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/libphonenumber-js": {
|
||||||
|
"version": "1.10.61",
|
||||||
|
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.61.tgz",
|
||||||
|
"integrity": "sha512-TsQsyzDttDvvzWNkbp/i0fVbzTGJIG0mUu/uNalIaRQEYeJxVQ/FPg+EJgSqfSXezREjM0V3RZ8cLVsKYhhw0Q=="
|
||||||
|
},
|
||||||
"node_modules/lilconfig": {
|
"node_modules/lilconfig": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
||||||
|
@ -12745,6 +12802,14 @@
|
||||||
"react-dom": ">=16.x <=18.x"
|
"react-dom": ">=16.x <=18.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/next-nprogress-bar": {
|
||||||
|
"version": "2.3.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/next-nprogress-bar/-/next-nprogress-bar-2.3.11.tgz",
|
||||||
|
"integrity": "sha512-OjSvsQwgSWa2qBMYO478QreGG9Jt82tr4wTQptmiyzNqqjzHCyKZNkhANnzPrjuFAoelIvmruJuakODofSnvTQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"nprogress": "^0.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/next-themes": {
|
"node_modules/next-themes": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz",
|
||||||
|
@ -12863,6 +12928,11 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/nprogress": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA=="
|
||||||
|
},
|
||||||
"node_modules/object-assign": {
|
"node_modules/object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
|
@ -13483,6 +13553,20 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/qs": {
|
||||||
|
"version": "6.12.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz",
|
||||||
|
"integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"side-channel": "^1.0.6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/queue-microtask": {
|
"node_modules/queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
|
@ -13610,6 +13694,22 @@
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/react-phone-number-input": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-phone-number-input/-/react-phone-number-input-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-anL8OAqlSnOXd6O+lidkprOO5+OpgW+ODrbfyLc6u8lOX8ghT0nO6ZOPrGjotpZND4cr0xxH+vu3dgbdUB2lBA==",
|
||||||
|
"dependencies": {
|
||||||
|
"classnames": "^2.5.1",
|
||||||
|
"country-flag-icons": "^1.5.11",
|
||||||
|
"input-format": "^0.3.10",
|
||||||
|
"libphonenumber-js": "^1.10.61",
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8",
|
||||||
|
"react-dom": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-remove-scroll": {
|
"node_modules/react-remove-scroll": {
|
||||||
"version": "2.5.5",
|
"version": "2.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz",
|
||||||
|
|
|
@ -46,15 +46,18 @@
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
|
"cmdk": "^1.0.0",
|
||||||
"contentlayer": "^0.3.4",
|
"contentlayer": "^0.3.4",
|
||||||
"eslint": "8.48.0",
|
"eslint": "8.48.0",
|
||||||
"eslint-config-next": "^14.0.1",
|
"eslint-config-next": "^14.0.1",
|
||||||
|
"geonames.js": "^3.0.6",
|
||||||
"gray-matter": "^4.0.3",
|
"gray-matter": "^4.0.3",
|
||||||
"lucide-react": "^0.291.0",
|
"lucide-react": "^0.291.0",
|
||||||
"monaco-jsx-highlighter": "^2.77.77",
|
"monaco-jsx-highlighter": "^2.77.77",
|
||||||
"monaco-themes": "^0.4.4",
|
"monaco-themes": "^0.4.4",
|
||||||
"next": "^14.0.1",
|
"next": "^14.0.1",
|
||||||
"next-mdx-remote": "^4.4.1",
|
"next-mdx-remote": "^4.4.1",
|
||||||
|
"next-nprogress-bar": "^2.3.11",
|
||||||
"next-themes": "^0.2.1",
|
"next-themes": "^0.2.1",
|
||||||
"postcss": "8.4.28",
|
"postcss": "8.4.28",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
@ -63,6 +66,7 @@
|
||||||
"react-error-boundary": "^4.0.13",
|
"react-error-boundary": "^4.0.13",
|
||||||
"react-error-overlay": "^6.0.11",
|
"react-error-overlay": "^6.0.11",
|
||||||
"react-hook-form": "^7.47.0",
|
"react-hook-form": "^7.47.0",
|
||||||
|
"react-phone-number-input": "^3.4.0",
|
||||||
"react-resizable-panels": "^2.0.16",
|
"react-resizable-panels": "^2.0.16",
|
||||||
"rehype-pretty-code": "^0.13.1",
|
"rehype-pretty-code": "^0.13.1",
|
||||||
"sharp": "^0.32.5",
|
"sharp": "^0.32.5",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Header from "@/components/layout/header";
|
import Header from "@/components/layout/header";
|
||||||
import Sidebar from "@/components/layout/sidebar";
|
import Sidebar from "@/components/layout/sidebar";
|
||||||
import StoreProvider from "@/lib/store-provider";
|
// import StoreProvider from "@/lib/store-provider";
|
||||||
import { createClient } from "@/utils/supabase/server";
|
import { createClient } from "@/utils/supabase/server";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
|
@ -29,14 +29,14 @@ export default async function DashboardLayout({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StoreProvider lastUpdate={new Date().getTime()}>
|
{/* <StoreProvider lastUpdate={new Date().getTime()}> */}
|
||||||
<Header />
|
<Header />
|
||||||
|
|
||||||
<div className="flex h-screen overflow-hidden">
|
<div className="flex h-screen overflow-hidden">
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<main className="w-full pt-16">{children}</main>
|
<main className="w-full pt-16">{children}</main>
|
||||||
</div>
|
</div>
|
||||||
</StoreProvider>
|
{/* </StoreProvider> */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,5 @@
|
||||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
||||||
import {
|
|
||||||
ResizableHandle,
|
|
||||||
ResizablePanel,
|
|
||||||
ResizablePanelGroup,
|
|
||||||
} from "@/components/ui/resizable";
|
|
||||||
import markdownStyles from "@/styles/markdown-styles.module.css";
|
|
||||||
import { tutorialData } from "@/constants/tutorial-data";
|
import { tutorialData } from "@/constants/tutorial-data";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { Button, buttonVariants } from "@/components/ui/button";
|
|
||||||
import Link from "next/link";
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import EditorWindow from "@/components/task/editor-window";
|
|
||||||
import { LANGUAGE_VERSIONS } from "@/constants/language-options";
|
import { LANGUAGE_VERSIONS } from "@/constants/language-options";
|
||||||
import { markdownToHtml } from "@/lib/markdown-to-html";
|
import { markdownToHtml } from "@/lib/markdown-to-html";
|
||||||
import TaskPage from "@/components/task-page";
|
import TaskPage from "@/components/task-page";
|
||||||
|
@ -18,10 +7,6 @@ import TaskPage from "@/components/task-page";
|
||||||
const languages = Object.keys(LANGUAGE_VERSIONS);
|
const languages = Object.keys(LANGUAGE_VERSIONS);
|
||||||
|
|
||||||
const Page = async ({ params }: { params: { taskId: string[] } }) => {
|
const Page = async ({ params }: { params: { taskId: string[] } }) => {
|
||||||
// const [activeMobileView, setActiveMobileView] = useState<
|
|
||||||
// "tutorial" | "code" | "output"
|
|
||||||
// >("tutorial");
|
|
||||||
|
|
||||||
if (!params.taskId[0] || !languages.includes(params.taskId[0])) {
|
if (!params.taskId[0] || !languages.includes(params.taskId[0])) {
|
||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
@ -44,15 +29,13 @@ const Page = async ({ params }: { params: { taskId: string[] } }) => {
|
||||||
|
|
||||||
const content = await markdownToHtml(tutorial?.content || "");
|
const content = await markdownToHtml(tutorial?.content || "");
|
||||||
return (
|
return (
|
||||||
<>
|
<TaskPage
|
||||||
<TaskPage
|
params={params}
|
||||||
params={params}
|
langTutorial={langTutorial}
|
||||||
langTutorial={langTutorial}
|
tutorial={tutorial}
|
||||||
tutorial={tutorial}
|
tutorialIndex={tutorialIndex}
|
||||||
tutorialIndex={tutorialIndex}
|
content={content}
|
||||||
content={content}
|
/>
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import "@uploadthing/react/styles.css";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { Inter } from "next/font/google";
|
import { Inter } from "next/font/google";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
import StoreProvider from "@/lib/store-provider";
|
||||||
|
|
||||||
const inter = Inter({ subsets: ["latin"] });
|
const inter = Inter({ subsets: ["latin"] });
|
||||||
|
|
||||||
|
@ -21,10 +22,13 @@ export default async function RootLayout({
|
||||||
return (
|
return (
|
||||||
<html lang="en" suppressHydrationWarning>
|
<html lang="en" suppressHydrationWarning>
|
||||||
<body className={`${inter.className} overflow-x-hidden`}>
|
<body className={`${inter.className} overflow-x-hidden`}>
|
||||||
<Providers>
|
<StoreProvider lastUpdate={new Date().getTime()}>
|
||||||
<Toaster />
|
<Providers>
|
||||||
{children}
|
<Toaster />
|
||||||
</Providers>
|
|
||||||
|
{children}
|
||||||
|
</Providers>
|
||||||
|
</StoreProvider>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
import Geolocation from "@/components/geolocation";
|
||||||
|
import { PhoneInput } from "@/components/phone-input";
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionContent,
|
AccordionContent,
|
||||||
|
@ -29,7 +31,7 @@ import { cn } from "@/lib/utils";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { AlertTriangleIcon, Trash, Trash2Icon } from "lucide-react";
|
import { AlertTriangleIcon, Trash, Trash2Icon } from "lucide-react";
|
||||||
import { useParams, useRouter } from "next/navigation";
|
import { useParams, useRouter } from "next/navigation";
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { SubmitHandler, useFieldArray, useForm } from "react-hook-form";
|
import { SubmitHandler, useFieldArray, useForm } from "react-hook-form";
|
||||||
|
|
||||||
interface ProfileFormType {
|
interface ProfileFormType {
|
||||||
|
@ -56,8 +58,13 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
const [currentStep, setCurrentStep] = useState(0);
|
const [currentStep, setCurrentStep] = useState(0);
|
||||||
const [data, setData] = useState({});
|
const [data, setData] = useState({});
|
||||||
const delta = currentStep - previousStep;
|
const delta = currentStep - previousStep;
|
||||||
|
const [countryGeoId, setCountryGeoId] = useState<null | number>(null);
|
||||||
|
const [stateGeoId, setStateGeoId] = useState<null | number>(null);
|
||||||
|
const [countryGeoId2, setCountryGeoId2] = useState<null | number>(null);
|
||||||
|
const [stateGeoId2, setStateGeoId2] = useState<null | number>(null);
|
||||||
|
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
|
// state: "",
|
||||||
jobs: [
|
jobs: [
|
||||||
{
|
{
|
||||||
jobtitle: "",
|
jobtitle: "",
|
||||||
|
@ -65,6 +72,7 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
startdate: "",
|
startdate: "",
|
||||||
enddate: "",
|
enddate: "",
|
||||||
jobcountry: "",
|
jobcountry: "",
|
||||||
|
jobstate: "",
|
||||||
jobcity: "",
|
jobcity: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -96,7 +104,7 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
// console.log("product", res);
|
// console.log("product", res);
|
||||||
}
|
}
|
||||||
router.refresh();
|
router.refresh();
|
||||||
router.push(`/dashboard/products`);
|
router.push(`/dashboard`);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
@ -135,12 +143,13 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
"email",
|
"email",
|
||||||
"contactno",
|
"contactno",
|
||||||
"country",
|
"country",
|
||||||
|
"state",
|
||||||
"city",
|
"city",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "Step 2",
|
id: "Step 2",
|
||||||
name: "Professional Informations",
|
name: "Professional Information",
|
||||||
// fields are mapping and flattening for the error to be trigger for the dynamic fields
|
// fields are mapping and flattening for the error to be trigger for the dynamic fields
|
||||||
fields: fields
|
fields: fields
|
||||||
?.map((_, index) => [
|
?.map((_, index) => [
|
||||||
|
@ -149,6 +158,7 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
`jobs.${index}.startdate`,
|
`jobs.${index}.startdate`,
|
||||||
`jobs.${index}.enddate`,
|
`jobs.${index}.enddate`,
|
||||||
`jobs.${index}.jobcountry`,
|
`jobs.${index}.jobcountry`,
|
||||||
|
`jobs.${index}.jobstate`,
|
||||||
`jobs.${index}.jobcity`,
|
`jobs.${index}.jobcity`,
|
||||||
// Add other field names as needed
|
// Add other field names as needed
|
||||||
])
|
])
|
||||||
|
@ -182,8 +192,8 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const countries = [{ id: "wow", name: "india" }];
|
const countries = [{ id: "1", name: "india" }];
|
||||||
const cities = [{ id: "2", name: "kerala" }];
|
const cities = [{ id: "1", name: "kerala" }];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -206,18 +216,18 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
{steps.map((step, index) => (
|
{steps.map((step, index) => (
|
||||||
<li key={step.name} className="md:flex-1">
|
<li key={step.name} className="md:flex-1">
|
||||||
{currentStep > index ? (
|
{currentStep > index ? (
|
||||||
<div className="group flex w-full flex-col border-l-4 border-sky-600 py-2 pl-4 transition-colors md:border-l-0 md:border-t-4 md:pb-0 md:pl-0 md:pt-4">
|
<div className="group flex w-full flex-col border-l-4 border-primary py-2 pl-4 transition-colors md:border-l-0 md:border-t-4 md:pb-0 md:pl-0 md:pt-4">
|
||||||
<span className="text-sm font-medium text-sky-600 transition-colors ">
|
<span className="text-sm font-medium text-primary transition-colors ">
|
||||||
{step.id}
|
{step.id}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-sm font-medium">{step.name}</span>
|
<span className="text-sm font-medium">{step.name}</span>
|
||||||
</div>
|
</div>
|
||||||
) : currentStep === index ? (
|
) : currentStep === index ? (
|
||||||
<div
|
<div
|
||||||
className="flex w-full flex-col border-l-4 border-sky-600 py-2 pl-4 md:border-l-0 md:border-t-4 md:pb-0 md:pl-0 md:pt-4"
|
className="flex w-full flex-col border-l-4 border-primary py-2 pl-4 md:border-l-0 md:border-t-4 md:pb-0 md:pl-0 md:pt-4"
|
||||||
aria-current="step"
|
aria-current="step"
|
||||||
>
|
>
|
||||||
<span className="text-sm font-medium text-sky-600">
|
<span className="text-sm font-medium text-primary">
|
||||||
{step.id}
|
{step.id}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-sm font-medium">{step.name}</span>
|
<span className="text-sm font-medium">{step.name}</span>
|
||||||
|
@ -307,11 +317,20 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Contact Number</FormLabel>
|
<FormLabel>Contact Number</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
{/* <Input
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="Enter you contact number"
|
placeholder="Enter your contact number"
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
{...field}
|
{...field}
|
||||||
|
/> */}
|
||||||
|
<PhoneInput
|
||||||
|
id="phone"
|
||||||
|
// onChange={(v) => setPhone(v)}
|
||||||
|
// value={phone}
|
||||||
|
placeholder="Enter a phone number..."
|
||||||
|
defaultCountry="IN"
|
||||||
|
international
|
||||||
|
{...field}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
|
@ -323,63 +342,68 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
name="country"
|
name="country"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Country</FormLabel>
|
<FormLabel
|
||||||
<Select
|
// className="block mb-[6px] mt-[2px]"
|
||||||
disabled={loading}
|
|
||||||
onValueChange={field.onChange}
|
|
||||||
value={field.value}
|
|
||||||
defaultValue={field.value}
|
|
||||||
>
|
>
|
||||||
<FormControl>
|
Country
|
||||||
<SelectTrigger>
|
</FormLabel>
|
||||||
<SelectValue
|
<Geolocation
|
||||||
defaultValue={field.value}
|
geoId={null}
|
||||||
placeholder="Select a country"
|
onChange={(country, geoId) => {
|
||||||
/>
|
setCountryGeoId(geoId);
|
||||||
</SelectTrigger>
|
field.onChange(country);
|
||||||
</FormControl>
|
}}
|
||||||
<SelectContent>
|
isCountry
|
||||||
{/* @ts-ignore */}
|
placeholderText="Select a country"
|
||||||
{countries.map((country) => (
|
searchPlaceholder="Search country..."
|
||||||
<SelectItem key={country.id} value={country.id}>
|
emptyPlaceholder="No country found"
|
||||||
{country.name}
|
isDisabled={false}
|
||||||
</SelectItem>
|
/>
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="state"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>State</FormLabel>
|
||||||
|
<Geolocation
|
||||||
|
geoId={countryGeoId}
|
||||||
|
onChange={(state, geoId) => {
|
||||||
|
setStateGeoId(geoId);
|
||||||
|
field.onChange(state);
|
||||||
|
}}
|
||||||
|
isCountry={false}
|
||||||
|
placeholderText="Select a state"
|
||||||
|
searchPlaceholder="Search state..."
|
||||||
|
emptyPlaceholder="No state found"
|
||||||
|
isDisabled={!countryGeoId}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="city"
|
name="city"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>City</FormLabel>
|
<FormLabel>City</FormLabel>
|
||||||
<Select
|
<Geolocation
|
||||||
disabled={loading}
|
geoId={stateGeoId}
|
||||||
onValueChange={field.onChange}
|
onChange={(v) => field.onChange(v)}
|
||||||
value={field.value}
|
isCountry={false}
|
||||||
defaultValue={field.value}
|
placeholderText="Select a city"
|
||||||
>
|
searchPlaceholder="Search city..."
|
||||||
<FormControl>
|
emptyPlaceholder="No city found"
|
||||||
<SelectTrigger>
|
isDisabled={!stateGeoId}
|
||||||
<SelectValue
|
/>
|
||||||
defaultValue={field.value}
|
|
||||||
placeholder="Select a city"
|
|
||||||
/>
|
|
||||||
</SelectTrigger>
|
|
||||||
</FormControl>
|
|
||||||
<SelectContent>
|
|
||||||
{/* @ts-ignore */}
|
|
||||||
{cities.map((city) => (
|
|
||||||
<SelectItem key={city.id} value={city.id}>
|
|
||||||
{city.name}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
|
@ -498,31 +522,42 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Job country</FormLabel>
|
<FormLabel>Job country</FormLabel>
|
||||||
<Select
|
<Geolocation
|
||||||
disabled={loading}
|
geoId={null}
|
||||||
onValueChange={field.onChange}
|
onChange={(country, geoId) => {
|
||||||
value={field.value}
|
setCountryGeoId2(geoId);
|
||||||
defaultValue={field.value}
|
field.onChange(country);
|
||||||
>
|
}}
|
||||||
<FormControl>
|
isCountry
|
||||||
<SelectTrigger>
|
placeholderText="Select job country"
|
||||||
<SelectValue
|
searchPlaceholder="Search country..."
|
||||||
defaultValue={field.value}
|
emptyPlaceholder="No country found"
|
||||||
placeholder="Select your job country"
|
isDisabled={false}
|
||||||
/>
|
/>
|
||||||
</SelectTrigger>
|
|
||||||
</FormControl>
|
<FormMessage />
|
||||||
<SelectContent>
|
</FormItem>
|
||||||
{countries.map((country) => (
|
)}
|
||||||
<SelectItem
|
/>
|
||||||
key={country.id}
|
<FormField
|
||||||
value={country.id}
|
control={form.control}
|
||||||
>
|
name={`jobs.${index}.jobstate`}
|
||||||
{country.name}
|
render={({ field }) => (
|
||||||
</SelectItem>
|
<FormItem>
|
||||||
))}
|
<FormLabel>Job State</FormLabel>
|
||||||
</SelectContent>
|
<Geolocation
|
||||||
</Select>
|
geoId={countryGeoId2}
|
||||||
|
onChange={(state, geoId) => {
|
||||||
|
setStateGeoId2(geoId);
|
||||||
|
field.onChange(state);
|
||||||
|
}}
|
||||||
|
isCountry={false}
|
||||||
|
placeholderText="Select job state"
|
||||||
|
searchPlaceholder="Search state..."
|
||||||
|
emptyPlaceholder="No state found"
|
||||||
|
isDisabled={!countryGeoId2}
|
||||||
|
/>
|
||||||
|
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
|
@ -533,28 +568,16 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Job city</FormLabel>
|
<FormLabel>Job city</FormLabel>
|
||||||
<Select
|
<Geolocation
|
||||||
disabled={loading}
|
geoId={stateGeoId2}
|
||||||
onValueChange={field.onChange}
|
onChange={(v) => field.onChange(v)}
|
||||||
value={field.value}
|
isCountry={false}
|
||||||
defaultValue={field.value}
|
placeholderText="Select job city"
|
||||||
>
|
searchPlaceholder="Search city..."
|
||||||
<FormControl>
|
emptyPlaceholder="No city found"
|
||||||
<SelectTrigger>
|
isDisabled={!stateGeoId2}
|
||||||
<SelectValue
|
/>
|
||||||
defaultValue={field.value}
|
|
||||||
placeholder="Select your job city"
|
|
||||||
/>
|
|
||||||
</SelectTrigger>
|
|
||||||
</FormControl>
|
|
||||||
<SelectContent>
|
|
||||||
{cities.map((city) => (
|
|
||||||
<SelectItem key={city.id} value={city.id}>
|
|
||||||
{city.name}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
|
@ -577,6 +600,7 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
startdate: "",
|
startdate: "",
|
||||||
enddate: "",
|
enddate: "",
|
||||||
jobcountry: "",
|
jobcountry: "",
|
||||||
|
jobstate: "",
|
||||||
jobcity: "",
|
jobcity: "",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -590,7 +614,7 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
<div>
|
<div>
|
||||||
<h1>Completed</h1>
|
<h1>Completed</h1>
|
||||||
<pre className="whitespace-pre-wrap">
|
<pre className="whitespace-pre-wrap">
|
||||||
{JSON.stringify(data)}
|
{JSON.stringify(data, null, 2)}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -604,11 +628,12 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
{/* Navigation */}
|
{/* Navigation */}
|
||||||
<div className="mt-8 pt-5">
|
<div className="mt-8 pt-5">
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={prev}
|
onClick={prev}
|
||||||
disabled={currentStep === 0}
|
disabled={currentStep === 0}
|
||||||
className="rounded bg-white px-2 py-1 text-sm font-semibold text-sky-900 shadow-sm ring-1 ring-inset ring-sky-300 hover:bg-sky-50 disabled:cursor-not-allowed disabled:opacity-50"
|
size="icon"
|
||||||
|
// className="rounded bg-white px-2 py-1 text-sm font-semibold text-sky-900 shadow-sm ring-1 ring-inset ring-sky-300 hover:bg-sky-50 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
@ -624,12 +649,13 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
d="M15.75 19.5L8.25 12l7.5-7.5"
|
d="M15.75 19.5L8.25 12l7.5-7.5"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</Button>
|
||||||
<button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={next}
|
onClick={next}
|
||||||
disabled={currentStep === steps.length - 1}
|
disabled={currentStep === steps.length - 1}
|
||||||
className="rounded bg-white px-2 py-1 text-sm font-semibold text-sky-900 shadow-sm ring-1 ring-inset ring-sky-300 hover:bg-sky-50 disabled:cursor-not-allowed disabled:opacity-50"
|
size="icon"
|
||||||
|
// className="rounded bg-white px-2 py-1 text-sm font-semibold text-sky-900 shadow-sm ring-1 ring-inset ring-sky-300 hover:bg-sky-50 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
@ -645,7 +671,7 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
d="M8.25 4.5l7.5 7.5-7.5 7.5"
|
d="M8.25 4.5l7.5 7.5-7.5 7.5"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { CaretSortIcon, CheckIcon } from "@radix-ui/react-icons";
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Command,
|
||||||
|
CommandEmpty,
|
||||||
|
CommandGroup,
|
||||||
|
CommandInput,
|
||||||
|
CommandItem,
|
||||||
|
CommandList,
|
||||||
|
} from "@/components/ui/command";
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from "@/components/ui/popover";
|
||||||
|
import { FC, useEffect, useState } from "react";
|
||||||
|
import Geonames from "geonames.js";
|
||||||
|
import { FormControl } from "./ui/form";
|
||||||
|
|
||||||
|
const frameworks = [
|
||||||
|
{
|
||||||
|
value: "next.js",
|
||||||
|
label: "Next.js",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "sveltekit",
|
||||||
|
label: "SvelteKit",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "nuxt.js",
|
||||||
|
label: "Nuxt.js",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "remix",
|
||||||
|
label: "Remix",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "astro",
|
||||||
|
label: "Astro",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const geonames = new Geonames({
|
||||||
|
username: "thalesandrade",
|
||||||
|
lan: "en",
|
||||||
|
encoding: "JSON",
|
||||||
|
});
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
geoId: number | null;
|
||||||
|
onChange: (country: string, geoId: number) => void;
|
||||||
|
isCountry: boolean;
|
||||||
|
placeholderText: string;
|
||||||
|
searchPlaceholder: string;
|
||||||
|
emptyPlaceholder: string;
|
||||||
|
isDisabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Geolocation: FC<Props> = ({
|
||||||
|
geoId,
|
||||||
|
onChange,
|
||||||
|
isCountry,
|
||||||
|
placeholderText,
|
||||||
|
searchPlaceholder,
|
||||||
|
emptyPlaceholder,
|
||||||
|
isDisabled,
|
||||||
|
}) => {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [currentValue, setCurrentValue] = useState<null | number>(null);
|
||||||
|
const [options, setOptions] = useState<
|
||||||
|
{ countryName: string; geonameId: number; name: string }[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
try {
|
||||||
|
const data = () => {
|
||||||
|
isCountry
|
||||||
|
? geonames.countryInfo({}).then((res: any) => {
|
||||||
|
// console.log(res);
|
||||||
|
setOptions(res.geonames);
|
||||||
|
})
|
||||||
|
: geonames.children({ geonameId: geoId }).then((res: any) => {
|
||||||
|
if (res.totalResultsCount) setOptions(res.geonames);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
data();
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}, [geoId, isCountry]);
|
||||||
|
|
||||||
|
const currentPlaceholderText =
|
||||||
|
currentValue && isCountry
|
||||||
|
? options.find((option: any) => option.geonameId === currentValue)
|
||||||
|
?.countryName
|
||||||
|
: currentValue
|
||||||
|
? options.find((option: any) => option.geonameId === currentValue)?.name
|
||||||
|
: placeholderText;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover open={open} onOpenChange={setOpen}>
|
||||||
|
<PopoverTrigger asChild disabled={isDisabled}>
|
||||||
|
<FormControl>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
role="combobox"
|
||||||
|
aria-expanded={open}
|
||||||
|
className="w-full justify-between"
|
||||||
|
>
|
||||||
|
{currentPlaceholderText}
|
||||||
|
<CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||||
|
</Button>
|
||||||
|
</FormControl>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-[200px] md:w-[400px] p-0">
|
||||||
|
<Command>
|
||||||
|
<CommandList>
|
||||||
|
<CommandInput placeholder={searchPlaceholder} className="h-9" />
|
||||||
|
<CommandEmpty>{emptyPlaceholder}</CommandEmpty>
|
||||||
|
<CommandGroup>
|
||||||
|
{options.map((v: any, index) => (
|
||||||
|
<CommandItem
|
||||||
|
key={index}
|
||||||
|
value={v.geonameId}
|
||||||
|
onSelect={() => {
|
||||||
|
setCurrentValue(
|
||||||
|
v.geonameId === currentValue ? null : v.geonameId,
|
||||||
|
);
|
||||||
|
const name = isCountry ? v.countryName : v.name;
|
||||||
|
onChange(
|
||||||
|
v.geonameId === currentValue ? "" : name,
|
||||||
|
v.geonameId === currentValue ? null : v.geonameId,
|
||||||
|
);
|
||||||
|
setOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isCountry ? v.countryName : v.name}
|
||||||
|
<CheckIcon
|
||||||
|
className={cn(
|
||||||
|
"ml-auto h-4 w-4",
|
||||||
|
currentValue === v.geonameId
|
||||||
|
? "opacity-100"
|
||||||
|
: "opacity-0",
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</CommandItem>
|
||||||
|
))}
|
||||||
|
</CommandGroup>
|
||||||
|
</CommandList>
|
||||||
|
</Command>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Geolocation;
|
|
@ -1,11 +1,19 @@
|
||||||
"use client";
|
"use client";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ThemeProvider from "./ThemeToggle/theme-provider";
|
import ThemeProvider from "./ThemeToggle/theme-provider";
|
||||||
|
import { AppProgressBar as ProgressBar } from "next-nprogress-bar";
|
||||||
|
|
||||||
export default function Providers({ children }: { children: React.ReactNode }) {
|
export default function Providers({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem>
|
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem>
|
||||||
{children}
|
{children}
|
||||||
|
<ProgressBar
|
||||||
|
height="4px"
|
||||||
|
color="hsl(217.2 91.2% 59.8%)"
|
||||||
|
options={{ showSpinner: false }}
|
||||||
|
shallowRouting
|
||||||
|
/>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
import { CheckIcon, ChevronsUpDown } from "lucide-react";
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import * as RPNInput from "react-phone-number-input";
|
||||||
|
|
||||||
|
import flags from "react-phone-number-input/flags";
|
||||||
|
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Command,
|
||||||
|
CommandEmpty,
|
||||||
|
CommandGroup,
|
||||||
|
CommandInput,
|
||||||
|
CommandItem,
|
||||||
|
CommandList,
|
||||||
|
} from "@/components/ui/command";
|
||||||
|
import { Input, InputProps } from "@/components/ui/input";
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from "@/components/ui/popover";
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { ScrollArea } from "./ui/scroll-area";
|
||||||
|
|
||||||
|
type PhoneInputProps = Omit<
|
||||||
|
React.InputHTMLAttributes<HTMLInputElement>,
|
||||||
|
"onChange" | "value"
|
||||||
|
> &
|
||||||
|
Omit<RPNInput.Props<typeof RPNInput.default>, "onChange"> & {
|
||||||
|
onChange?: (value: RPNInput.Value) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const PhoneInput: React.ForwardRefExoticComponent<PhoneInputProps> =
|
||||||
|
React.forwardRef<React.ElementRef<typeof RPNInput.default>, PhoneInputProps>(
|
||||||
|
({ className, onChange, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<RPNInput.default
|
||||||
|
ref={ref}
|
||||||
|
className={cn("flex", className)}
|
||||||
|
flagComponent={FlagComponent}
|
||||||
|
countrySelectComponent={CountrySelect}
|
||||||
|
inputComponent={InputComponent}
|
||||||
|
/**
|
||||||
|
* Handles the onChange event.
|
||||||
|
*
|
||||||
|
* react-phone-number-input might trigger the onChange event as undefined
|
||||||
|
* when a valid phone number is not entered. To prevent this,
|
||||||
|
* the value is coerced to an empty string.
|
||||||
|
*
|
||||||
|
* @param {E164Number | undefined} value - The entered value
|
||||||
|
*/
|
||||||
|
onChange={(value) => onChange?.(value || "")}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
PhoneInput.displayName = "PhoneInput";
|
||||||
|
|
||||||
|
const InputComponent = React.forwardRef<HTMLInputElement, InputProps>(
|
||||||
|
({ className, ...props }, ref) => (
|
||||||
|
<Input
|
||||||
|
className={cn("rounded-e-lg rounded-s-none", className)}
|
||||||
|
{...props}
|
||||||
|
ref={ref}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
);
|
||||||
|
InputComponent.displayName = "InputComponent";
|
||||||
|
|
||||||
|
type CountrySelectOption = { label: string; value: RPNInput.Country };
|
||||||
|
|
||||||
|
type CountrySelectProps = {
|
||||||
|
disabled?: boolean;
|
||||||
|
value: RPNInput.Country;
|
||||||
|
onChange: (value: RPNInput.Country) => void;
|
||||||
|
options: CountrySelectOption[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const CountrySelect = ({
|
||||||
|
disabled,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
options,
|
||||||
|
}: CountrySelectProps) => {
|
||||||
|
const handleSelect = React.useCallback(
|
||||||
|
(country: RPNInput.Country) => {
|
||||||
|
onChange(country);
|
||||||
|
},
|
||||||
|
[onChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant={"outline"}
|
||||||
|
className={cn("flex gap-1 rounded-e-none rounded-s-lg px-3")}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
<FlagComponent country={value} countryName={value} />
|
||||||
|
<ChevronsUpDown
|
||||||
|
className={cn(
|
||||||
|
"-mr-2 h-4 w-4 opacity-50",
|
||||||
|
disabled ? "hidden" : "opacity-100",
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-[300px] p-0">
|
||||||
|
<Command>
|
||||||
|
<CommandList>
|
||||||
|
<ScrollArea className="h-72">
|
||||||
|
<CommandInput placeholder="Search country..." />
|
||||||
|
<CommandEmpty>No country found.</CommandEmpty>
|
||||||
|
<CommandGroup>
|
||||||
|
{options
|
||||||
|
.filter((x) => x.value)
|
||||||
|
.map((option) => (
|
||||||
|
<CommandItem
|
||||||
|
className="gap-2"
|
||||||
|
key={option.value}
|
||||||
|
onSelect={() => handleSelect(option.value)}
|
||||||
|
>
|
||||||
|
<FlagComponent
|
||||||
|
country={option.value}
|
||||||
|
countryName={option.label}
|
||||||
|
/>
|
||||||
|
<span className="flex-1 text-sm">{option.label}</span>
|
||||||
|
{option.value && (
|
||||||
|
<span className="text-foreground/50 text-sm">
|
||||||
|
{`+${RPNInput.getCountryCallingCode(option.value)}`}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<CheckIcon
|
||||||
|
className={cn(
|
||||||
|
"ml-auto h-4 w-4",
|
||||||
|
option.value === value ? "opacity-100" : "opacity-0",
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</CommandItem>
|
||||||
|
))}
|
||||||
|
</CommandGroup>
|
||||||
|
</ScrollArea>
|
||||||
|
</CommandList>
|
||||||
|
</Command>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const FlagComponent = ({ country, countryName }: RPNInput.FlagProps) => {
|
||||||
|
const Flag = flags[country];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className="bg-foreground/20 flex h-4 w-6 overflow-hidden rounded-sm">
|
||||||
|
{Flag && <Flag title={countryName} />}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
FlagComponent.displayName = "FlagComponent";
|
||||||
|
|
||||||
|
export { PhoneInput };
|
|
@ -25,6 +25,7 @@ export const FinishedScreen = () => {
|
||||||
totalCorrectAns,
|
totalCorrectAns,
|
||||||
questionsArray,
|
questionsArray,
|
||||||
reset,
|
reset,
|
||||||
|
correctAns
|
||||||
} = useQuizStore(
|
} = useQuizStore(
|
||||||
useShallow((store) => ({
|
useShallow((store) => ({
|
||||||
points: store.points,
|
points: store.points,
|
||||||
|
@ -33,6 +34,7 @@ export const FinishedScreen = () => {
|
||||||
totalCorrectAns: store.totalCorrectAns,
|
totalCorrectAns: store.totalCorrectAns,
|
||||||
questionsArray: store.questionsArray,
|
questionsArray: store.questionsArray,
|
||||||
reset: store.reset,
|
reset: store.reset,
|
||||||
|
correctAns: store.correctAns
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
// const {points, highscore} = useSelector(store => store.questions)
|
// const {points, highscore} = useSelector(store => store.questions)
|
||||||
|
@ -58,10 +60,14 @@ export const FinishedScreen = () => {
|
||||||
<CardTitle>Quiz Results</CardTitle>
|
<CardTitle>Quiz Results</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<p className="text-green-500">Correct: {totalCorrectAns}</p>
|
<p className="text-green-500">Correct: {correctAns.length}</p>
|
||||||
|
<p className="text-rose-500">
|
||||||
|
Incorrect: {questionsArray.length - correctAns.length}
|
||||||
|
</p>
|
||||||
|
{/* <p className="text-green-500">Correct: {totalCorrectAns}</p>
|
||||||
<p className="text-rose-500">
|
<p className="text-rose-500">
|
||||||
Incorrect: {questionsArray.length - totalCorrectAns}
|
Incorrect: {questionsArray.length - totalCorrectAns}
|
||||||
</p>
|
</p> */}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
<CardFooter>
|
<CardFooter>
|
||||||
<Button
|
<Button
|
||||||
|
|
|
@ -7,17 +7,19 @@ import { Button } from "../ui/button";
|
||||||
// import { useDispatch, useSelector } from 'react-redux'
|
// import { useDispatch, useSelector } from 'react-redux'
|
||||||
// import { gameEnded, nextQuestion } from '../features/questions/questionsSlice'
|
// import { gameEnded, nextQuestion } from '../features/questions/questionsSlice'
|
||||||
|
|
||||||
export const Next = () => {
|
export const Next = ({ currentCorrectAns }: { currentCorrectAns: string }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { index, gameEnded, nextQuestion, questionsArray } = useQuizStore(
|
const { index, gameEnded, nextQuestion, questionsArray, newAnswer } =
|
||||||
useShallow((store) => ({
|
useQuizStore(
|
||||||
index: store.index,
|
useShallow((store) => ({
|
||||||
gameEnded: store.gameEnded,
|
index: store.index,
|
||||||
nextQuestion: store.nextQuestion,
|
gameEnded: store.gameEnded,
|
||||||
questionsArray: store.questionsArray,
|
nextQuestion: store.nextQuestion,
|
||||||
})),
|
questionsArray: store.questionsArray,
|
||||||
);
|
newAnswer: store.newAnswer,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
// const {index} = useSelector(store => store.questions)
|
// const {index} = useSelector(store => store.questions)
|
||||||
|
|
||||||
|
@ -31,7 +33,13 @@ export const Next = () => {
|
||||||
|
|
||||||
if (index < questionsArray.length - 1)
|
if (index < questionsArray.length - 1)
|
||||||
return (
|
return (
|
||||||
<Button className="" onClick={nextQuestion}>
|
<Button
|
||||||
|
className=""
|
||||||
|
onClick={() => {
|
||||||
|
newAnswer(currentCorrectAns);
|
||||||
|
nextQuestion();
|
||||||
|
}}
|
||||||
|
>
|
||||||
Next
|
Next
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|
|
@ -18,6 +18,7 @@ export const Question = ({ difficulty }: { difficulty: string }) => {
|
||||||
// const { status, index, currentQuestion, answer } = useSelector(
|
// const { status, index, currentQuestion, answer } = useSelector(
|
||||||
// (store) => store.questions,
|
// (store) => store.questions,
|
||||||
// );
|
// );
|
||||||
|
const [currentCorrectAns, setCurrentCorrectAns] = useState("");
|
||||||
|
|
||||||
const [isStart, setIsStart] = useState(false);
|
const [isStart, setIsStart] = useState(false);
|
||||||
|
|
||||||
|
@ -75,7 +76,10 @@ export const Question = ({ difficulty }: { difficulty: string }) => {
|
||||||
{options?.map((option: any, index: number) => {
|
{options?.map((option: any, index: number) => {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
variant={`${answer === option ? "default" : "secondary"}`}
|
// variant={`${answer === option ? "default" : "secondary"}`}
|
||||||
|
variant={`${
|
||||||
|
currentCorrectAns === option ? "default" : "secondary"
|
||||||
|
}`}
|
||||||
key={index}
|
key={index}
|
||||||
className={cn(
|
className={cn(
|
||||||
"justify-start text-lg py-6 disabled:pointer-events-auto disabled:cursor-not-allowed",
|
"justify-start text-lg py-6 disabled:pointer-events-auto disabled:cursor-not-allowed",
|
||||||
|
@ -90,8 +94,9 @@ export const Question = ({ difficulty }: { difficulty: string }) => {
|
||||||
// : ""
|
// : ""
|
||||||
// }
|
// }
|
||||||
// `}
|
// `}
|
||||||
disabled={ !isStart}
|
disabled={!isStart}
|
||||||
onClick={() => newAnswer(option)}
|
onClick={() => setCurrentCorrectAns(option)}
|
||||||
|
// onClick={() => newAnswer(option)}
|
||||||
>
|
>
|
||||||
{option}
|
{option}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -100,9 +105,18 @@ export const Question = ({ difficulty }: { difficulty: string }) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between mt-6 items-center">
|
<div className="flex justify-between mt-6 items-center">
|
||||||
<div>{answer && <Next />}</div>
|
<div>
|
||||||
|
{/* {answer && <Next currentCorrectAns={currentCorrectAns} />} */}
|
||||||
|
{currentCorrectAns !== "" && (
|
||||||
|
<Next currentCorrectAns={currentCorrectAns} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{isStart ? <Timer /> : <Button onClick={() => setIsStart(true)}>Start</Button>}
|
{isStart ? (
|
||||||
|
<Timer />
|
||||||
|
) : (
|
||||||
|
<Button onClick={() => setIsStart(true)}>Start</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||||
import {
|
import {
|
||||||
ResizableHandle,
|
ResizableHandle,
|
||||||
|
@ -8,19 +8,14 @@ import {
|
||||||
ResizablePanelGroup,
|
ResizablePanelGroup,
|
||||||
} from "@/components/ui/resizable";
|
} from "@/components/ui/resizable";
|
||||||
import markdownStyles from "@/styles/markdown-styles.module.css";
|
import markdownStyles from "@/styles/markdown-styles.module.css";
|
||||||
import { tutorialData } from "@/constants/tutorial-data";
|
|
||||||
import { notFound } from "next/navigation";
|
|
||||||
import { Button, buttonVariants } from "@/components/ui/button";
|
import { Button, buttonVariants } from "@/components/ui/button";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import EditorWindow from "@/components/task/editor-window";
|
import EditorWindow from "@/components/task/editor-window";
|
||||||
import { LANGUAGE_VERSIONS } from "@/constants/language-options";
|
|
||||||
import { markdownToHtml } from "@/lib/markdown-to-html";
|
|
||||||
import Header from "./task/header";
|
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import ThemeToggle from "./layout/ThemeToggle/theme-toggle";
|
import ThemeToggle from "./layout/ThemeToggle/theme-toggle";
|
||||||
|
import { useQuizStore } from "@/lib/quiz-store";
|
||||||
const languages = Object.keys(LANGUAGE_VERSIONS);
|
import { useShallow } from "zustand/react/shallow";
|
||||||
|
|
||||||
interface LangTutorial {
|
interface LangTutorial {
|
||||||
id: number;
|
id: number;
|
||||||
|
@ -55,55 +50,50 @@ const TaskPage = ({
|
||||||
"tutorial" | "code" | "output"
|
"tutorial" | "code" | "output"
|
||||||
>("tutorial");
|
>("tutorial");
|
||||||
|
|
||||||
// if (!params.taskId[0] || !languages.includes(params.taskId[0])) {
|
const { isTaskPageLoading, updateTaskPageLoading } = useQuizStore(
|
||||||
// notFound();
|
useShallow((store) => ({
|
||||||
// }
|
isTaskPageLoading: store.isTaskPageLoading,
|
||||||
|
updateTaskPageLoading: store.updateTaskPageLoading,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
// const langTutorial = tutorialData.find(
|
useEffect(() => {
|
||||||
// (t) => t.language === params.taskId[0],
|
if (typeof window !== "undefined") {
|
||||||
// )!;
|
// console.log(isTaskPageLoading);
|
||||||
|
updateTaskPageLoading(false);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
// const tutorial = langTutorial.tutorial.find(
|
|
||||||
// (t) => t.id === (Number(params.taskId[1]) || 1),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const tutorialIndex = langTutorial.tutorial.findIndex(
|
|
||||||
// (t) => t.id === (Number(params.taskId[1]) || 1),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// if (!tutorial || tutorialIndex === -1) {
|
|
||||||
// notFound();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const content = await markdownToHtml(tutorial?.content || "");
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex md:hidden items-center justify-center gap-4 fixed md:static w-screen bottom-0 left-0 z-50 px-4 py-3 bg-background border-t">
|
<div className="md:hidden">
|
||||||
<Button
|
<div
|
||||||
variant={activeMobileView === "tutorial" ? "default" : "outline"}
|
className={cn(
|
||||||
onClick={() => setActiveMobileView("tutorial")}
|
"flex items-center justify-center gap-4 fixed w-screen bottom-0 left-0 z-50 px-4 py-3 bg-background border-t transition-transform",
|
||||||
|
isTaskPageLoading ? "translate-y-full" : "translate-y-0",
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
Tutorial
|
<Button
|
||||||
</Button>
|
variant={activeMobileView === "tutorial" ? "default" : "outline"}
|
||||||
<Button
|
onClick={() => setActiveMobileView("tutorial")}
|
||||||
variant={activeMobileView === "code" ? "default" : "outline"}
|
>
|
||||||
onClick={() => setActiveMobileView("code")}
|
Tutorial
|
||||||
>
|
</Button>
|
||||||
Code
|
<Button
|
||||||
</Button>
|
variant={activeMobileView === "code" ? "default" : "outline"}
|
||||||
<Button
|
onClick={() => setActiveMobileView("code")}
|
||||||
variant={activeMobileView === "output" ? "default" : "outline"}
|
>
|
||||||
onClick={() => setActiveMobileView("output")}
|
Code
|
||||||
>
|
</Button>
|
||||||
Output
|
<Button
|
||||||
</Button>
|
variant={activeMobileView === "output" ? "default" : "outline"}
|
||||||
|
onClick={() => setActiveMobileView("output")}
|
||||||
|
>
|
||||||
|
Output
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="md:hidden w-full h-full">
|
<div className="md:hidden w-full h-full">
|
||||||
{/* <ResizablePanelGroup
|
|
||||||
direction="vertical"
|
|
||||||
className="max-w-[1440px] mx-auto h-full"
|
|
||||||
> */}
|
|
||||||
{/* <ResizablePanel defaultSize={50}> */}
|
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed left-0 top-0 h-[calc(100vh-59px)] w-screen transition-transform translate-x-0",
|
"fixed left-0 top-0 h-[calc(100vh-59px)] w-screen transition-transform translate-x-0",
|
||||||
|
@ -136,16 +126,14 @@ const TaskPage = ({
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<div className="flex items-center gap-8">
|
<div className="flex items-center gap-8">
|
||||||
{/* <Link href="/">Home</Link> */}
|
|
||||||
<Link href="/dashboard">Dashboard</Link>
|
<Link href="/dashboard">Dashboard</Link>
|
||||||
{/* <Link href="/login">Login</Link> */}
|
|
||||||
<ThemeToggle />
|
<ThemeToggle />
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ScrollArea className="h-[calc(100vh-calc(53px+59px))]">
|
<ScrollArea className="h-[calc(100vh-calc(53px+59px))]">
|
||||||
<div className="p-4 flex flex-col gap-4 h-full mb-14">
|
<div className="p-4 flex flex-col gap-4 h-full mb-16">
|
||||||
<div
|
<div
|
||||||
className={cn("grow", markdownStyles["markdown"])}
|
className={cn("grow", markdownStyles["markdown"])}
|
||||||
dangerouslySetInnerHTML={{ __html: content }}
|
dangerouslySetInnerHTML={{ __html: content }}
|
||||||
|
@ -154,6 +142,7 @@ const TaskPage = ({
|
||||||
<div>
|
<div>
|
||||||
{langTutorial?.tutorial[tutorialIndex - 1] && (
|
{langTutorial?.tutorial[tutorialIndex - 1] && (
|
||||||
<Link
|
<Link
|
||||||
|
onClick={() => updateTaskPageLoading(true)}
|
||||||
href={`/dashboard/task/${params.taskId[0]}/${
|
href={`/dashboard/task/${params.taskId[0]}/${
|
||||||
Number(params.taskId[1]) - 1
|
Number(params.taskId[1]) - 1
|
||||||
}`}
|
}`}
|
||||||
|
@ -169,6 +158,7 @@ const TaskPage = ({
|
||||||
<div>
|
<div>
|
||||||
{langTutorial?.tutorial[tutorialIndex + 1] && (
|
{langTutorial?.tutorial[tutorialIndex + 1] && (
|
||||||
<Link
|
<Link
|
||||||
|
onClick={() => updateTaskPageLoading(true)}
|
||||||
href={`/dashboard/task/${params.taskId[0]}/${
|
href={`/dashboard/task/${params.taskId[0]}/${
|
||||||
Number(params.taskId[1]) + 1
|
Number(params.taskId[1]) + 1
|
||||||
}`}
|
}`}
|
||||||
|
@ -184,70 +174,14 @@ const TaskPage = ({
|
||||||
</div>
|
</div>
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
</div>
|
</div>
|
||||||
{/* </ResizablePanel> */}
|
|
||||||
{/* <ResizableHandle withHandle /> */}
|
|
||||||
{/* <ResizablePanel defaultSize={50}> */}
|
|
||||||
<EditorWindow
|
<EditorWindow
|
||||||
activeMobileView={activeMobileView}
|
activeMobileView={activeMobileView}
|
||||||
language={params.taskId[0]}
|
language={params.taskId[0]}
|
||||||
step={Number(params.taskId[1]) || 1}
|
step={Number(params.taskId[1]) || 1}
|
||||||
/>
|
/>
|
||||||
{/* </ResizablePanel> */}
|
|
||||||
{/* </ResizablePanelGroup> */}
|
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="md:hidden w-full h-full">
|
|
||||||
<ResizablePanelGroup
|
|
||||||
direction="vertical"
|
|
||||||
className="max-w-[1440px] mx-auto h-full"
|
|
||||||
>
|
|
||||||
<ResizablePanel defaultSize={50}>
|
|
||||||
<ScrollArea className="h-[calc(100vh-55px)]">
|
|
||||||
<div className="px-4 py-6 flex flex-col gap-4 h-full mb-[60vh]">
|
|
||||||
<div
|
|
||||||
className={cn("grow", markdownStyles["markdown"])}
|
|
||||||
dangerouslySetInnerHTML={{ __html: content }}
|
|
||||||
></div>
|
|
||||||
<div className="flex justify-between">
|
|
||||||
<div className="mb-6">
|
|
||||||
{langTutorial?.tutorial[tutorialIndex - 1] && (
|
|
||||||
<Link
|
|
||||||
href={`/dashboard/task/${params.taskId[0]}/${
|
|
||||||
Number(params.taskId[1]) - 1
|
|
||||||
}`}
|
|
||||||
className={buttonVariants({
|
|
||||||
variant: "outline",
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
Prev
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mb-6">
|
|
||||||
{langTutorial?.tutorial[tutorialIndex + 1] && (
|
|
||||||
<Link
|
|
||||||
href={`/dashboard/task/${params.taskId[0]}/${
|
|
||||||
Number(params.taskId[1]) + 1
|
|
||||||
}`}
|
|
||||||
className={buttonVariants({ variant: "outline" })}
|
|
||||||
>
|
|
||||||
Next
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ScrollArea>
|
|
||||||
</ResizablePanel>
|
|
||||||
<ResizableHandle withHandle />
|
|
||||||
<ResizablePanel defaultSize={50}>
|
|
||||||
<EditorWindow
|
|
||||||
language={params.taskId[0]}
|
|
||||||
step={Number(params.taskId[1]) || 1}
|
|
||||||
/>
|
|
||||||
</ResizablePanel>
|
|
||||||
</ResizablePanelGroup>
|
|
||||||
</div> */}
|
|
||||||
<div className="hidden md:block w-full h-full">
|
<div className="hidden md:block w-full h-full">
|
||||||
<ResizablePanelGroup
|
<ResizablePanelGroup
|
||||||
direction="horizontal"
|
direction="horizontal"
|
||||||
|
@ -255,14 +189,14 @@ const TaskPage = ({
|
||||||
>
|
>
|
||||||
<ResizablePanel defaultSize={50}>
|
<ResizablePanel defaultSize={50}>
|
||||||
<ScrollArea className="h-[calc(100vh-55px)]">
|
<ScrollArea className="h-[calc(100vh-55px)]">
|
||||||
<div className="px-4 py-6 flex flex-col gap-4 h-full">
|
<div className="px-4 py-6 flex flex-col gap-4 h-full mb-6">
|
||||||
<div
|
<div
|
||||||
className={cn("grow", markdownStyles["markdown"])}
|
className={cn("grow", markdownStyles["markdown"])}
|
||||||
dangerouslySetInnerHTML={{ __html: content }}
|
dangerouslySetInnerHTML={{ __html: content }}
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<div className="mb-6">
|
<div>
|
||||||
{langTutorial?.tutorial[tutorialIndex - 1] && (
|
{langTutorial?.tutorial[tutorialIndex - 1] && (
|
||||||
<Link
|
<Link
|
||||||
href={`/dashboard/task/${params.taskId[0]}/${
|
href={`/dashboard/task/${params.taskId[0]}/${
|
||||||
|
@ -277,7 +211,7 @@ const TaskPage = ({
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-6">
|
<div>
|
||||||
{langTutorial?.tutorial[tutorialIndex + 1] && (
|
{langTutorial?.tutorial[tutorialIndex + 1] && (
|
||||||
<Link
|
<Link
|
||||||
href={`/dashboard/task/${params.taskId[0]}/${
|
href={`/dashboard/task/${params.taskId[0]}/${
|
||||||
|
|
|
@ -12,7 +12,6 @@ import {
|
||||||
ResizablePanelGroup,
|
ResizablePanelGroup,
|
||||||
} from "@/components/ui/resizable";
|
} from "@/components/ui/resizable";
|
||||||
import { ThemeDropdown } from "./theme-dropdown";
|
import { ThemeDropdown } from "./theme-dropdown";
|
||||||
import LanguagesDropdown from "./languages-dropdown";
|
|
||||||
import Output from "./output";
|
import Output from "./output";
|
||||||
import { tutorialData } from "@/constants/tutorial-data";
|
import { tutorialData } from "@/constants/tutorial-data";
|
||||||
import { notFound, useRouter } from "next/navigation";
|
import { notFound, useRouter } from "next/navigation";
|
||||||
|
@ -93,13 +92,10 @@ export default function EditorWindow({
|
||||||
if (!tutorial) {
|
if (!tutorial) {
|
||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
// console.log(tutorial);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="md:hidden">
|
<div className="md:hidden">
|
||||||
{/* <ResizablePanelGroup direction="vertical" className="border-r">
|
|
||||||
<ResizablePanel defaultSize={50}> */}
|
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed left-0 top-0 h-[calc(100vh-59px)] w-screen translate-x-full transition-transform ",
|
"fixed left-0 top-0 h-[calc(100vh-59px)] w-screen translate-x-full transition-transform ",
|
||||||
|
@ -117,10 +113,6 @@ export default function EditorWindow({
|
||||||
handleThemeChange={handleThemeChange}
|
handleThemeChange={handleThemeChange}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
{/* <LanguagesDropdown
|
|
||||||
handleLanguageChange={handleLanguageChange}
|
|
||||||
language={lang}
|
|
||||||
/> */}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="h-[calc(100vh-calc(55px+53px))]">
|
<div className="h-[calc(100vh-calc(55px+53px))]">
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
|
@ -135,9 +127,7 @@ export default function EditorWindow({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* </ResizablePanel> */}
|
|
||||||
{/* <ResizableHandle withHandle /> */}
|
|
||||||
{/* <ResizablePanel defaultSize={50}> */}
|
|
||||||
<ErrorBoundary FallbackComponent={PreviewErrorFallback}>
|
<ErrorBoundary FallbackComponent={PreviewErrorFallback}>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
|
@ -167,8 +157,6 @@ export default function EditorWindow({
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
{/* </ResizablePanel> */}
|
|
||||||
{/* </ResizablePanelGroup> */}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="hidden md:block h-[calc(100vh-55px)]">
|
<div className="hidden md:block h-[calc(100vh-55px)]">
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import { type DialogProps } from "@radix-ui/react-dialog"
|
||||||
|
import { MagnifyingGlassIcon } from "@radix-ui/react-icons"
|
||||||
|
import { Command as CommandPrimitive } from "cmdk"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
import { Dialog, DialogContent } from "@/components/ui/dialog"
|
||||||
|
|
||||||
|
const Command = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CommandPrimitive
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
Command.displayName = CommandPrimitive.displayName
|
||||||
|
|
||||||
|
interface CommandDialogProps extends DialogProps {}
|
||||||
|
|
||||||
|
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
|
||||||
|
return (
|
||||||
|
<Dialog {...props}>
|
||||||
|
<DialogContent className="overflow-hidden p-0">
|
||||||
|
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
||||||
|
{children}
|
||||||
|
</Command>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const CommandInput = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
|
||||||
|
<MagnifyingGlassIcon className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||||
|
<CommandPrimitive.Input
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
|
||||||
|
CommandInput.displayName = CommandPrimitive.Input.displayName
|
||||||
|
|
||||||
|
const CommandList = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.List>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CommandPrimitive.List
|
||||||
|
ref={ref}
|
||||||
|
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
|
||||||
|
CommandList.displayName = CommandPrimitive.List.displayName
|
||||||
|
|
||||||
|
const CommandEmpty = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.Empty>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
|
||||||
|
>((props, ref) => (
|
||||||
|
<CommandPrimitive.Empty
|
||||||
|
ref={ref}
|
||||||
|
className="py-6 text-center text-sm"
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
|
||||||
|
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
|
||||||
|
|
||||||
|
const CommandGroup = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.Group>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CommandPrimitive.Group
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
|
||||||
|
CommandGroup.displayName = CommandPrimitive.Group.displayName
|
||||||
|
|
||||||
|
const CommandSeparator = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.Separator>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CommandPrimitive.Separator
|
||||||
|
ref={ref}
|
||||||
|
className={cn("-mx-1 h-px bg-border", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
|
||||||
|
|
||||||
|
const CommandItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.Item>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CommandPrimitive.Item
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled='true']:pointer-events-none data-[disabled='true']:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
|
||||||
|
CommandItem.displayName = CommandPrimitive.Item.displayName
|
||||||
|
|
||||||
|
const CommandShortcut = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className={cn(
|
||||||
|
"ml-auto text-xs tracking-widest text-muted-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
CommandShortcut.displayName = "CommandShortcut"
|
||||||
|
|
||||||
|
export {
|
||||||
|
Command,
|
||||||
|
CommandDialog,
|
||||||
|
CommandInput,
|
||||||
|
CommandList,
|
||||||
|
CommandEmpty,
|
||||||
|
CommandGroup,
|
||||||
|
CommandItem,
|
||||||
|
CommandShortcut,
|
||||||
|
CommandSeparator,
|
||||||
|
}
|
|
@ -1,29 +1,49 @@
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { isValidPhoneNumber } from "react-phone-number-input";
|
||||||
|
|
||||||
export const profileSchema = z.object({
|
export const profileSchema = z.object({
|
||||||
firstname: z
|
firstname: z
|
||||||
.string()
|
.string({ required_error: "Please enter your first name" })
|
||||||
.min(3, { message: "Product Name must be at least 3 characters" }),
|
.trim()
|
||||||
|
.min(1, { message: "Please enter your first name" }),
|
||||||
lastname: z
|
lastname: z
|
||||||
.string()
|
.string({ required_error: "Please enter your last name" })
|
||||||
.min(3, { message: "Product Name must be at least 3 characters" }),
|
.trim()
|
||||||
|
.min(1, { message: "Please enter your last name" }),
|
||||||
email: z
|
email: z
|
||||||
.string()
|
.string({ required_error: "Please enter your email" })
|
||||||
.email({ message: "Product Name must be at least 3 characters" }),
|
.email({ message: "Please enter a valid email" }),
|
||||||
contactno: z.coerce.number(),
|
contactno: z
|
||||||
country: z.string().min(1, { message: "Please select a category" }),
|
.string({ required_error: "Please enter your phone number" })
|
||||||
city: z.string().min(1, { message: "Please select a category" }),
|
.refine((value) => isValidPhoneNumber(value), {
|
||||||
|
message: "Please enter a valid phone number",
|
||||||
|
}),
|
||||||
|
country: z
|
||||||
|
.string({ required_error: "Please select your country" })
|
||||||
|
.trim()
|
||||||
|
.min(1, { message: "Please select your country" }),
|
||||||
|
state: z
|
||||||
|
.string({ required_error: "Please select your state" })
|
||||||
|
.trim()
|
||||||
|
.min(1, { message: "Please select your state" }),
|
||||||
|
city: z
|
||||||
|
.string({ required_error: "Please select your city" })
|
||||||
|
.trim()
|
||||||
|
.min(1, { message: "Please select your city" }),
|
||||||
// jobs array is for the dynamic fields
|
// jobs array is for the dynamic fields
|
||||||
jobs: z.array(
|
jobs: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
jobcountry: z.string().min(1, { message: "Please select a category" }),
|
jobcountry: z.string().min(1, { message: "Please select a country" }),
|
||||||
jobcity: z.string().min(1, { message: "Please select a category" }),
|
jobstate: z.string().min(1, { message: "Please select a job state" }),
|
||||||
|
jobcity: z.string().min(1, { message: "Please select a city" }),
|
||||||
jobtitle: z
|
jobtitle: z
|
||||||
.string()
|
.string()
|
||||||
.min(3, { message: "Product Name must be at least 3 characters" }),
|
.trim()
|
||||||
|
.min(1, { message: "Please enter your job title" }),
|
||||||
employer: z
|
employer: z
|
||||||
.string()
|
.string()
|
||||||
.min(3, { message: "Product Name must be at least 3 characters" }),
|
.trim()
|
||||||
|
.min(1, { message: "Please enter your employer name" }),
|
||||||
startdate: z
|
startdate: z
|
||||||
.string()
|
.string()
|
||||||
.refine((value) => /^\d{4}-\d{2}-\d{2}$/.test(value), {
|
.refine((value) => /^\d{4}-\d{2}-\d{2}$/.test(value), {
|
||||||
|
|
|
@ -39,6 +39,10 @@ export interface StoreInterface {
|
||||||
// increment: () => void;
|
// increment: () => void;
|
||||||
// decrement: () => void;
|
// decrement: () => void;
|
||||||
reset: () => void;
|
reset: () => void;
|
||||||
|
correctAns: string[];
|
||||||
|
|
||||||
|
isTaskPageLoading: boolean;
|
||||||
|
updateTaskPageLoading: (value: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDefaultInitialState() {
|
function getDefaultInitialState() {
|
||||||
|
@ -65,6 +69,8 @@ function getDefaultInitialState() {
|
||||||
highscore: 0,
|
highscore: 0,
|
||||||
secondsRemaining: 210,
|
secondsRemaining: 210,
|
||||||
totalCorrectAns: 0,
|
totalCorrectAns: 0,
|
||||||
|
correctAns: [],
|
||||||
|
isTaskPageLoading: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,10 +100,15 @@ export function initializeStore(preloadedState: PreloadedStoreInterface) {
|
||||||
// console.log(get().totalCorrectAns);
|
// console.log(get().totalCorrectAns);
|
||||||
set({
|
set({
|
||||||
answer,
|
answer,
|
||||||
points:
|
// points:
|
||||||
answer === get().currentQuestion.correctAnswer
|
// answer === get().currentQuestion.correctAnswer
|
||||||
? get().points + 20
|
// ? get().points + 20
|
||||||
: get().points,
|
// : get().points,
|
||||||
|
correctAns:
|
||||||
|
answer === get().currentQuestion.correctAnswer &&
|
||||||
|
!get().correctAns.includes(answer)
|
||||||
|
? [...get().correctAns, answer]
|
||||||
|
: get().correctAns,
|
||||||
totalCorrectAns:
|
totalCorrectAns:
|
||||||
answer === get().currentQuestion.correctAnswer
|
answer === get().currentQuestion.correctAnswer
|
||||||
? get().totalCorrectAns + 1
|
? get().totalCorrectAns + 1
|
||||||
|
@ -167,5 +178,11 @@ export function initializeStore(preloadedState: PreloadedStoreInterface) {
|
||||||
// set({
|
// set({
|
||||||
// count: getDefaultInitialState().count,
|
// count: getDefaultInitialState().count,
|
||||||
// }),
|
// }),
|
||||||
|
|
||||||
|
updateTaskPageLoading: (value) => {
|
||||||
|
console.log(value)
|
||||||
|
set({
|
||||||
|
isTaskPageLoading: value,
|
||||||
|
})},
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue