demeter

Autonomous Hydroponic Intelligence

frontend/src/components/Onboarding.jsx (11408B)


  1import React, { useState } from "react";
  2import { useNavigate } from "react-router-dom";
  3import {
  4  Leaf,
  5  LayoutGrid,
  6  PlusCircle,
  7  Bell,
  8  CheckCircle2,
  9  ChevronRight,
 10  X,
 11  Sparkles,
 12  HelpCircle,
 13} from "lucide-react";
 14import { useSettings } from "../hooks/useSettings";
 15import { useT } from "../hooks/useTranslation";
 16
 17const STEP_ICONS = [Leaf, LayoutGrid, PlusCircle, Bell, CheckCircle2, Sparkles];
 18const STEP_COLORS = [
 19  "var(--green)",
 20  "var(--blue)",
 21  "var(--green)",
 22  "var(--red)",
 23  "#f59e0b",
 24  "var(--blue)",
 25];
 26const STEP_KEYS = [
 27  { title: "onboarding_s1_title", desc: "onboarding_s1_desc" },
 28  { title: "onboarding_s2_title", desc: "onboarding_s2_desc" },
 29  { title: "onboarding_s3_title", desc: "onboarding_s3_desc" },
 30  { title: "onboarding_s4_title", desc: "onboarding_s4_desc" },
 31  { title: "onboarding_s5_title", desc: "onboarding_s5_desc" },
 32  { title: "onboarding_s6_title", desc: "onboarding_s6_desc" },
 33];
 34
 35export default function Onboarding({ onDone }) {
 36  const [step, setStep] = useState(0);
 37  const { update } = useSettings();
 38  const { t, lang } = useT();
 39  const navigate = useNavigate();
 40
 41  const total = STEP_KEYS.length;
 42  const isLast = step === total - 1;
 43  const Icon = STEP_ICONS[step];
 44  const color = STEP_COLORS[step];
 45  const { title: titleKey, desc: descKey } = STEP_KEYS[step];
 46
 47  const finish = () => {
 48    update("onboardingDone", true);
 49    onDone?.();
 50  };
 51
 52  const goToAI = () => {
 53    finish();
 54    navigate("/intelligence");
 55  };
 56
 57  const goToHelp = () => {
 58    finish();
 59    navigate("/help");
 60  };
 61
 62  // AI Labels
 63  const askAILabel = lang === "hi" ? "AI से पूछें →" : "Ask AI →";
 64  const askAISubLabel =
 65    lang === "hi"
 66      ? "सवाल हैं? फार्म बुद्धिमत्ता AI से पूछें"
 67      : "Have questions? Ask Farm Intelligence";
 68
 69  // Help Labels
 70  const helpLabel = lang === "hi" ? "मदद और शब्दकोश →" : "Help & Glossary →";
 71  const helpSubLabel =
 72    lang === "hi"
 73      ? "खेती के शब्द और AI के काम करने का तरीका समझें"
 74      : "Understand farming terms and how AI works";
 75
 76  return (
 77    /* Backdrop */
 78    <div
 79      style={{
 80        position: "fixed",
 81        inset: 0,
 82        zIndex: 9999,
 83        background: "rgba(0,0,0,0.65)",
 84        display: "flex",
 85        alignItems: "center",
 86        justifyContent: "center",
 87        padding: 24,
 88      }}
 89    >
 90      {/* Modal */}
 91      <div
 92        className="animate-fade-up"
 93        style={{
 94          width: "100%",
 95          maxWidth: 480,
 96          borderRadius: 20,
 97          background: "var(--bg-2)",
 98          border: "1px solid var(--border)",
 99          overflow: "hidden",
100          boxShadow: "0 24px 80px rgba(0,0,0,0.5)",
101        }}
102      >
103        {/* Header strip */}
104        <div
105          style={{
106            height: 4,
107            background: "var(--border)",
108            position: "relative",
109          }}
110        >
111          <div
112            style={{
113              position: "absolute",
114              left: 0,
115              top: 0,
116              height: "100%",
117              width: `${((step + 1) / total) * 100}%`,
118              background: color,
119              borderRadius: 4,
120              transition: "width 0.4s ease",
121            }}
122          />
123        </div>
124
125        {/* Top row */}
126        <div
127          style={{
128            display: "flex",
129            alignItems: "center",
130            justifyContent: "space-between",
131            padding: "16px 20px 0",
132          }}
133        >
134          <span
135            style={{
136              fontSize: 11,
137              fontFamily: "DM Mono, monospace",
138              color: "var(--text-3)",
139            }}
140          >
141            {t("onboarding_step", { n: step + 1, total })}
142          </span>
143          <button
144            onClick={finish}
145            style={{
146              background: "none",
147              border: "none",
148              cursor: "pointer",
149              color: "var(--text-3)",
150              display: "flex",
151              padding: 4,
152            }}
153          >
154            <X size={16} />
155          </button>
156        </div>
157
158        {/* Body */}
159        <div
160          style={{
161            padding: "24px 28px 28px",
162            display: "flex",
163            flexDirection: "column",
164            alignItems: "flex-start",
165            gap: 16,
166          }}
167        >
168          {/* Icon */}
169          <div
170            style={{
171              width: 56,
172              height: 56,
173              borderRadius: 16,
174              background: `${color}18`,
175              border: `1px solid ${color}35`,
176              display: "flex",
177              alignItems: "center",
178              justifyContent: "center",
179            }}
180          >
181            <Icon size={26} style={{ color }} />
182          </div>
183
184          {/* Title */}
185          <div
186            style={{
187              fontSize: 22,
188              fontWeight: 700,
189              color: "var(--text)",
190              lineHeight: 1.2,
191            }}
192          >
193            {t(titleKey)}
194          </div>
195
196          {/* Description */}
197          <div
198            style={{
199              fontSize: 14,
200              color: "var(--text-2)",
201              lineHeight: 1.75,
202              whiteSpace: "pre-line",
203              width: "100%",
204            }}
205          >
206            {t(descKey)}
207          </div>
208
209          {/* Help & AI Nudges */}
210          {isLast && (
211            <div
212              style={{
213                display: "flex",
214                flexDirection: "column",
215                gap: 10,
216                width: "100%",
217              }}
218            >
219              {/* Help Page Link */}
220              <div
221                style={{
222                  width: "100%",
223                  padding: "12px 14px",
224                  borderRadius: 10,
225                  background: "rgba(59,130,246,0.08)",
226                  border: "1px solid rgba(59,130,246,0.25)",
227                  display: "flex",
228                  alignItems: "center",
229                  gap: 10,
230                  cursor: "pointer",
231                  boxSizing: "border-box",
232                }}
233                onClick={goToHelp}
234              >
235                <div
236                  style={{
237                    width: 32,
238                    height: 32,
239                    borderRadius: 8,
240                    background: "rgba(59,130,246,0.15)",
241                    display: "flex",
242                    alignItems: "center",
243                    justifyContent: "center",
244                    flexShrink: 0,
245                  }}
246                >
247                  <HelpCircle size={15} style={{ color: "var(--blue)" }} />
248                </div>
249                <div>
250                  <div
251                    style={{
252                      fontSize: 12,
253                      fontWeight: 700,
254                      color: "var(--blue)",
255                      marginBottom: 2,
256                    }}
257                  >
258                    {helpLabel}
259                  </div>
260                  <div style={{ fontSize: 11, color: "var(--text-3)" }}>
261                    {helpSubLabel}
262                  </div>
263                </div>
264                <ChevronRight
265                  size={14}
266                  style={{ color: "var(--blue)", marginLeft: "auto" }}
267                />
268              </div>
269
270              {/* Ask AI Nudge */}
271              <div
272                style={{
273                  width: "100%",
274                  padding: "12px 14px",
275                  borderRadius: 10,
276                  background: "rgba(74,222,128,0.08)",
277                  border: "1px solid rgba(74,222,128,0.25)",
278                  display: "flex",
279                  alignItems: "center",
280                  gap: 10,
281                  cursor: "pointer",
282                  boxSizing: "border-box",
283                }}
284                onClick={goToAI}
285              >
286                <div
287                  style={{
288                    width: 32,
289                    height: 32,
290                    borderRadius: 8,
291                    background: "rgba(74,222,128,0.15)",
292                    display: "flex",
293                    alignItems: "center",
294                    justifyContent: "center",
295                    flexShrink: 0,
296                  }}
297                >
298                  <Sparkles size={15} style={{ color: "var(--green)" }} />
299                </div>
300                <div>
301                  <div
302                    style={{
303                      fontSize: 12,
304                      fontWeight: 700,
305                      color: "var(--green)",
306                      marginBottom: 2,
307                    }}
308                  >
309                    {askAILabel}
310                  </div>
311                  <div style={{ fontSize: 11, color: "var(--text-3)" }}>
312                    {askAISubLabel}
313                  </div>
314                </div>
315                <ChevronRight
316                  size={14}
317                  style={{ color: "var(--green)", marginLeft: "auto" }}
318                />
319              </div>
320            </div>
321          )}
322
323          {/* Step dots */}
324          <div
325            style={{
326              display: "flex",
327              gap: 6,
328              marginTop: 4,
329              alignSelf: "center",
330            }}
331          >
332            {STEP_KEYS.map((_, i) => (
333              <div
334                key={i}
335                onClick={() => setStep(i)}
336                style={{
337                  width: i === step ? 18 : 7,
338                  height: 7,
339                  borderRadius: 4,
340                  background: i === step ? color : "var(--border)",
341                  cursor: "pointer",
342                  transition: "all 0.3s",
343                }}
344              />
345            ))}
346          </div>
347
348          {/* Buttons */}
349          <div
350            style={{
351              display: "flex",
352              gap: 10,
353              width: "100%",
354              marginTop: 4,
355            }}
356          >
357            {!isLast && (
358              <button
359                onClick={finish}
360                style={{
361                  flex: 1,
362                  padding: "10px 0",
363                  borderRadius: 10,
364                  fontSize: 13,
365                  fontWeight: 500,
366                  background: "var(--surface)",
367                  border: "1px solid var(--border)",
368                  color: "var(--text-3)",
369                  cursor: "pointer",
370                }}
371              >
372                {t("onboarding_skip")}
373              </button>
374            )}
375
376            <button
377              onClick={() => (isLast ? finish() : setStep((s) => s + 1))}
378              style={{
379                flex: isLast ? 1 : 2,
380                padding: "10px 0",
381                borderRadius: 10,
382                fontSize: 14,
383                fontWeight: 700,
384                background: color,
385                border: "none",
386                color: "#0c1a0e",
387                cursor: "pointer",
388                display: "flex",
389                alignItems: "center",
390                justifyContent: "center",
391                gap: 6,
392              }}
393            >
394              {isLast ? t("onboarding_finish") : t("onboarding_next")}
395              {!isLast && <ChevronRight size={14} />}
396            </button>
397          </div>
398        </div>
399      </div>
400    </div>
401  );
402}