diff --git a/web/app/(pages)/tasks/page.tsx b/web/app/(pages)/tasks/page.tsx index 31c7823c..cabad9b4 100644 --- a/web/app/(pages)/tasks/page.tsx +++ b/web/app/(pages)/tasks/page.tsx @@ -1,5 +1,15 @@ import { TaskRoute } from "@/components/routes/task/TaskRoute" +import { currentUser } from "@clerk/nextjs/server" +import { notFound } from "next/navigation" +import { get } from "ronin" + +export default async function TaskPage() { + const user = await currentUser() + const flag = await get.featureFlag.with.name("TASK") + + if (!user?.emailAddresses.some(email => flag?.emails.includes(email.emailAddress))) { + notFound() + } -export default function TaskPage() { return } diff --git a/web/app/actions.ts b/web/app/actions.ts index 14795825..42f598f6 100644 --- a/web/app/actions.ts +++ b/web/app/actions.ts @@ -10,6 +10,19 @@ import { ZSAError } from "zsa" const MAX_FILE_SIZE = 1 * 1024 * 1024 const ALLOWED_FILE_TYPES = ["image/jpeg", "image/png", "image/gif", "image/webp"] +export const getFeatureFlag = authedProcedure + .input( + z.object({ + name: z.string() + }) + ) + .handler(async ({ input }) => { + const { name } = input + const flag = await get.featureFlag.with.name(name) + + return { flag } + }) + export const sendFeedback = authedProcedure .input( z.object({ diff --git a/web/components/custom/sidebar/partial/task-section.tsx b/web/components/custom/sidebar/partial/task-section.tsx index 5f725eab..203100f7 100644 --- a/web/components/custom/sidebar/partial/task-section.tsx +++ b/web/components/custom/sidebar/partial/task-section.tsx @@ -1,9 +1,11 @@ import Link from "next/link" import { usePathname } from "next/navigation" -import { useAccount } from "@/lib/providers/jazz-provider" import { cn } from "@/lib/utils" import { ListOfTasks } from "@/lib/schema/tasks" import { LaIcon } from "../../la-icon" +import { useEffect, useState } from "react" +import { useAuth, useUser } from "@clerk/nextjs" +import { getFeatureFlag } from "@/app/actions" export const TaskSection: React.FC<{ pathname: string }> = ({ pathname }) => { const me = { root: { tasks: [{ id: "1", title: "Test Task" }] } } @@ -11,12 +13,52 @@ export const TaskSection: React.FC<{ pathname: string }> = ({ pathname }) => { const taskCount = me?.root.tasks?.length || 0 const isActive = pathname === "/tasks" + const [isFetching, setIsFetching] = useState(false) + const [isFeatureActive, setIsFeatureActive] = useState(false) + const { isLoaded, isSignedIn } = useAuth() + const { user } = useUser() + + useEffect(() => { + async function checkFeatureFlag() { + setIsFetching(true) + + if (isLoaded && isSignedIn) { + const [data, err] = await getFeatureFlag({ name: "TASK" }) + + if (err) { + console.error(err) + setIsFetching(false) + return + } + + if (user?.emailAddresses.some(email => data.flag?.emails.includes(email.emailAddress))) { + setIsFeatureActive(true) + } + setIsFetching(false) + } + } + + checkFeatureFlag() + }, [isLoaded, isSignedIn, user]) + + if (!isLoaded || !isSignedIn) { + return
Loading...
+ } + if (!me) return null + if (!isFeatureActive) { + return null + } + return (
- + {isFetching ? ( +
Fetching tasks...
+ ) : ( + + )}
) } diff --git a/web/components/custom/sidebar/sidebar.tsx b/web/components/custom/sidebar/sidebar.tsx index 591bad35..b1f70df1 100644 --- a/web/components/custom/sidebar/sidebar.tsx +++ b/web/components/custom/sidebar/sidebar.tsx @@ -115,23 +115,20 @@ const SidebarContent: React.FC = React.memo(() => { const pathname = usePathname() return ( - <> - ) }) diff --git a/web/package.json b/web/package.json index 0135be5a..ae4a70da 100644 --- a/web/package.json +++ b/web/package.json @@ -1,128 +1,128 @@ { - "name": "web", - "version": "0.1.0", - "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start", - "lint": "next lint", - "test": "jest" - }, - "dependencies": { - "@clerk/nextjs": "^5.6.0", - "@dnd-kit/core": "^6.1.0", - "@dnd-kit/modifiers": "^7.0.0", - "@dnd-kit/sortable": "^8.0.0", - "@hookform/resolvers": "^3.9.0", - "@nothing-but/force-graph": "^0.9.5", - "@nothing-but/utils": "^0.16.0", - "@omit/react-confirm-dialog": "^1.1.5", - "@omit/react-fancy-switch": "^0.1.3", - "@radix-ui/react-alert-dialog": "^1.1.1", - "@radix-ui/react-avatar": "^1.1.0", - "@radix-ui/react-checkbox": "^1.1.1", - "@radix-ui/react-context-menu": "^2.2.1", - "@radix-ui/react-dialog": "^1.1.1", - "@radix-ui/react-dismissable-layer": "^1.1.0", - "@radix-ui/react-dropdown-menu": "^2.1.1", - "@radix-ui/react-focus-scope": "^1.1.0", - "@radix-ui/react-icons": "^1.3.0", - "@radix-ui/react-label": "^2.1.0", - "@radix-ui/react-popover": "^1.1.1", - "@radix-ui/react-scroll-area": "^1.1.0", - "@radix-ui/react-select": "^2.1.1", - "@radix-ui/react-separator": "^1.1.0", - "@radix-ui/react-slot": "^1.1.0", - "@radix-ui/react-switch": "^1.1.0", - "@radix-ui/react-toggle": "^1.1.0", - "@radix-ui/react-toggle-group": "^1.1.0", - "@radix-ui/react-tooltip": "^1.1.2", - "@sentry/nextjs": "^8.30.0", - "@tanstack/react-virtual": "^3.10.8", - "@tiptap/core": "^2.7.2", - "@tiptap/extension-blockquote": "^2.7.2", - "@tiptap/extension-bold": "^2.7.2", - "@tiptap/extension-bullet-list": "^2.7.2", - "@tiptap/extension-code": "^2.7.2", - "@tiptap/extension-code-block-lowlight": "^2.7.2", - "@tiptap/extension-color": "^2.7.2", - "@tiptap/extension-document": "^2.7.2", - "@tiptap/extension-dropcursor": "^2.7.2", - "@tiptap/extension-focus": "^2.7.2", - "@tiptap/extension-gapcursor": "^2.7.2", - "@tiptap/extension-hard-break": "^2.7.2", - "@tiptap/extension-heading": "^2.7.2", - "@tiptap/extension-history": "^2.7.2", - "@tiptap/extension-horizontal-rule": "^2.7.2", - "@tiptap/extension-image": "^2.7.2", - "@tiptap/extension-italic": "^2.7.2", - "@tiptap/extension-link": "^2.7.2", - "@tiptap/extension-list-item": "^2.7.2", - "@tiptap/extension-ordered-list": "^2.7.2", - "@tiptap/extension-paragraph": "^2.7.2", - "@tiptap/extension-placeholder": "^2.7.2", - "@tiptap/extension-strike": "^2.7.2", - "@tiptap/extension-task-item": "^2.7.2", - "@tiptap/extension-task-list": "^2.7.2", - "@tiptap/extension-text": "^2.7.2", - "@tiptap/extension-typography": "^2.7.2", - "@tiptap/pm": "^2.7.2", - "@tiptap/react": "^2.7.2", - "@tiptap/starter-kit": "^2.7.2", - "@tiptap/suggestion": "^2.7.2", - "axios": "^1.7.7", - "cheerio": "1.0.0", - "class-variance-authority": "^0.7.0", - "clsx": "^2.1.1", - "cmdk": "^1.0.0", - "date-fns": "^3.6.0", - "framer-motion": "^11.5.6", - "geist": "^1.3.1", - "jazz-browser-auth-clerk": "0.8.0", - "jazz-react": "0.8.0", - "jazz-react-auth-clerk": "0.8.0", - "jazz-tools": "0.8.0", - "jotai": "^2.10.0", - "lowlight": "^3.1.0", - "lucide-react": "^0.429.0", - "next": "14.2.10", - "next-themes": "^0.3.0", - "nuqs": "^1.19.1", - "query-string": "^9.1.0", - "react": "^18.3.1", - "react-day-picker": "^8.10.1", - "react-dom": "^18.3.1", - "react-hook-form": "^7.53.0", - "react-textarea-autosize": "^8.5.3", - "ronin": "^4.3.1", - "slugify": "^1.6.6", - "sonner": "^1.5.0", - "streaming-markdown": "^0.0.14", - "tailwind-merge": "^2.5.2", - "tailwindcss-animate": "^1.0.7", - "vaul": "^0.9.4", - "zod": "^3.23.8", - "zsa": "^0.6.0", - "zsa-react": "^0.2.3" - }, - "devDependencies": { - "@ronin/learn-anything": "0.0.0-3452357373461", - "@testing-library/jest-dom": "^6.5.0", - "@testing-library/react": "^16.0.1", - "@types/jest": "^29.5.13", - "@types/node": "^22.5.5", - "@types/react": "^18.3.8", - "@types/react-dom": "^18.3.0", - "dotenv": "^16.4.5", - "eslint": "^8.57.1", - "eslint-config-next": "14.2.5", - "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", - "postcss": "^8.4.47", - "prettier-plugin-tailwindcss": "^0.6.6", - "tailwindcss": "^3.4.12", - "ts-jest": "^29.2.5", - "ts-node": "^10.9.2", - "typescript": "^5.6.2" - } + "name": "web", + "version": "0.1.0", + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint", + "test": "jest" + }, + "dependencies": { + "@clerk/nextjs": "^5.6.0", + "@dnd-kit/core": "^6.1.0", + "@dnd-kit/modifiers": "^7.0.0", + "@dnd-kit/sortable": "^8.0.0", + "@hookform/resolvers": "^3.9.0", + "@nothing-but/force-graph": "^0.9.5", + "@nothing-but/utils": "^0.16.0", + "@omit/react-confirm-dialog": "^1.1.5", + "@omit/react-fancy-switch": "^0.1.3", + "@radix-ui/react-alert-dialog": "^1.1.1", + "@radix-ui/react-avatar": "^1.1.0", + "@radix-ui/react-checkbox": "^1.1.1", + "@radix-ui/react-context-menu": "^2.2.1", + "@radix-ui/react-dialog": "^1.1.1", + "@radix-ui/react-dismissable-layer": "^1.1.0", + "@radix-ui/react-dropdown-menu": "^2.1.1", + "@radix-ui/react-focus-scope": "^1.1.0", + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-popover": "^1.1.1", + "@radix-ui/react-scroll-area": "^1.1.0", + "@radix-ui/react-select": "^2.1.1", + "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-switch": "^1.1.0", + "@radix-ui/react-toggle": "^1.1.0", + "@radix-ui/react-toggle-group": "^1.1.0", + "@radix-ui/react-tooltip": "^1.1.2", + "@sentry/nextjs": "^8.31.0", + "@tanstack/react-virtual": "^3.10.8", + "@tiptap/core": "^2.7.2", + "@tiptap/extension-blockquote": "^2.7.2", + "@tiptap/extension-bold": "^2.7.2", + "@tiptap/extension-bullet-list": "^2.7.2", + "@tiptap/extension-code": "^2.7.2", + "@tiptap/extension-code-block-lowlight": "^2.7.2", + "@tiptap/extension-color": "^2.7.2", + "@tiptap/extension-document": "^2.7.2", + "@tiptap/extension-dropcursor": "^2.7.2", + "@tiptap/extension-focus": "^2.7.2", + "@tiptap/extension-gapcursor": "^2.7.2", + "@tiptap/extension-hard-break": "^2.7.2", + "@tiptap/extension-heading": "^2.7.2", + "@tiptap/extension-history": "^2.7.2", + "@tiptap/extension-horizontal-rule": "^2.7.2", + "@tiptap/extension-image": "^2.7.2", + "@tiptap/extension-italic": "^2.7.2", + "@tiptap/extension-link": "^2.7.2", + "@tiptap/extension-list-item": "^2.7.2", + "@tiptap/extension-ordered-list": "^2.7.2", + "@tiptap/extension-paragraph": "^2.7.2", + "@tiptap/extension-placeholder": "^2.7.2", + "@tiptap/extension-strike": "^2.7.2", + "@tiptap/extension-task-item": "^2.7.2", + "@tiptap/extension-task-list": "^2.7.2", + "@tiptap/extension-text": "^2.7.2", + "@tiptap/extension-typography": "^2.7.2", + "@tiptap/pm": "^2.7.2", + "@tiptap/react": "^2.7.2", + "@tiptap/starter-kit": "^2.7.2", + "@tiptap/suggestion": "^2.7.2", + "axios": "^1.7.7", + "cheerio": "1.0.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "cmdk": "^1.0.0", + "date-fns": "^3.6.0", + "framer-motion": "^11.5.6", + "geist": "^1.3.1", + "jazz-browser-auth-clerk": "0.8.0", + "jazz-react": "0.8.0", + "jazz-react-auth-clerk": "0.8.0", + "jazz-tools": "0.8.0", + "jotai": "^2.10.0", + "lowlight": "^3.1.0", + "lucide-react": "^0.429.0", + "next": "14.2.10", + "next-themes": "^0.3.0", + "nuqs": "^1.19.2", + "query-string": "^9.1.0", + "react": "^18.3.1", + "react-day-picker": "^8.10.1", + "react-dom": "^18.3.1", + "react-hook-form": "^7.53.0", + "react-textarea-autosize": "^8.5.3", + "ronin": "^4.3.1", + "slugify": "^1.6.6", + "sonner": "^1.5.0", + "streaming-markdown": "^0.0.14", + "tailwind-merge": "^2.5.2", + "tailwindcss-animate": "^1.0.7", + "vaul": "^0.9.4", + "zod": "^3.23.8", + "zsa": "^0.6.0", + "zsa-react": "^0.2.3" + }, + "devDependencies": { + "@ronin/learn-anything": "^0.0.0-3453250405724", + "@testing-library/jest-dom": "^6.5.0", + "@testing-library/react": "^16.0.1", + "@types/jest": "^29.5.13", + "@types/node": "^22.6.1", + "@types/react": "^18.3.8", + "@types/react-dom": "^18.3.0", + "dotenv": "^16.4.5", + "eslint": "^8.57.1", + "eslint-config-next": "14.2.5", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "postcss": "^8.4.47", + "prettier-plugin-tailwindcss": "^0.6.6", + "tailwindcss": "^3.4.13", + "ts-jest": "^29.2.5", + "ts-node": "^10.9.2", + "typescript": "^5.6.2" + } }