diff --git a/apps/api/src/db/organization_config.py b/apps/api/src/db/organization_config.py index 54f45484..a54e537e 100644 --- a/apps/api/src/db/organization_config.py +++ b/apps/api/src/db/organization_config.py @@ -40,7 +40,6 @@ class AssignmentOrgConfig(BaseModel): class PaymentOrgConfig(BaseModel): enabled: bool = True - stripe_key: str = "" class DiscussionOrgConfig(BaseModel): @@ -91,7 +90,7 @@ class OrgCloudConfig(BaseModel): # Main Config class OrganizationConfigBase(BaseModel): - config_version: str = "1.1" + config_version: str = "1.2" general: OrgGeneralConfig features: OrgFeatureConfig cloud: OrgCloudConfig diff --git a/apps/api/src/services/install/install.py b/apps/api/src/services/install/install.py index 935caf80..84841fb4 100644 --- a/apps/api/src/services/install/install.py +++ b/apps/api/src/services/install/install.py @@ -330,7 +330,7 @@ def install_create_organization(org_object: OrganizationCreate, db_session: Sess # Org Config org_config = OrganizationConfigBase( - config_version="1.1", + config_version="1.2", general=OrgGeneralConfig( enabled=True, color="normal", @@ -345,7 +345,7 @@ def install_create_organization(org_object: OrganizationCreate, db_session: Sess storage=StorageOrgConfig(enabled=True, limit=0), ai=AIOrgConfig(enabled=True, limit=0, model="gpt-4o-mini"), assignments=AssignmentOrgConfig(enabled=True, limit=0), - payments=PaymentOrgConfig(enabled=True, stripe_key=""), + payments=PaymentOrgConfig(enabled=False), discussions=DiscussionOrgConfig(enabled=True, limit=0), analytics=AnalyticsOrgConfig(enabled=True, limit=0), collaboration=CollaborationOrgConfig(enabled=True, limit=0), diff --git a/apps/api/src/tests/utils/init_data_for_tests.py b/apps/api/src/tests/utils/init_data_for_tests.py index 8229cfe2..7e140d2b 100644 --- a/apps/api/src/tests/utils/init_data_for_tests.py +++ b/apps/api/src/tests/utils/init_data_for_tests.py @@ -8,7 +8,7 @@ from src.services.install.install import ( install_default_elements, ) - +# TODO: Depreceated and need to be removed and remade async def create_initial_data_for_tests(db_session: Session): # Install default elements await install_default_elements({}, db_session) diff --git a/apps/web/app/orgs/[orgslug]/dash/payments/[subpage]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/payments/[subpage]/page.tsx index d305180e..173ececd 100644 --- a/apps/web/app/orgs/[orgslug]/dash/payments/[subpage]/page.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/payments/[subpage]/page.tsx @@ -10,8 +10,7 @@ import { useOrg } from '@components/Contexts/OrgContext' import PaymentsConfigurationPage from '@components/Dashboard/Pages/Payments/PaymentsConfigurationPage' import PaymentsProductPage from '@components/Dashboard/Pages/Payments/PaymentsProductPage' import PaymentsCustomersPage from '@components/Dashboard/Pages/Payments/PaymentsCustomersPage' - - +import useFeatureFlag from '@components/Hooks/useFeatureFlag' export type PaymentsParams = { subpage: string @@ -24,11 +23,28 @@ function PaymentsPage({ params }: { params: PaymentsParams }) { const [selectedSubPage, setSelectedSubPage] = useState(params.subpage || 'general') const [H1Label, setH1Label] = useState('') const [H2Label, setH2Label] = useState('') + + const isPaymentsEnabled = useFeatureFlag({ + path: ['features', 'payments', 'enabled'], + defaultValue: false + }) useEffect(() => { handleLabels() }, [selectedSubPage]) + if (!isPaymentsEnabled) { + return ( +
+
+

Payments Not Available

+

The payments feature is not enabled for this organization.

+

Please contact your administrator to enable payments.

+
+
+ ) + } + function handleLabels() { if (selectedSubPage === 'general') { setH1Label('Payments') diff --git a/apps/web/components/Dashboard/Menus/DashLeftMenu.tsx b/apps/web/components/Dashboard/Menus/DashLeftMenu.tsx index 5d90e4e5..4b0a3931 100644 --- a/apps/web/components/Dashboard/Menus/DashLeftMenu.tsx +++ b/apps/web/components/Dashboard/Menus/DashLeftMenu.tsx @@ -11,11 +11,13 @@ import UserAvatar from '../../Objects/UserAvatar' import AdminAuthorization from '@components/Security/AdminAuthorization' import { useLHSession } from '@components/Contexts/LHSessionContext' import { getUriWithOrg, getUriWithoutOrg } from '@services/config/config' +import useFeatureFlag from '@components/Hooks/useFeatureFlag' function DashLeftMenu() { const org = useOrg() as any const session = useLHSession() as any const [loading, setLoading] = React.useState(true) + const isPaymentsEnabled = useFeatureFlag({ path: ['features', 'payments', 'enabled'], defaultValue: false }) function waitForEverythingToLoad() { if (org && session) { @@ -112,14 +114,16 @@ function DashLeftMenu() { - - - - - + {isPaymentsEnabled && ( + + + + + + )} (!!feature.defaultValue) + + useEffect(() => { + if (org?.config?.config) { + let currentValue = org.config.config + + // Traverse the path to get the feature flag value + for (const key of feature.path) { + if (currentValue && typeof currentValue === 'object') { + currentValue = currentValue[key] + } else { + currentValue = feature.defaultValue || false + break + } + } + + setIsEnabled(!!currentValue) + } else { + setIsEnabled(!!feature.defaultValue) + } + }, [org, feature]) + + return isEnabled +} + +export default useFeatureFlag \ No newline at end of file diff --git a/apps/web/components/Objects/Courses/CourseActions/CoursePaidOptions.tsx b/apps/web/components/Objects/Courses/CourseActions/CoursePaidOptions.tsx index 67813140..c2537497 100644 --- a/apps/web/components/Objects/Courses/CourseActions/CoursePaidOptions.tsx +++ b/apps/web/components/Objects/Courses/CourseActions/CoursePaidOptions.tsx @@ -4,8 +4,8 @@ import { useLHSession } from '@components/Contexts/LHSessionContext' import useSWR from 'swr' import { getProductsByCourse, getStripeProductCheckoutSession } from '@services/payments/products' import { RefreshCcw, SquareCheck, ChevronDown, ChevronUp } from 'lucide-react' -import { Badge } from '@components/Ui/badge' -import { Button } from '@components/Ui/button' +import { Badge } from '@components/ui/badge' +import { Button } from '@components/ui/button' import toast from 'react-hot-toast' import { useRouter } from 'next/navigation' import { getUriWithOrg } from '@services/config/config' diff --git a/apps/web/components/Objects/Modals/Course/Create/CreateCourse.tsx b/apps/web/components/Objects/Modals/Course/Create/CreateCourse.tsx index 0eb79918..f20f1490 100644 --- a/apps/web/components/Objects/Modals/Course/Create/CreateCourse.tsx +++ b/apps/web/components/Objects/Modals/Course/Create/CreateCourse.tsx @@ -1,7 +1,7 @@ 'use client' -import { Input } from "@components/Ui/input" -import { Textarea } from "@components/Ui/textarea" -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@components/Ui/select" +import { Input } from "@components/ui/input" +import { Textarea } from "@components/ui/textarea" +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@components/ui/select" import FormLayout, { FormField, FormLabelAndMessage, diff --git a/apps/web/components/Objects/StyledElements/Modal/Modal.tsx b/apps/web/components/Objects/StyledElements/Modal/Modal.tsx index fe839f61..dc0f859a 100644 --- a/apps/web/components/Objects/StyledElements/Modal/Modal.tsx +++ b/apps/web/components/Objects/StyledElements/Modal/Modal.tsx @@ -1,7 +1,7 @@ 'use client' import React from 'react' -import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, DialogFooter } from "@components/Ui/dialog" +import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, DialogFooter } from "@components/ui/dialog" import { ButtonBlack } from '../Form/Form' import { cn } from "@/lib/utils" diff --git a/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx b/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx index 9871dff4..42ebb5f0 100644 --- a/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx +++ b/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx @@ -17,7 +17,7 @@ import { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, -} from "@components/Ui/dropdown-menu" +} from "@components/ui/dropdown-menu" type Course = { course_uuid: string diff --git a/apps/web/components/Pages/Payments/UnconfiguredPaymentsDisclaimer.tsx b/apps/web/components/Pages/Payments/UnconfiguredPaymentsDisclaimer.tsx index a87f0df2..1ed9bc08 100644 --- a/apps/web/components/Pages/Payments/UnconfiguredPaymentsDisclaimer.tsx +++ b/apps/web/components/Pages/Payments/UnconfiguredPaymentsDisclaimer.tsx @@ -1,5 +1,5 @@ import { Settings, ChevronRight, CreditCard } from 'lucide-react' -import { Alert, AlertTitle, AlertDescription } from '@components/Ui/alert' +import { Alert, AlertTitle, AlertDescription } from '@components/ui/alert' import { AlertTriangle, ShoppingCart, Users } from 'lucide-react' import React from 'react' import Link from 'next/link' diff --git a/apps/web/components/ui/toggle-group.tsx b/apps/web/components/ui/toggle-group.tsx index 41063bda..4df0e4fe 100644 --- a/apps/web/components/ui/toggle-group.tsx +++ b/apps/web/components/ui/toggle-group.tsx @@ -5,7 +5,7 @@ import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group" import { type VariantProps } from "class-variance-authority" import { cn } from "@/lib/utils" -import { toggleVariants } from "@components/Ui/toggle" +import { toggleVariants } from "@components/ui/toggle" const ToggleGroupContext = React.createContext< VariantProps