your-ai-workflow-firebase-os 1.2.4 → 1.2.6

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.
@@ -212,12 +212,13 @@ function eee({ children: e }) {
212
212
  if (h.current = n?.uid || null, n) {
213
213
  console.log("[AuthContext] 1. onAuthStateChanged fired for user:", n.uid), r(n);
214
214
  try {
215
- let r = T(W, "user_profiles", n.uid);
215
+ let r = T(W, "user_profiles", n.uid), i = (await E(r)).data() || {};
216
216
  await j(r, {
217
217
  uid: n.uid,
218
218
  email: n.email,
219
- displayName: n.displayName || "",
220
- lastLoginAt: (/* @__PURE__ */ new Date()).toISOString()
219
+ displayName: n.displayName || i.displayName || "",
220
+ lastLoginAt: (/* @__PURE__ */ new Date()).toISOString(),
221
+ createdAt: i.createdAt || (/* @__PURE__ */ new Date()).toISOString()
221
222
  }, { merge: !0 }), console.log("[AuthContext] 2. Successfully synced user data into user_profiles."), e && e(), e = D(r, (e) => {
222
223
  if (e.exists()) {
223
224
  let i = e.data(), a = i.role || "user", s = "";
@@ -10110,7 +10111,7 @@ function uce({ field: e, value: t, onChange: n }) {
10110
10111
  });
10111
10112
  }
10112
10113
  function Es({ onClose: e, formId: r, formConfig: i, isInline: a }) {
10113
- let [o, s] = x({}), [c, l] = x("idle"), [u, d] = x(""), f = b(null), [p, h] = x(i || null), [g, _] = x(!i);
10114
+ let [o, s] = x({}), [c, l] = x("idle"), [u, d] = x(""), f = b(null), [p, h] = x(i || null), [g, _] = x(!i), v = Ce();
10114
10115
  m(() => {
10115
10116
  if (i) {
10116
10117
  h(i), _(!1);
@@ -10156,7 +10157,7 @@ function Es({ onClose: e, formId: r, formConfig: i, isInline: a }) {
10156
10157
  document.body.style.overflow = "unset";
10157
10158
  };
10158
10159
  }, [a]);
10159
- let v = async (t) => {
10160
+ let y = async (t) => {
10160
10161
  t.preventDefault(), l("loading"), d("");
10161
10162
  try {
10162
10163
  let t = p?.submitPage === "requests" ? "user_requests" : "user_submissions", n = Ie.currentUser ? {
@@ -10168,30 +10169,30 @@ function Es({ onClose: e, formId: r, formConfig: i, isInline: a }) {
10168
10169
  await S(C(W, t), {
10169
10170
  ...o,
10170
10171
  ...n,
10171
- formId: r || "unknown",
10172
+ formId: r || p?.systemName || p?.title || "unknown",
10172
10173
  submittedAt: A()
10173
10174
  }), l("success"), setTimeout(() => {
10174
- p?.redirectTo ? window.location.href = p.redirectTo : (e?.(), l("idle"), s({}));
10175
+ p?.redirectTo && !i && (p.redirectTo.startsWith("/") ? v(p.redirectTo) : window.location.href = p.redirectTo), e?.(), l("idle"), s({});
10175
10176
  }, 3e3);
10176
10177
  } catch (e) {
10177
10178
  console.error("Submission error:", e), l("error"), d("We could not send your message right now. Please try again.");
10178
10179
  }
10179
- }, [y, w] = x(!1);
10180
+ }, [w, ee] = x(!1);
10180
10181
  if (m(() => {
10181
10182
  let e;
10182
- return g || !p && !i ? e = setTimeout(() => w(!0), 150) : w(!1), () => clearTimeout(e);
10183
+ return g || !p && !i ? e = setTimeout(() => ee(!0), 150) : ee(!1), () => clearTimeout(e);
10183
10184
  }, [
10184
10185
  g,
10185
10186
  p,
10186
10187
  i
10187
- ]), g || !p) return y ? a ? /* @__PURE__ */ B("div", {
10188
+ ]), g || !p) return w ? a ? /* @__PURE__ */ B("div", {
10188
10189
  className: "w-full flex justify-center py-[10vh]",
10189
10190
  children: /* @__PURE__ */ B(K, { className: "w-8 h-8 animate-spin text-accent" })
10190
10191
  }) : Ee(/* @__PURE__ */ B("div", {
10191
10192
  className: "fixed inset-0 z-[100] flex items-center justify-center bg-background/60 backdrop-blur-xl",
10192
10193
  children: /* @__PURE__ */ B(K, { className: "w-8 h-8 animate-spin text-accent" })
10193
10194
  }), document.body) : null;
10194
- let ee = /* @__PURE__ */ B("div", {
10195
+ let te = /* @__PURE__ */ B("div", {
10195
10196
  className: "relative z-10 w-full",
10196
10197
  children: c === "success" ? /* @__PURE__ */ V(Y.div, {
10197
10198
  initial: {
@@ -10265,7 +10266,7 @@ function Es({ onClose: e, formId: r, formConfig: i, isInline: a }) {
10265
10266
  })]
10266
10267
  }),
10267
10268
  /* @__PURE__ */ V("form", {
10268
- onSubmit: v,
10269
+ onSubmit: y,
10269
10270
  className: "flex flex-col gap-4 sm:gap-5 w-full",
10270
10271
  children: [[...p.fields || []].sort((e, t) => {
10271
10272
  let n = e.type === "checkbox", r = t.type === "checkbox";
@@ -10418,7 +10419,7 @@ function Es({ onClose: e, formId: r, formConfig: i, isInline: a }) {
10418
10419
  y: 0
10419
10420
  },
10420
10421
  className: "w-full max-w-[500px] p-6 sm:p-8 lg:p-10 rounded-3xl md:rounded-3xl glass-panel relative glow-hover shadow-[0_8px_32px_rgba(0,0,0,0.08)] z-10 mx-auto",
10421
- children: [/* @__PURE__ */ B("div", { className: "absolute -inset-[1px] bg-gradient-to-br from-[var(--primary-glow)] to-transparent opacity-30 blur-[20px] rounded-3xl md:rounded-3xl -z-10" }), ee]
10422
+ children: [/* @__PURE__ */ B("div", { className: "absolute -inset-[1px] bg-gradient-to-br from-[var(--primary-glow)] to-transparent opacity-30 blur-[20px] rounded-3xl md:rounded-3xl -z-10" }), te]
10422
10423
  })]
10423
10424
  }) : Ee(/* @__PURE__ */ V("div", {
10424
10425
  className: "fixed inset-0 z-[100] flex items-start justify-center p-4 py-20 md:py-10 h-[-webkit-fill-available] md:h-screen w-screen overflow-y-auto no-scrollbar",
@@ -10446,7 +10447,7 @@ function Es({ onClose: e, formId: r, formConfig: i, isInline: a }) {
10446
10447
  },
10447
10448
  ref: f,
10448
10449
  className: "w-full max-w-[500px] p-6 sm:p-8 lg:p-10 rounded-3xl md:rounded-3xl glass-panel relative glow-hover shadow-[0_8px_32px_rgba(0,0,0,0.08)] z-10 mx-auto my-auto border border-[var(--panel-border)] shrink-0",
10449
- children: [/* @__PURE__ */ B("div", { className: "absolute -inset-[1px] bg-gradient-to-br from-[var(--primary-glow)] to-transparent opacity-30 blur-[20px] rounded-3xl md:rounded-3xl -z-10" }), ee]
10450
+ children: [/* @__PURE__ */ B("div", { className: "absolute -inset-[1px] bg-gradient-to-br from-[var(--primary-glow)] to-transparent opacity-30 blur-[20px] rounded-3xl md:rounded-3xl -z-10" }), te]
10450
10451
  })]
10451
10452
  }), document.body);
10452
10453
  }
@@ -78954,7 +78955,7 @@ function OVn() {
78954
78955
  })
78955
78956
  }), /* @__PURE__ */ B("p", {
78956
78957
  className: "text-[14px] md:text-[15px] text-foreground/80 leading-relaxed whitespace-pre-wrap font-medium",
78957
- children: typeof t == "boolean" ? t ? "Yes" : "No" : String(t || "No data provided")
78958
+ children: typeof t == "boolean" ? t ? "Yes" : "No" : e.toLowerCase() === "budget" && t ? `$${t}` : String(t || "No data provided")
78958
78959
  })]
78959
78960
  }, e))]
78960
78961
  })
@@ -79092,7 +79093,7 @@ function OVn() {
79092
79093
  })
79093
79094
  }), /* @__PURE__ */ B("p", {
79094
79095
  className: "text-[14px] md:text-[15px] text-foreground/80 leading-relaxed whitespace-pre-wrap font-medium",
79095
- children: typeof t == "boolean" ? t ? "Yes" : "No" : String(t || "No data provided")
79096
+ children: typeof t == "boolean" ? t ? "Yes" : "No" : e.toLowerCase() === "budget" && t ? `$${t}` : String(t || "No data provided")
79096
79097
  })]
79097
79098
  }, e)),
79098
79099
  /* @__PURE__ */ B("div", {
@@ -79239,9 +79240,14 @@ function kVn() {
79239
79240
  },
79240
79241
  transition: { delay: t * .05 },
79241
79242
  className: "glass-panel border border-[var(--panel-border)] rounded-2xl flex flex-col overflow-hidden hover:border-accent/40 transition-all duration-300",
79242
- children: [/* @__PURE__ */ V("button", {
79243
+ children: [/* @__PURE__ */ V("div", {
79244
+ role: "button",
79245
+ tabIndex: 0,
79246
+ onKeyDown: (t) => {
79247
+ (t.key === "Enter" || t.key === " ") && d(e.id);
79248
+ },
79243
79249
  onClick: () => d(e.id),
79244
- className: "w-full flex items-center justify-between p-4 md:px-6 hover:bg-foreground/[0.02] transition-colors text-left",
79250
+ className: "w-full flex items-center justify-between p-4 md:px-6 hover:bg-foreground/[0.02] transition-colors text-left cursor-pointer",
79245
79251
  children: [/* @__PURE__ */ V("div", {
79246
79252
  className: "flex items-center gap-4 flex-1 min-w-0",
79247
79253
  children: [/* @__PURE__ */ B("div", {
@@ -79362,7 +79368,7 @@ function kVn() {
79362
79368
  })
79363
79369
  }), /* @__PURE__ */ B("p", {
79364
79370
  className: "text-[14px] md:text-[15px] text-foreground/80 leading-relaxed whitespace-pre-wrap font-medium",
79365
- children: typeof t == "boolean" ? t ? "Yes" : "No" : String(t || "No data provided")
79371
+ children: typeof t == "boolean" ? t ? "Yes" : "No" : e.toLowerCase() === "budget" && t ? `$${t}` : String(t || "No data provided")
79366
79372
  })]
79367
79373
  }, e))
79368
79374
  ]
@@ -79415,9 +79421,14 @@ function kVn() {
79415
79421
  },
79416
79422
  transition: { delay: t * .05 },
79417
79423
  className: "glass-panel border border-[var(--panel-border)] rounded-2xl flex flex-col overflow-hidden opacity-50 grayscale hover:opacity-100 hover:grayscale-0 hover:border-accent/40 transition-all duration-300",
79418
- children: [/* @__PURE__ */ V("button", {
79424
+ children: [/* @__PURE__ */ V("div", {
79425
+ role: "button",
79426
+ tabIndex: 0,
79427
+ onKeyDown: (t) => {
79428
+ (t.key === "Enter" || t.key === " ") && d(e.id);
79429
+ },
79419
79430
  onClick: () => d(e.id),
79420
- className: "w-full flex items-center justify-between p-4 md:px-6 hover:bg-foreground/[0.02] transition-colors text-left",
79431
+ className: "w-full flex items-center justify-between p-4 md:px-6 hover:bg-foreground/[0.02] transition-colors text-left cursor-pointer",
79421
79432
  children: [/* @__PURE__ */ V("div", {
79422
79433
  className: "flex items-center gap-4 flex-1 min-w-0",
79423
79434
  children: [/* @__PURE__ */ B("div", {
@@ -79525,7 +79536,7 @@ function kVn() {
79525
79536
  })
79526
79537
  }), /* @__PURE__ */ B("p", {
79527
79538
  className: "text-[14px] md:text-[15px] text-foreground/80 leading-relaxed whitespace-pre-wrap font-medium",
79528
- children: typeof t == "boolean" ? t ? "Yes" : "No" : String(t || "No data provided")
79539
+ children: typeof t == "boolean" ? t ? "Yes" : "No" : e.toLowerCase() === "budget" && t ? `$${t}` : String(t || "No data provided")
79529
79540
  })]
79530
79541
  }, e)),
79531
79542
  /* @__PURE__ */ B("div", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "your-ai-workflow-firebase-os",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "description": "A complete Firebase-powered admin OS — one React component.",
5
5
  "type": "module",
6
6
  "main": "dist/your-ai-workflow-firebase-os.cjs.js",
@@ -19,6 +19,7 @@ const customizedCountries = [
19
19
  ];
20
20
 
21
21
  import { doc, getDoc } from 'firebase/firestore';
22
+ import { useNavigate } from 'react-router-dom';
22
23
 
23
24
  interface ContactPopupProps {
24
25
  onClose?: () => void;
@@ -60,6 +61,7 @@ export function ContactPopup({ onClose, formId, formConfig: propsConfig, isInlin
60
61
  const popupRef = useRef<HTMLDivElement>(null);
61
62
  const [formConfig, setFormConfig] = useState<any>(propsConfig || null);
62
63
  const [loadingConfig, setLoadingConfig] = useState(!propsConfig);
64
+ const navigate = useNavigate();
63
65
 
64
66
  useEffect(() => {
65
67
  if (propsConfig) {
@@ -159,19 +161,22 @@ export function ContactPopup({ onClose, formId, formConfig: propsConfig, isInlin
159
161
  await addDoc(collection(db, collectionName), {
160
162
  ...formData,
161
163
  ...userPayload,
162
- formId: formId || 'unknown',
164
+ formId: formId || formConfig?.systemName || formConfig?.title || 'unknown',
163
165
  submittedAt: serverTimestamp(),
164
166
  });
165
167
 
166
168
  setStatus('success');
167
169
  setTimeout(() => {
168
- if (formConfig?.redirectTo) {
169
- window.location.href = formConfig.redirectTo;
170
- } else {
171
- onClose?.();
172
- setStatus('idle');
173
- setFormData({});
170
+ if (formConfig?.redirectTo && !propsConfig) {
171
+ if (formConfig.redirectTo.startsWith('/')) {
172
+ navigate(formConfig.redirectTo);
173
+ } else {
174
+ window.location.href = formConfig.redirectTo;
175
+ }
174
176
  }
177
+ onClose?.();
178
+ setStatus('idle');
179
+ setFormData({});
175
180
  }, 3000);
176
181
  } catch (error: any) {
177
182
  console.error('Submission error:', error);
@@ -2,7 +2,7 @@ import React, { createContext, useContext, useEffect, useState } from 'react';
2
2
  import { auth, db } from './firebase';
3
3
  import { onAuthStateChanged, signOut as firebaseSignOut, updateProfile, sendEmailVerification } from 'firebase/auth';
4
4
  import type { User } from 'firebase/auth';
5
- import { doc, setDoc, onSnapshot, updateDoc } from 'firebase/firestore';
5
+ import { doc, setDoc, onSnapshot, updateDoc, getDoc } from 'firebase/firestore';
6
6
  import { useConfig } from './ConfigContext';
7
7
  interface AuthContextType {
8
8
  user: User | null;
@@ -77,11 +77,15 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
77
77
 
78
78
  try {
79
79
  const userRef = doc(db, 'user_profiles', u.uid);
80
+ const userSnap = await getDoc(userRef);
81
+ const existingData = userSnap.data() || {};
82
+
80
83
  await setDoc(userRef, {
81
84
  uid: u.uid,
82
85
  email: u.email,
83
- displayName: u.displayName || '',
84
- lastLoginAt: new Date().toISOString()
86
+ displayName: u.displayName || existingData.displayName || '',
87
+ lastLoginAt: new Date().toISOString(),
88
+ createdAt: existingData.createdAt || new Date().toISOString()
85
89
  }, { merge: true });
86
90
 
87
91
  console.log("[AuthContext] 2. Successfully synced user data into user_profiles.");
@@ -156,9 +156,12 @@ export function Requests() {
156
156
  transition={{ delay: index * 0.05 }}
157
157
  className="glass-panel border border-[var(--panel-border)] rounded-2xl flex flex-col overflow-hidden hover:border-accent/40 transition-all duration-300"
158
158
  >
159
- <button
159
+ <div
160
+ role="button"
161
+ tabIndex={0}
162
+ onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') toggleExpand(request.id); }}
160
163
  onClick={() => toggleExpand(request.id)}
161
- className="w-full flex items-center justify-between p-4 md:px-6 hover:bg-foreground/[0.02] transition-colors text-left"
164
+ className="w-full flex items-center justify-between p-4 md:px-6 hover:bg-foreground/[0.02] transition-colors text-left cursor-pointer"
162
165
  >
163
166
  <div className="flex items-center gap-4 flex-1 min-w-0">
164
167
  <div className="relative shrink-0">
@@ -213,7 +216,7 @@ export function Requests() {
213
216
  <ChevronDown className="w-4 h-4 text-foreground/50" />
214
217
  </div>
215
218
  </div>
216
- </button>
219
+ </div>
217
220
 
218
221
  <AnimatePresence>
219
222
  {isExpanded && (
@@ -248,7 +251,7 @@ export function Requests() {
248
251
  </div>
249
252
  </div>
250
253
  <p className="text-[14px] md:text-[15px] text-foreground/80 leading-relaxed whitespace-pre-wrap font-medium">
251
- {typeof val === 'boolean' ? (val ? 'Yes' : 'No') : String(val || "No data provided")}
254
+ {typeof val === 'boolean' ? (val ? 'Yes' : 'No') : (key.toLowerCase() === 'budget' && val ? `$${val}` : String(val || "No data provided"))}
252
255
  </p>
253
256
  </div>
254
257
  );
@@ -295,9 +298,12 @@ export function Requests() {
295
298
  transition={{ delay: index * 0.05 }}
296
299
  className="glass-panel border border-[var(--panel-border)] rounded-2xl flex flex-col overflow-hidden opacity-50 grayscale hover:opacity-100 hover:grayscale-0 hover:border-accent/40 transition-all duration-300"
297
300
  >
298
- <button
301
+ <div
302
+ role="button"
303
+ tabIndex={0}
304
+ onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') toggleExpand(request.id); }}
299
305
  onClick={() => toggleExpand(request.id)}
300
- className="w-full flex items-center justify-between p-4 md:px-6 hover:bg-foreground/[0.02] transition-colors text-left"
306
+ className="w-full flex items-center justify-between p-4 md:px-6 hover:bg-foreground/[0.02] transition-colors text-left cursor-pointer"
301
307
  >
302
308
  <div className="flex items-center gap-4 flex-1 min-w-0">
303
309
  <div className="relative shrink-0 grayscale">
@@ -344,7 +350,7 @@ export function Requests() {
344
350
  <ChevronDown className="w-4 h-4 text-foreground/50" />
345
351
  </div>
346
352
  </div>
347
- </button>
353
+ </div>
348
354
 
349
355
  <AnimatePresence>
350
356
  {isExpanded && (
@@ -378,7 +384,7 @@ export function Requests() {
378
384
  </div>
379
385
  </div>
380
386
  <p className="text-[14px] md:text-[15px] text-foreground/80 leading-relaxed whitespace-pre-wrap font-medium">
381
- {typeof val === 'boolean' ? (val ? 'Yes' : 'No') : String(val || "No data provided")}
387
+ {typeof val === 'boolean' ? (val ? 'Yes' : 'No') : (key.toLowerCase() === 'budget' && val ? `$${val}` : String(val || "No data provided"))}
382
388
  </p>
383
389
  </div>
384
390
  );
@@ -225,7 +225,7 @@ export function Submissions() {
225
225
  </div>
226
226
  </div>
227
227
  <p className="text-[14px] md:text-[15px] text-foreground/80 leading-relaxed whitespace-pre-wrap font-medium">
228
- {typeof val === 'boolean' ? (val ? 'Yes' : 'No') : String(val || "No data provided")}
228
+ {typeof val === 'boolean' ? (val ? 'Yes' : 'No') : (key.toLowerCase() === 'budget' && val ? `$${val}` : String(val || "No data provided"))}
229
229
  </p>
230
230
  </div>
231
231
  );
@@ -335,7 +335,7 @@ export function Submissions() {
335
335
  </div>
336
336
  </div>
337
337
  <p className="text-[14px] md:text-[15px] text-foreground/80 leading-relaxed whitespace-pre-wrap font-medium">
338
- {typeof val === 'boolean' ? (val ? 'Yes' : 'No') : String(val || "No data provided")}
338
+ {typeof val === 'boolean' ? (val ? 'Yes' : 'No') : (key.toLowerCase() === 'budget' && val ? `$${val}` : String(val || "No data provided"))}
339
339
  </p>
340
340
  </div>
341
341
  );