luxlabs 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/package.json +1 -1
  2. package/templates/interface-boilerplate/app/api/auth/[...all]/route.ts +52 -0
  3. package/templates/interface-boilerplate/app/auth/callback/page.tsx +22 -31
  4. package/templates/interface-boilerplate/app/dashboard/page.tsx +41 -214
  5. package/templates/interface-boilerplate/app/favicon.ico +0 -0
  6. package/templates/interface-boilerplate/app/globals.css +18 -113
  7. package/templates/interface-boilerplate/app/layout.tsx +21 -33
  8. package/templates/interface-boilerplate/app/page.tsx +37 -116
  9. package/templates/interface-boilerplate/app/settings/page.tsx +71 -0
  10. package/templates/interface-boilerplate/app/sign-in/page.tsx +19 -0
  11. package/templates/interface-boilerplate/app/sign-up/page.tsx +19 -0
  12. package/templates/interface-boilerplate/components/auth/sign-in-form.tsx +144 -0
  13. package/templates/interface-boilerplate/components/auth/sign-up-form.tsx +236 -0
  14. package/templates/interface-boilerplate/components/ui/badge.tsx +18 -14
  15. package/templates/interface-boilerplate/components/ui/button.tsx +29 -24
  16. package/templates/interface-boilerplate/components/ui/card.tsx +76 -57
  17. package/templates/interface-boilerplate/components/ui/input.tsx +8 -9
  18. package/templates/interface-boilerplate/eslint.config.mjs +18 -0
  19. package/templates/interface-boilerplate/lib/auth-client.ts +18 -0
  20. package/templates/interface-boilerplate/lib/auth.config.ts +111 -0
  21. package/templates/interface-boilerplate/lib/lux.ts +8 -0
  22. package/templates/interface-boilerplate/lib/utils.ts +3 -3
  23. package/templates/interface-boilerplate/middleware.ts +60 -0
  24. package/templates/interface-boilerplate/next.config.ts +7 -0
  25. package/templates/interface-boilerplate/package-lock.json +6855 -0
  26. package/templates/interface-boilerplate/package.json +18 -37
  27. package/templates/interface-boilerplate/postcss.config.mjs +7 -0
  28. package/templates/interface-boilerplate/tsconfig.json +18 -4
  29. package/templates/interface-boilerplate/.env.example +0 -2
  30. package/templates/interface-boilerplate/.eslintrc.json +0 -4
  31. package/templates/interface-boilerplate/app/login/page.tsx +0 -178
  32. package/templates/interface-boilerplate/app/signup/page.tsx +0 -199
  33. package/templates/interface-boilerplate/components/AnalyticsProvider.tsx +0 -142
  34. package/templates/interface-boilerplate/components/AuthGuard.tsx +0 -76
  35. package/templates/interface-boilerplate/components/ErrorBoundary.tsx +0 -106
  36. package/templates/interface-boilerplate/components/theme-provider.tsx +0 -9
  37. package/templates/interface-boilerplate/components/theme-toggle.tsx +0 -39
  38. package/templates/interface-boilerplate/components/ui/avatar.tsx +0 -46
  39. package/templates/interface-boilerplate/components/ui/checkbox.tsx +0 -27
  40. package/templates/interface-boilerplate/components/ui/dialog.tsx +0 -100
  41. package/templates/interface-boilerplate/components/ui/dropdown-menu.tsx +0 -173
  42. package/templates/interface-boilerplate/components/ui/index.ts +0 -53
  43. package/templates/interface-boilerplate/components/ui/label.tsx +0 -20
  44. package/templates/interface-boilerplate/components/ui/progress.tsx +0 -24
  45. package/templates/interface-boilerplate/components/ui/select.tsx +0 -149
  46. package/templates/interface-boilerplate/components/ui/separator.tsx +0 -25
  47. package/templates/interface-boilerplate/components/ui/skeleton.tsx +0 -12
  48. package/templates/interface-boilerplate/components/ui/switch.tsx +0 -28
  49. package/templates/interface-boilerplate/components/ui/tabs.tsx +0 -54
  50. package/templates/interface-boilerplate/components/ui/textarea.tsx +0 -22
  51. package/templates/interface-boilerplate/components/ui/tooltip.tsx +0 -29
  52. package/templates/interface-boilerplate/lib/analytics.ts +0 -182
  53. package/templates/interface-boilerplate/lib/auth-context.tsx +0 -83
  54. package/templates/interface-boilerplate/lib/auth.ts +0 -199
  55. package/templates/interface-boilerplate/lib/callFlow.ts +0 -234
  56. package/templates/interface-boilerplate/lib/flowTracer.ts +0 -195
  57. package/templates/interface-boilerplate/lib/hooks/.gitkeep +0 -0
  58. package/templates/interface-boilerplate/lib/stores/.gitkeep +0 -0
  59. package/templates/interface-boilerplate/next.config.js +0 -6
  60. package/templates/interface-boilerplate/postcss.config.js +0 -6
  61. package/templates/interface-boilerplate/tailwind.config.js +0 -103
@@ -1,149 +0,0 @@
1
- 'use client';
2
-
3
- import * as React from 'react';
4
- import * as SelectPrimitive from '@radix-ui/react-select';
5
- import { Check, ChevronDown, ChevronUp } from 'lucide-react';
6
- import { cn } from '@/lib/utils';
7
-
8
- const Select = SelectPrimitive.Root;
9
- const SelectGroup = SelectPrimitive.Group;
10
- const SelectValue = SelectPrimitive.Value;
11
-
12
- const SelectTrigger = React.forwardRef<
13
- React.ElementRef<typeof SelectPrimitive.Trigger>,
14
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
15
- >(({ className, children, ...props }, ref) => (
16
- <SelectPrimitive.Trigger
17
- ref={ref}
18
- className={cn(
19
- 'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
20
- className
21
- )}
22
- {...props}
23
- >
24
- {children}
25
- <SelectPrimitive.Icon asChild>
26
- <ChevronDown className="h-4 w-4 opacity-50" />
27
- </SelectPrimitive.Icon>
28
- </SelectPrimitive.Trigger>
29
- ));
30
- SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
31
-
32
- const SelectScrollUpButton = React.forwardRef<
33
- React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
34
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
35
- >(({ className, ...props }, ref) => (
36
- <SelectPrimitive.ScrollUpButton
37
- ref={ref}
38
- className={cn('flex cursor-default items-center justify-center py-1', className)}
39
- {...props}
40
- >
41
- <ChevronUp className="h-4 w-4" />
42
- </SelectPrimitive.ScrollUpButton>
43
- ));
44
- SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
45
-
46
- const SelectScrollDownButton = React.forwardRef<
47
- React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
48
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
49
- >(({ className, ...props }, ref) => (
50
- <SelectPrimitive.ScrollDownButton
51
- ref={ref}
52
- className={cn('flex cursor-default items-center justify-center py-1', className)}
53
- {...props}
54
- >
55
- <ChevronDown className="h-4 w-4" />
56
- </SelectPrimitive.ScrollDownButton>
57
- ));
58
- SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
59
-
60
- const SelectContent = React.forwardRef<
61
- React.ElementRef<typeof SelectPrimitive.Content>,
62
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
63
- >(({ className, children, position = 'popper', ...props }, ref) => (
64
- <SelectPrimitive.Portal>
65
- <SelectPrimitive.Content
66
- ref={ref}
67
- className={cn(
68
- 'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
69
- position === 'popper' &&
70
- 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
71
- className
72
- )}
73
- position={position}
74
- {...props}
75
- >
76
- <SelectScrollUpButton />
77
- <SelectPrimitive.Viewport
78
- className={cn(
79
- 'p-1',
80
- position === 'popper' &&
81
- 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]'
82
- )}
83
- >
84
- {children}
85
- </SelectPrimitive.Viewport>
86
- <SelectScrollDownButton />
87
- </SelectPrimitive.Content>
88
- </SelectPrimitive.Portal>
89
- ));
90
- SelectContent.displayName = SelectPrimitive.Content.displayName;
91
-
92
- const SelectLabel = React.forwardRef<
93
- React.ElementRef<typeof SelectPrimitive.Label>,
94
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
95
- >(({ className, ...props }, ref) => (
96
- <SelectPrimitive.Label
97
- ref={ref}
98
- className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)}
99
- {...props}
100
- />
101
- ));
102
- SelectLabel.displayName = SelectPrimitive.Label.displayName;
103
-
104
- const SelectItem = React.forwardRef<
105
- React.ElementRef<typeof SelectPrimitive.Item>,
106
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
107
- >(({ className, children, ...props }, ref) => (
108
- <SelectPrimitive.Item
109
- ref={ref}
110
- className={cn(
111
- 'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
112
- className
113
- )}
114
- {...props}
115
- >
116
- <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
117
- <SelectPrimitive.ItemIndicator>
118
- <Check className="h-4 w-4" />
119
- </SelectPrimitive.ItemIndicator>
120
- </span>
121
- <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
122
- </SelectPrimitive.Item>
123
- ));
124
- SelectItem.displayName = SelectPrimitive.Item.displayName;
125
-
126
- const SelectSeparator = React.forwardRef<
127
- React.ElementRef<typeof SelectPrimitive.Separator>,
128
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
129
- >(({ className, ...props }, ref) => (
130
- <SelectPrimitive.Separator
131
- ref={ref}
132
- className={cn('-mx-1 my-1 h-px bg-muted', className)}
133
- {...props}
134
- />
135
- ));
136
- SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
137
-
138
- export {
139
- Select,
140
- SelectGroup,
141
- SelectValue,
142
- SelectTrigger,
143
- SelectContent,
144
- SelectLabel,
145
- SelectItem,
146
- SelectSeparator,
147
- SelectScrollUpButton,
148
- SelectScrollDownButton,
149
- };
@@ -1,25 +0,0 @@
1
- 'use client';
2
-
3
- import * as React from 'react';
4
- import * as SeparatorPrimitive from '@radix-ui/react-separator';
5
- import { cn } from '@/lib/utils';
6
-
7
- const Separator = React.forwardRef<
8
- React.ElementRef<typeof SeparatorPrimitive.Root>,
9
- React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
10
- >(({ className, orientation = 'horizontal', decorative = true, ...props }, ref) => (
11
- <SeparatorPrimitive.Root
12
- ref={ref}
13
- decorative={decorative}
14
- orientation={orientation}
15
- className={cn(
16
- 'shrink-0 bg-border',
17
- orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
18
- className
19
- )}
20
- {...props}
21
- />
22
- ));
23
- Separator.displayName = SeparatorPrimitive.Root.displayName;
24
-
25
- export { Separator };
@@ -1,12 +0,0 @@
1
- import { cn } from '@/lib/utils';
2
-
3
- function Skeleton({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
4
- return (
5
- <div
6
- className={cn('animate-pulse rounded-md bg-muted', className)}
7
- {...props}
8
- />
9
- );
10
- }
11
-
12
- export { Skeleton };
@@ -1,28 +0,0 @@
1
- 'use client';
2
-
3
- import * as React from 'react';
4
- import * as SwitchPrimitives from '@radix-ui/react-switch';
5
- import { cn } from '@/lib/utils';
6
-
7
- const Switch = React.forwardRef<
8
- React.ElementRef<typeof SwitchPrimitives.Root>,
9
- React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
10
- >(({ className, ...props }, ref) => (
11
- <SwitchPrimitives.Root
12
- className={cn(
13
- 'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
14
- className
15
- )}
16
- {...props}
17
- ref={ref}
18
- >
19
- <SwitchPrimitives.Thumb
20
- className={cn(
21
- 'pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0'
22
- )}
23
- />
24
- </SwitchPrimitives.Root>
25
- ));
26
- Switch.displayName = SwitchPrimitives.Root.displayName;
27
-
28
- export { Switch };
@@ -1,54 +0,0 @@
1
- 'use client';
2
-
3
- import * as React from 'react';
4
- import * as TabsPrimitive from '@radix-ui/react-tabs';
5
- import { cn } from '@/lib/utils';
6
-
7
- const Tabs = TabsPrimitive.Root;
8
-
9
- const TabsList = React.forwardRef<
10
- React.ElementRef<typeof TabsPrimitive.List>,
11
- React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
12
- >(({ className, ...props }, ref) => (
13
- <TabsPrimitive.List
14
- ref={ref}
15
- className={cn(
16
- 'inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground',
17
- className
18
- )}
19
- {...props}
20
- />
21
- ));
22
- TabsList.displayName = TabsPrimitive.List.displayName;
23
-
24
- const TabsTrigger = React.forwardRef<
25
- React.ElementRef<typeof TabsPrimitive.Trigger>,
26
- React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
27
- >(({ className, ...props }, ref) => (
28
- <TabsPrimitive.Trigger
29
- ref={ref}
30
- className={cn(
31
- 'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm',
32
- className
33
- )}
34
- {...props}
35
- />
36
- ));
37
- TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
38
-
39
- const TabsContent = React.forwardRef<
40
- React.ElementRef<typeof TabsPrimitive.Content>,
41
- React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
42
- >(({ className, ...props }, ref) => (
43
- <TabsPrimitive.Content
44
- ref={ref}
45
- className={cn(
46
- 'mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
47
- className
48
- )}
49
- {...props}
50
- />
51
- ));
52
- TabsContent.displayName = TabsPrimitive.Content.displayName;
53
-
54
- export { Tabs, TabsList, TabsTrigger, TabsContent };
@@ -1,22 +0,0 @@
1
- import * as React from 'react';
2
- import { cn } from '@/lib/utils';
3
-
4
- export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
5
-
6
- const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
7
- ({ className, ...props }, ref) => {
8
- return (
9
- <textarea
10
- className={cn(
11
- 'flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
12
- className
13
- )}
14
- ref={ref}
15
- {...props}
16
- />
17
- );
18
- }
19
- );
20
- Textarea.displayName = 'Textarea';
21
-
22
- export { Textarea };
@@ -1,29 +0,0 @@
1
- 'use client';
2
-
3
- import * as React from 'react';
4
- import * as TooltipPrimitive from '@radix-ui/react-tooltip';
5
- import { cn } from '@/lib/utils';
6
-
7
- const TooltipProvider = TooltipPrimitive.Provider;
8
-
9
- const Tooltip = TooltipPrimitive.Root;
10
-
11
- const TooltipTrigger = TooltipPrimitive.Trigger;
12
-
13
- const TooltipContent = React.forwardRef<
14
- React.ElementRef<typeof TooltipPrimitive.Content>,
15
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
16
- >(({ className, sideOffset = 4, ...props }, ref) => (
17
- <TooltipPrimitive.Content
18
- ref={ref}
19
- sideOffset={sideOffset}
20
- className={cn(
21
- 'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
22
- className
23
- )}
24
- {...props}
25
- />
26
- ));
27
- TooltipContent.displayName = TooltipPrimitive.Content.displayName;
28
-
29
- export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
@@ -1,182 +0,0 @@
1
- /**
2
- * PostHog Analytics Helper
3
- *
4
- * Initializes PostHog for tracking user behavior in production interfaces.
5
- *
6
- * Usage:
7
- * 1. Wrap your app with <AnalyticsProvider> (in layout.tsx)
8
- * 2. Use trackEvent() for custom events
9
- * 3. Use identifyUser() when user logs in
10
- * 4. Use resetUser() when user logs out
11
- *
12
- * A/B Testing (Feature Flags):
13
- * 1. Create experiments in PostHog dashboard
14
- * 2. Use useFeatureFlagVariantKey() hook in client components
15
- * 3. Use getFeatureFlag() for server-side or non-React code
16
- *
17
- * @see AnalyticsProvider component for React context setup
18
- */
19
-
20
- import posthog from 'posthog-js';
21
-
22
- const POSTHOG_KEY = process.env.NEXT_PUBLIC_POSTHOG_KEY || '';
23
- const POSTHOG_HOST = process.env.NEXT_PUBLIC_POSTHOG_HOST || 'https://us.i.posthog.com';
24
- const INTERFACE_ID = process.env.NEXT_PUBLIC_LUX_INTERFACE_ID || '';
25
-
26
- let initialized = false;
27
-
28
- /**
29
- * Initialize PostHog analytics
30
- * NOTE: Prefer using <AnalyticsProvider> instead of calling this directly.
31
- * This function is kept for backward compatibility and non-React contexts.
32
- */
33
- export function initAnalytics(): void {
34
- if (typeof window === 'undefined') return;
35
- if (initialized) return;
36
-
37
- if (!POSTHOG_KEY) {
38
- console.warn('[analytics] PostHog not configured - missing POSTHOG_KEY');
39
- return;
40
- }
41
-
42
- // Initialize PostHog with standard configuration
43
- posthog.init(POSTHOG_KEY, {
44
- api_host: POSTHOG_HOST,
45
- autocapture: true,
46
- capture_pageview: true,
47
- capture_pageleave: true,
48
- persistence: 'localStorage',
49
- loaded: (ph) => {
50
- // Register super properties that will be sent with every event
51
- if (INTERFACE_ID) {
52
- ph.register({
53
- $lux_interface_id: INTERFACE_ID,
54
- });
55
- }
56
- },
57
- });
58
-
59
- initialized = true;
60
- console.log('[analytics] PostHog initialized');
61
- }
62
-
63
- /**
64
- * Track a custom event
65
- * @param name - Event name (e.g., 'button_clicked', 'form_submitted')
66
- * @param properties - Optional event properties
67
- */
68
- export function trackEvent(name: string, properties?: Record<string, any>): void {
69
- if (!initialized && !posthog.__loaded) return;
70
- posthog.capture(name, properties);
71
- }
72
-
73
- /**
74
- * Identify a user (call when user logs in)
75
- * @param userId - Unique user identifier
76
- * @param properties - Optional user properties (email, name, etc.)
77
- */
78
- export function identifyUser(userId: string, properties?: Record<string, any>): void {
79
- if (!initialized && !posthog.__loaded) return;
80
- posthog.identify(userId, properties);
81
- }
82
-
83
- /**
84
- * Reset user identity (call when user logs out)
85
- */
86
- export function resetUser(): void {
87
- if (!initialized && !posthog.__loaded) return;
88
- posthog.reset();
89
- }
90
-
91
- /**
92
- * Check if analytics is initialized
93
- */
94
- export function isAnalyticsInitialized(): boolean {
95
- return initialized || posthog.__loaded;
96
- }
97
-
98
- // ============================================================================
99
- // A/B Testing & Feature Flags
100
- // ============================================================================
101
-
102
- /**
103
- * Get a feature flag value (for non-React contexts or server-side checks)
104
- *
105
- * For React components, prefer using the useFeatureFlagVariantKey hook:
106
- * ```tsx
107
- * import { useFeatureFlagVariantKey } from 'posthog-js/react';
108
- * const variant = useFeatureFlagVariantKey('my-experiment');
109
- * ```
110
- *
111
- * @param flagKey - The feature flag key from PostHog
112
- * @returns The variant key (e.g., 'control', 'test') or undefined if not loaded
113
- */
114
- export function getFeatureFlag(flagKey: string): string | boolean | undefined {
115
- if (!posthog.__loaded) return undefined;
116
- return posthog.getFeatureFlag(flagKey);
117
- }
118
-
119
- /**
120
- * Check if a feature flag is enabled (boolean flags)
121
- * @param flagKey - The feature flag key from PostHog
122
- * @returns true if enabled, false otherwise
123
- */
124
- export function isFeatureEnabled(flagKey: string): boolean {
125
- if (!posthog.__loaded) return false;
126
- return posthog.isFeatureEnabled(flagKey) ?? false;
127
- }
128
-
129
- /**
130
- * Get the payload associated with a feature flag
131
- * Useful for passing configuration data with experiments
132
- *
133
- * @param flagKey - The feature flag key from PostHog
134
- * @returns The payload object or undefined
135
- */
136
- export function getFeatureFlagPayload(flagKey: string): Record<string, any> | undefined {
137
- if (!posthog.__loaded) return undefined;
138
- return posthog.getFeatureFlagPayload(flagKey) as Record<string, any> | undefined;
139
- }
140
-
141
- /**
142
- * Manually reload feature flags
143
- * Useful after user identification or when you need fresh flag values
144
- */
145
- export function reloadFeatureFlags(): void {
146
- if (!posthog.__loaded) return;
147
- posthog.reloadFeatureFlags();
148
- }
149
-
150
- /**
151
- * Register a callback for when feature flags are loaded
152
- * @param callback - Function to call when flags are ready
153
- */
154
- export function onFeatureFlagsLoaded(callback: () => void): void {
155
- if (!posthog.__loaded) return;
156
- posthog.onFeatureFlags(callback);
157
- }
158
-
159
- /**
160
- * Track a conversion event for an A/B test
161
- * This helps PostHog calculate experiment results
162
- *
163
- * @param experimentKey - The experiment/feature flag key
164
- * @param eventName - The conversion event name (e.g., 'signup_completed')
165
- * @param properties - Optional additional properties
166
- */
167
- export function trackExperimentConversion(
168
- experimentKey: string,
169
- eventName: string,
170
- properties?: Record<string, any>
171
- ): void {
172
- if (!posthog.__loaded) return;
173
-
174
- // Get the current variant for attribution
175
- const variant = posthog.getFeatureFlag(experimentKey);
176
-
177
- posthog.capture(eventName, {
178
- ...properties,
179
- $experiment_key: experimentKey,
180
- $experiment_variant: variant,
181
- });
182
- }
@@ -1,83 +0,0 @@
1
- 'use client';
2
-
3
- import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
4
- import { User, AuthSession, getSession, signIn, signUp, signOut, signInWithGoogle } from './auth';
5
-
6
- interface AuthContextType {
7
- user: User | null;
8
- isLoading: boolean;
9
- isAuthenticated: boolean;
10
- signIn: (email: string, password: string) => Promise<{ success: boolean; error?: string }>;
11
- signUp: (email: string, password: string, name?: string) => Promise<{ success: boolean; error?: string }>;
12
- signOut: () => Promise<void>;
13
- signInWithGoogle: (redirectUri?: string) => void;
14
- refresh: () => Promise<void>;
15
- }
16
-
17
- const AuthContext = createContext<AuthContextType | null>(null);
18
-
19
- export function AuthProvider({ children }: { children: ReactNode }) {
20
- const [user, setUser] = useState<User | null>(null);
21
- const [isLoading, setIsLoading] = useState(true);
22
-
23
- const refresh = async () => {
24
- try {
25
- const session = await getSession();
26
- setUser(session?.user || null);
27
- } catch {
28
- setUser(null);
29
- } finally {
30
- setIsLoading(false);
31
- }
32
- };
33
-
34
- useEffect(() => {
35
- refresh();
36
- }, []);
37
-
38
- const handleSignIn = async (email: string, password: string) => {
39
- const result = await signIn(email, password);
40
- if (result.success && result.user) {
41
- setUser(result.user);
42
- }
43
- return result;
44
- };
45
-
46
- const handleSignUp = async (email: string, password: string, name?: string) => {
47
- const result = await signUp(email, password, name);
48
- if (result.success && result.user) {
49
- setUser(result.user);
50
- }
51
- return result;
52
- };
53
-
54
- const handleSignOut = async () => {
55
- await signOut();
56
- setUser(null);
57
- };
58
-
59
- return (
60
- <AuthContext.Provider
61
- value={{
62
- user,
63
- isLoading,
64
- isAuthenticated: !!user,
65
- signIn: handleSignIn,
66
- signUp: handleSignUp,
67
- signOut: handleSignOut,
68
- signInWithGoogle,
69
- refresh,
70
- }}
71
- >
72
- {children}
73
- </AuthContext.Provider>
74
- );
75
- }
76
-
77
- export function useAuth(): AuthContextType {
78
- const context = useContext(AuthContext);
79
- if (!context) {
80
- throw new Error('useAuth must be used within an AuthProvider');
81
- }
82
- return context;
83
- }