feat: add AI settings controls
This commit is contained in:
@@ -71,6 +71,8 @@ function ShortcutsList({ os }: { os: Os }) {
|
||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||
|
||||
interface AIToolbarProps {
|
||||
adminAiEnabled: boolean;
|
||||
aiEnabled: boolean;
|
||||
isAuthenticated: boolean;
|
||||
isPending: boolean;
|
||||
aiPrompt: string;
|
||||
@@ -94,6 +96,8 @@ interface AIToolbarProps {
|
||||
// ─── Component ────────────────────────────────────────────────────────────────
|
||||
|
||||
export const AIToolbar = ({
|
||||
adminAiEnabled,
|
||||
aiEnabled,
|
||||
isAuthenticated,
|
||||
isPending,
|
||||
aiPrompt,
|
||||
@@ -255,10 +259,28 @@ export const AIToolbar = ({
|
||||
}
|
||||
|
||||
const hasImages = imagePreviews.length > 0;
|
||||
const canUseAi = adminAiEnabled && aiEnabled;
|
||||
const showDisabledState = isAuthenticated && !canUseAi;
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
{isAuthenticated ? (
|
||||
{showDisabledState ? (
|
||||
<div className="flex items-center gap-3 py-2">
|
||||
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground">
|
||||
<Sparkles className="h-4 w-4" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="text-sm font-medium leading-tight text-foreground">
|
||||
AI integrations are unavailable
|
||||
</p>
|
||||
<p className="mt-0.5 text-sm leading-relaxed text-muted-foreground">
|
||||
{adminAiEnabled
|
||||
? "AI has been turned off in this browser from Settings."
|
||||
: "AI integrations are currently disabled by the administrator."}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
) : isAuthenticated ? (
|
||||
<div className="space-y-4">
|
||||
<div className="rounded-2xl border border-border/70 bg-background/90 shadow-sm focus-within:ring-2 focus-within:ring-primary/30">
|
||||
<Textarea
|
||||
@@ -316,7 +338,7 @@ export const AIToolbar = ({
|
||||
size="sm"
|
||||
className="h-7 max-w-full rounded-full px-2.5 text-[11px]"
|
||||
onClick={() => onAiTemplateSelect(prompt)}
|
||||
disabled={aiLoading}
|
||||
disabled={aiLoading || !canUseAi}
|
||||
>
|
||||
<span className="truncate">{prompt}</span>
|
||||
</Button>
|
||||
@@ -371,7 +393,7 @@ export const AIToolbar = ({
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<ImagePicker
|
||||
onFilesSelect={onImagesSelect}
|
||||
disabled={aiLoading}
|
||||
disabled={aiLoading || !canUseAi}
|
||||
multiple
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
@@ -425,7 +447,7 @@ export const AIToolbar = ({
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={onAiSummarize}
|
||||
disabled={aiLoading}
|
||||
disabled={aiLoading || !canUseAi}
|
||||
className="h-9 gap-1.5 rounded-xl px-3 text-xs text-muted-foreground hover:text-primary"
|
||||
>
|
||||
<Bot className="h-3 w-3" />
|
||||
@@ -437,7 +459,9 @@ export const AIToolbar = ({
|
||||
size="sm"
|
||||
className="h-10 gap-1.5 rounded-xl px-4 text-xs"
|
||||
onClick={onAiCreate}
|
||||
disabled={aiLoading || (!aiPrompt.trim() && !hasImages)}
|
||||
disabled={
|
||||
aiLoading || !canUseAi || (!aiPrompt.trim() && !hasImages)
|
||||
}
|
||||
>
|
||||
{aiLoading ? (
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
||||
@@ -456,11 +480,11 @@ export const AIToolbar = ({
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-foreground leading-tight">
|
||||
Generate event drafts with AI
|
||||
Sign in required to generate event drafts with AI
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground mt-0.5">
|
||||
Paste natural language or a flyer, then review the filled event
|
||||
before saving.
|
||||
Sign in to turn natural language or flyers into event drafts, then
|
||||
review or save them from your calendar workflow.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user