File size: 3,985 Bytes
921d377
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
 * Step 3 — Policy profile picker.
 *
 * The 6 built-in profiles mirror policy/profiles.py. Selecting
 * one decides the runtime guardrails (consent gates, region
 * blocks, narration moderation). For the mature_gated profile we
 * surface an extra warning banner so authors can't pick it
 * accidentally.
 */

import React from "react";
import { ShieldAlert, ShieldCheck } from "lucide-react";
import type { WizardForm } from "../wizardState";

export interface Step3Props {
  form: WizardForm;
  setForm: (patch: Partial<WizardForm>) => void;
}

interface ProfileOption {
  id: string;
  label: string;
  short: string;
  long: string;
  mature: boolean;
}

const PROFILES: ProfileOption[] = [
  { id: "sfw_general", label: "SFW · General",
    short: "Safe for any audience.",
    long: "Default guardrails. No mature intents. No consent prompt.",
    mature: false },
  { id: "sfw_education", label: "SFW · Education",
    short: "Tutorials and lessons.",
    long: "Adds curriculum-friendly tone defaults; same SFW gates.",
    mature: false },
  { id: "language_learning", label: "Language learning",
    short: "Conversational practice.",
    long: "CEFR-aware progression; SFW gates with permissive tone presets.",
    mature: false },
  { id: "enterprise_training", label: "Enterprise training",
    short: "Onboarding & compliance.",
    long: "Strict tone profile + audit-friendly events. Region block enforced.",
    mature: false },
  { id: "social_romantic", label: "Social / Romantic",
    short: "Mood-aware companions.",
    long: "Allows flirty / affectionate intents. Universal-block intents stay blocked.",
    mature: false },
  { id: "mature_gated", label: "Mature (gated)",
    short: "Adults only — explicit consent required.",
    long: "Enables mature narration intents. REQUIRES consent + region check.",
    mature: true },
];

export function Step3Policy({ form, setForm }: Step3Props) {
  const selected = PROFILES.find((p) => p.id === form.policy_profile_id);

  return (
    <div className="flex flex-col gap-4">
      <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
        {PROFILES.map((p) => {
          const isSelected = form.policy_profile_id === p.id;
          return (
            <button
              key={p.id}
              type="button"
              onClick={() => setForm({ policy_profile_id: p.id })}
              aria-pressed={isSelected}
              className={[
                "text-left bg-[#121212] border rounded-md p-3.5 transition-colors flex gap-3",
                "focus:outline-none focus-visible:ring-2 focus-visible:ring-[#3ea6ff]",
                isSelected
                  ? "border-[#3ea6ff] bg-[rgba(62,166,255,0.08)] ring-1 ring-[#3ea6ff]"
                  : "border-[#3f3f3f] hover:border-[#555] hover:bg-[#1a1a1a]",
              ].join(" ")}
            >
              <div className="shrink-0 mt-0.5">
                {p.mature
                  ? <ShieldAlert className="w-5 h-5 text-amber-400" aria-hidden />
                  : <ShieldCheck className="w-5 h-5 text-emerald-400" aria-hidden />}
              </div>
              <div className="flex-1 min-w-0">
                <div className="text-sm font-medium text-[#f1f1f1]">{p.label}</div>
                <div className="text-xs text-[#aaa] mt-0.5">{p.short}</div>
              </div>
            </button>
          );
        })}
      </div>

      {selected && (
        <div
          className={[
            "rounded-md border p-3 text-xs",
            selected.mature
              ? "border-amber-500/40 bg-amber-500/5 text-amber-200"
              : "border-[#3f3f3f] bg-[#121212] text-[#cfd8dc]",
          ].join(" ")}
          aria-live="polite"
        >
          <span className="font-semibold">{selected.label}.</span> {selected.long}
        </div>
      )}
    </div>
  );
}

/** Always valid — every option is a known profile. */
export function step3Valid(_f: WizardForm): boolean {
  return true;
}