@retinalabsllc/zairusjs 0.2.3 → 0.2.4

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.
package/dist/index.d.mts CHANGED
@@ -556,4 +556,30 @@ interface UniversalMembersPageProps {
556
556
  }
557
557
  declare const UniversalMembersPage: React.FC<UniversalMembersPageProps>;
558
558
 
559
- export { AITranscriptionFeature, type AITranscriptionFeatureProps, AppBento2, type AppBento2Props, type BentoFeature, type BoardMember, type CompanyDetails, type DocumentSectionData, type EmailContact, Faq, type FaqItem, type FaqProps, FeatureScroll, type FeatureScrollProps, Footer, type FooterColumn, type FooterLink, type FooterProps, GifFeatureCard, type GifFeatureCardProps, Header, type HeaderLink, type HeaderProps, HeroSection, type HeroSectionProps, ManagedBoardBlock, type ManagedBoardBlockProps, ManagedContactBlock, type ManagedContactBlockProps, ManagedDocument, type ManagedDocumentProps, ManagedNewsletterSplitBlock, type ManagedNewsletterSplitBlockProps, ManagedNotFoundBlock, type ManagedNotFoundBlockProps, ManagedPricingBlock, type ManagedPricingBlockProps, ManagedProjectsBlock, type ManagedProjectsBlockProps, ManagedToaster, type NavItem, NumberInput, type NumberInputProps, PageSpinner, type PageSpinnerProps, type PlatformFeatureItem, PlatformFeatures, type PlatformFeaturesProps, PortfolioHero, type PortfolioHeroProps, type PricingFeature, type PricingPlan, ProductHero, type ProductHeroProps, type ProjectItem, type ScrollFeature, type SocialContact, type SocialLink, TextInput, type TextInputProps, ThreeDActionButton, type ThreeDActionButtonProps, ThreeDButton, type ThreeDButtonProps, UniversalHeader, type UniversalHeaderProps, UniversalIdentityPage, type UniversalIdentityPageProps, type UniversalMember, UniversalMembersPage, type UniversalMembersPageProps, UniversalOrganizationPage, type UniversalOrganizationPageProps, UniversalSidebar, type UniversalSidebarProps, type WorkspaceItem, ZairusAuth, type ZairusAuthProps };
559
+ interface ThemeColorOption {
560
+ id: string;
561
+ label: string;
562
+ bgClass: string;
563
+ borderClass: string;
564
+ }
565
+ interface UniversalProfileSettingsProps {
566
+ initialFirstName: string;
567
+ initialLastName: string;
568
+ email: string;
569
+ initialProfileColor: string;
570
+ accountStatus?: string;
571
+ memberSince?: string | Date | null;
572
+ isReadOnly?: boolean;
573
+ themeColors: ThemeColorOption[];
574
+ onSaveProfile: (payload: {
575
+ firstName: string;
576
+ lastName: string;
577
+ profileColor: string;
578
+ }) => Promise<{
579
+ success: boolean;
580
+ error?: string;
581
+ }>;
582
+ }
583
+ declare const UniversalProfileSettings: React.FC<UniversalProfileSettingsProps>;
584
+
585
+ export { AITranscriptionFeature, type AITranscriptionFeatureProps, AppBento2, type AppBento2Props, type BentoFeature, type BoardMember, type CompanyDetails, type DocumentSectionData, type EmailContact, Faq, type FaqItem, type FaqProps, FeatureScroll, type FeatureScrollProps, Footer, type FooterColumn, type FooterLink, type FooterProps, GifFeatureCard, type GifFeatureCardProps, Header, type HeaderLink, type HeaderProps, HeroSection, type HeroSectionProps, ManagedBoardBlock, type ManagedBoardBlockProps, ManagedContactBlock, type ManagedContactBlockProps, ManagedDocument, type ManagedDocumentProps, ManagedNewsletterSplitBlock, type ManagedNewsletterSplitBlockProps, ManagedNotFoundBlock, type ManagedNotFoundBlockProps, ManagedPricingBlock, type ManagedPricingBlockProps, ManagedProjectsBlock, type ManagedProjectsBlockProps, ManagedToaster, type NavItem, NumberInput, type NumberInputProps, PageSpinner, type PageSpinnerProps, type PlatformFeatureItem, PlatformFeatures, type PlatformFeaturesProps, PortfolioHero, type PortfolioHeroProps, type PricingFeature, type PricingPlan, ProductHero, type ProductHeroProps, type ProjectItem, type ScrollFeature, type SocialContact, type SocialLink, TextInput, type TextInputProps, type ThemeColorOption, ThreeDActionButton, type ThreeDActionButtonProps, ThreeDButton, type ThreeDButtonProps, UniversalHeader, type UniversalHeaderProps, UniversalIdentityPage, type UniversalIdentityPageProps, type UniversalMember, UniversalMembersPage, type UniversalMembersPageProps, UniversalOrganizationPage, type UniversalOrganizationPageProps, UniversalProfileSettings, type UniversalProfileSettingsProps, UniversalSidebar, type UniversalSidebarProps, type WorkspaceItem, ZairusAuth, type ZairusAuthProps };
package/dist/index.d.ts CHANGED
@@ -556,4 +556,30 @@ interface UniversalMembersPageProps {
556
556
  }
557
557
  declare const UniversalMembersPage: React.FC<UniversalMembersPageProps>;
558
558
 
559
- export { AITranscriptionFeature, type AITranscriptionFeatureProps, AppBento2, type AppBento2Props, type BentoFeature, type BoardMember, type CompanyDetails, type DocumentSectionData, type EmailContact, Faq, type FaqItem, type FaqProps, FeatureScroll, type FeatureScrollProps, Footer, type FooterColumn, type FooterLink, type FooterProps, GifFeatureCard, type GifFeatureCardProps, Header, type HeaderLink, type HeaderProps, HeroSection, type HeroSectionProps, ManagedBoardBlock, type ManagedBoardBlockProps, ManagedContactBlock, type ManagedContactBlockProps, ManagedDocument, type ManagedDocumentProps, ManagedNewsletterSplitBlock, type ManagedNewsletterSplitBlockProps, ManagedNotFoundBlock, type ManagedNotFoundBlockProps, ManagedPricingBlock, type ManagedPricingBlockProps, ManagedProjectsBlock, type ManagedProjectsBlockProps, ManagedToaster, type NavItem, NumberInput, type NumberInputProps, PageSpinner, type PageSpinnerProps, type PlatformFeatureItem, PlatformFeatures, type PlatformFeaturesProps, PortfolioHero, type PortfolioHeroProps, type PricingFeature, type PricingPlan, ProductHero, type ProductHeroProps, type ProjectItem, type ScrollFeature, type SocialContact, type SocialLink, TextInput, type TextInputProps, ThreeDActionButton, type ThreeDActionButtonProps, ThreeDButton, type ThreeDButtonProps, UniversalHeader, type UniversalHeaderProps, UniversalIdentityPage, type UniversalIdentityPageProps, type UniversalMember, UniversalMembersPage, type UniversalMembersPageProps, UniversalOrganizationPage, type UniversalOrganizationPageProps, UniversalSidebar, type UniversalSidebarProps, type WorkspaceItem, ZairusAuth, type ZairusAuthProps };
559
+ interface ThemeColorOption {
560
+ id: string;
561
+ label: string;
562
+ bgClass: string;
563
+ borderClass: string;
564
+ }
565
+ interface UniversalProfileSettingsProps {
566
+ initialFirstName: string;
567
+ initialLastName: string;
568
+ email: string;
569
+ initialProfileColor: string;
570
+ accountStatus?: string;
571
+ memberSince?: string | Date | null;
572
+ isReadOnly?: boolean;
573
+ themeColors: ThemeColorOption[];
574
+ onSaveProfile: (payload: {
575
+ firstName: string;
576
+ lastName: string;
577
+ profileColor: string;
578
+ }) => Promise<{
579
+ success: boolean;
580
+ error?: string;
581
+ }>;
582
+ }
583
+ declare const UniversalProfileSettings: React.FC<UniversalProfileSettingsProps>;
584
+
585
+ export { AITranscriptionFeature, type AITranscriptionFeatureProps, AppBento2, type AppBento2Props, type BentoFeature, type BoardMember, type CompanyDetails, type DocumentSectionData, type EmailContact, Faq, type FaqItem, type FaqProps, FeatureScroll, type FeatureScrollProps, Footer, type FooterColumn, type FooterLink, type FooterProps, GifFeatureCard, type GifFeatureCardProps, Header, type HeaderLink, type HeaderProps, HeroSection, type HeroSectionProps, ManagedBoardBlock, type ManagedBoardBlockProps, ManagedContactBlock, type ManagedContactBlockProps, ManagedDocument, type ManagedDocumentProps, ManagedNewsletterSplitBlock, type ManagedNewsletterSplitBlockProps, ManagedNotFoundBlock, type ManagedNotFoundBlockProps, ManagedPricingBlock, type ManagedPricingBlockProps, ManagedProjectsBlock, type ManagedProjectsBlockProps, ManagedToaster, type NavItem, NumberInput, type NumberInputProps, PageSpinner, type PageSpinnerProps, type PlatformFeatureItem, PlatformFeatures, type PlatformFeaturesProps, PortfolioHero, type PortfolioHeroProps, type PricingFeature, type PricingPlan, ProductHero, type ProductHeroProps, type ProjectItem, type ScrollFeature, type SocialContact, type SocialLink, TextInput, type TextInputProps, type ThemeColorOption, ThreeDActionButton, type ThreeDActionButtonProps, ThreeDButton, type ThreeDButtonProps, UniversalHeader, type UniversalHeaderProps, UniversalIdentityPage, type UniversalIdentityPageProps, type UniversalMember, UniversalMembersPage, type UniversalMembersPageProps, UniversalOrganizationPage, type UniversalOrganizationPageProps, UniversalProfileSettings, type UniversalProfileSettingsProps, UniversalSidebar, type UniversalSidebarProps, type WorkspaceItem, ZairusAuth, type ZairusAuthProps };
package/dist/index.js CHANGED
@@ -59,6 +59,7 @@ __export(index_exports, {
59
59
  UniversalIdentityPage: () => UniversalIdentityPage,
60
60
  UniversalMembersPage: () => UniversalMembersPage,
61
61
  UniversalOrganizationPage: () => UniversalOrganizationPage,
62
+ UniversalProfileSettings: () => UniversalProfileSettings,
62
63
  UniversalSidebar: () => UniversalSidebar,
63
64
  ZairusAuth: () => ZairusAuth
64
65
  });
@@ -2235,6 +2236,141 @@ var UniversalMembersPage = ({
2235
2236
  "Cancel"
2236
2237
  )))), memberToDelete && canManage && /* @__PURE__ */ import_react43.default.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4" }, /* @__PURE__ */ import_react43.default.createElement("div", { className: "absolute inset-0 bg-black/30", onClick: () => !isDeleting && setMemberToDelete(null) }), /* @__PURE__ */ import_react43.default.createElement("div", { className: "relative w-72 bg-white shadow-2xl rounded-2xl flex flex-col items-center overflow-hidden animate-in zoom-in-95 duration-200" }, /* @__PURE__ */ import_react43.default.createElement("div", { className: "p-6 text-center w-full" }, /* @__PURE__ */ import_react43.default.createElement("h3", { className: "text-[14px] text-black tracking-tight mb-1" }, "Remove Member"), /* @__PURE__ */ import_react43.default.createElement("p", { className: "text-[12px] text-neutral-500 leading-snug mt-2" }, "Are you sure you want to remove this member? They will lose access instantly.")), /* @__PURE__ */ import_react43.default.createElement("div", { className: "w-full flex" }, /* @__PURE__ */ import_react43.default.createElement("button", { onClick: () => setMemberToDelete(null), disabled: isDeleting, className: "flex-1 py-2 text-[13px] text-neutral-600 hover:bg-neutral-50 transition-colors disabled:opacity-50 outline-none" }, "Cancel"), /* @__PURE__ */ import_react43.default.createElement("button", { onClick: handleDelete, disabled: isDeleting, className: "flex-1 py-2 text-[13px] text-red-600 hover:bg-neutral-50 transition-colors disabled:opacity-50 flex justify-center outline-none" }, isDeleting ? /* @__PURE__ */ import_react43.default.createElement(ButtonSpinner3, null) : "Remove")))));
2237
2238
  };
2239
+
2240
+ // src/components/UniversalProfileSettings.tsx
2241
+ var import_react45 = __toESM(require("react"));
2242
+ var import_react_hot_toast6 = __toESM(require("react-hot-toast"));
2243
+ var import_react46 = require("@hugeicons/react");
2244
+ var import_core_free_icons12 = require("@hugeicons/core-free-icons");
2245
+ var UniversalProfileSettings = ({
2246
+ initialFirstName,
2247
+ initialLastName,
2248
+ email,
2249
+ initialProfileColor,
2250
+ accountStatus = "GOOD",
2251
+ memberSince,
2252
+ isReadOnly = false,
2253
+ themeColors,
2254
+ onSaveProfile
2255
+ }) => {
2256
+ const [firstName, setFirstName] = (0, import_react45.useState)(initialFirstName);
2257
+ const [lastName, setLastName] = (0, import_react45.useState)(initialLastName);
2258
+ const [profileColor, setProfileColor] = (0, import_react45.useState)(initialProfileColor);
2259
+ const [isSubmitting, setIsSubmitting] = (0, import_react45.useState)(false);
2260
+ const [isColorModalOpen, setIsColorModalOpen] = (0, import_react45.useState)(false);
2261
+ (0, import_react45.useEffect)(() => {
2262
+ setFirstName(initialFirstName || "");
2263
+ setLastName(initialLastName || "");
2264
+ setProfileColor(initialProfileColor || "NONE");
2265
+ }, [initialFirstName, initialLastName, initialProfileColor]);
2266
+ const handleFirstNameChange = (val) => {
2267
+ setFirstName(val.replace(/[^a-zA-Z\s-]/g, "").substring(0, 50));
2268
+ };
2269
+ const handleLastNameChange = (val) => {
2270
+ setLastName(val.replace(/[^a-zA-Z\s-]/g, "").substring(0, 50));
2271
+ };
2272
+ const handleSave = async (e) => {
2273
+ e.preventDefault();
2274
+ if (isSubmitting || isReadOnly) return;
2275
+ setIsSubmitting(true);
2276
+ try {
2277
+ const res = await onSaveProfile({ firstName, lastName, profileColor });
2278
+ if (res.success) {
2279
+ import_react_hot_toast6.default.success("Profile updated successfully.");
2280
+ setTimeout(() => window.location.reload(), 1e3);
2281
+ } else {
2282
+ import_react_hot_toast6.default.error(res.error || "Failed to update profile.");
2283
+ setIsSubmitting(false);
2284
+ }
2285
+ } catch (error) {
2286
+ import_react_hot_toast6.default.error("Service unavailable. Try again later.");
2287
+ setIsSubmitting(false);
2288
+ }
2289
+ };
2290
+ const hasChanges = firstName !== initialFirstName || lastName !== initialLastName || profileColor !== initialProfileColor;
2291
+ const isSaveDisabled = isSubmitting || isReadOnly || !hasChanges || firstName.trim().length === 0 || lastName.trim().length === 0;
2292
+ const selectedColorDef = themeColors.find((c) => c.id === profileColor) || themeColors[0] || { label: "Default", bgClass: "bg-neutral-100", borderClass: "border-neutral-200" };
2293
+ return /* @__PURE__ */ import_react45.default.createElement("div", { className: "flex flex-col max-w-3xl rounded-2xl p-6 bg-white gap-8 animate-in fade-in duration-300 min-h-full" }, /* @__PURE__ */ import_react45.default.createElement(ManagedToaster, null), /* @__PURE__ */ import_react45.default.createElement("div", { className: "flex flex-col sm:flex-row sm:items-start justify-between gap-3 sm:gap-4" }, /* @__PURE__ */ import_react45.default.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ import_react45.default.createElement("h1", { className: "text-xl text-black mb-1 truncate tracking-tight" }, "Personal Settings"), /* @__PURE__ */ import_react45.default.createElement("p", { className: "text-xs text-neutral-500 truncate" }, "Manage your personal account profile.")), isReadOnly && /* @__PURE__ */ import_react45.default.createElement("span", { className: "px-3 py-1 bg-neutral-50 text-neutral-500 rounded-full text-[10px] tracking-[0.2em] shrink-0 w-fit" }, "Read Only Access")), /* @__PURE__ */ import_react45.default.createElement("div", { className: "w-full max-w-2xl" }, /* @__PURE__ */ import_react45.default.createElement("form", { className: "flex flex-col gap-8", onSubmit: handleSave, autoComplete: "off" }, /* @__PURE__ */ import_react45.default.createElement("div", { className: "flex flex-col sm:flex-row gap-6" }, /* @__PURE__ */ import_react45.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ import_react45.default.createElement(
2294
+ TextInput,
2295
+ {
2296
+ label: "First Name",
2297
+ value: firstName,
2298
+ onChange: handleFirstNameChange,
2299
+ disabled: isReadOnly || isSubmitting,
2300
+ placeholder: "System"
2301
+ }
2302
+ )), /* @__PURE__ */ import_react45.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ import_react45.default.createElement(
2303
+ TextInput,
2304
+ {
2305
+ label: "Last Name",
2306
+ value: lastName,
2307
+ onChange: handleLastNameChange,
2308
+ disabled: isReadOnly || isSubmitting,
2309
+ placeholder: "Admin"
2310
+ }
2311
+ ))), /* @__PURE__ */ import_react45.default.createElement("div", { className: "space-y-2 min-w-0" }, /* @__PURE__ */ import_react45.default.createElement(
2312
+ TextInput,
2313
+ {
2314
+ label: "Email ID",
2315
+ value: email,
2316
+ onChange: () => {
2317
+ },
2318
+ disabled: true
2319
+ }
2320
+ ), /* @__PURE__ */ import_react45.default.createElement("p", { className: "text-[10px] text-neutral-400 mt-1 truncate" }, "To change your email address, please contact support.")), /* @__PURE__ */ import_react45.default.createElement("div", { className: "space-y-2 min-w-0" }, /* @__PURE__ */ import_react45.default.createElement("label", { className: "text-[10px] text-neutral-400 tracking-[0.2em] truncate block uppercase" }, "Profile Color"), /* @__PURE__ */ import_react45.default.createElement(
2321
+ "button",
2322
+ {
2323
+ type: "button",
2324
+ onClick: () => !isReadOnly && setIsColorModalOpen(true),
2325
+ disabled: isReadOnly || isSubmitting,
2326
+ className: "w-full flex items-center justify-between px-2 py-3 text-sm bg-transparent border-b border-neutral-200 text-black transition-all outline-none focus:border-black disabled:opacity-50 disabled:cursor-not-allowed text-left"
2327
+ },
2328
+ /* @__PURE__ */ import_react45.default.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ import_react45.default.createElement("div", { className: `w-4 h-4 rounded-full border ${selectedColorDef.bgClass} ${selectedColorDef.borderClass}` }), /* @__PURE__ */ import_react45.default.createElement("span", null, selectedColorDef.label)),
2329
+ /* @__PURE__ */ import_react45.default.createElement(import_react46.HugeiconsIcon, { icon: import_core_free_icons12.ArrowDown01Icon, size: 14, className: "text-neutral-400 shrink-0" })
2330
+ )), /* @__PURE__ */ import_react45.default.createElement("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between pt-8 mt-2 gap-6 sm:gap-4 border-t border-neutral-100" }, /* @__PURE__ */ import_react45.default.createElement("div", { className: "flex items-center gap-6 min-w-0" }, /* @__PURE__ */ import_react45.default.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ import_react45.default.createElement("span", { className: "text-[10px] text-neutral-400 tracking-[0.2em] block truncate uppercase" }, "Account Status"), /* @__PURE__ */ import_react45.default.createElement("span", { className: "text-xs text-black block truncate" }, accountStatus)), /* @__PURE__ */ import_react45.default.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ import_react45.default.createElement("span", { className: "text-[10px] text-neutral-400 tracking-[0.2em] block truncate uppercase" }, "Member Since"), /* @__PURE__ */ import_react45.default.createElement("span", { className: "text-xs text-black block truncate" }, memberSince ? new Date(memberSince).toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" }) : "N/A"))), /* @__PURE__ */ import_react45.default.createElement("div", { className: "flex flex-col-reverse sm:flex-row items-center gap-3 sm:gap-4 w-full sm:w-auto shrink-0" }, hasChanges && !isSubmitting && !isReadOnly && /* @__PURE__ */ import_react45.default.createElement(
2331
+ "button",
2332
+ {
2333
+ type: "button",
2334
+ onClick: () => {
2335
+ setFirstName(initialFirstName);
2336
+ setLastName(initialLastName);
2337
+ setProfileColor(initialProfileColor);
2338
+ },
2339
+ className: "text-[11px] tracking-widest text-neutral-500 hover:text-black transition-colors w-full sm:w-auto py-2 sm:py-0 outline-none"
2340
+ },
2341
+ "Cancel"
2342
+ ), /* @__PURE__ */ import_react45.default.createElement(
2343
+ ThreeDActionButton,
2344
+ {
2345
+ type: "submit",
2346
+ disabled: isSaveDisabled,
2347
+ isLoading: isSubmitting,
2348
+ className: "min-w-32 w-full sm:w-auto"
2349
+ },
2350
+ "Save Changes"
2351
+ ))))), isColorModalOpen && !isReadOnly && /* @__PURE__ */ import_react45.default.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4" }, /* @__PURE__ */ import_react45.default.createElement("div", { className: "absolute inset-0 bg-black/30", onClick: () => setIsColorModalOpen(false) }), /* @__PURE__ */ import_react45.default.createElement("div", { className: "relative w-72 bg-white shadow-2xl rounded-2xl flex flex-col items-center overflow-hidden animate-in zoom-in-95 duration-200" }, /* @__PURE__ */ import_react45.default.createElement("div", { className: "p-6 text-center w-full" }, /* @__PURE__ */ import_react45.default.createElement("h3", { className: "text-[14px] text-black tracking-tight" }, "Pick Profile Color")), /* @__PURE__ */ import_react45.default.createElement("div", { className: "w-full flex flex-col pl-2 pr-2 pb-2" }, themeColors.map((colorOption) => /* @__PURE__ */ import_react45.default.createElement(
2352
+ "button",
2353
+ {
2354
+ type: "button",
2355
+ key: colorOption.id,
2356
+ onClick: () => {
2357
+ setProfileColor(colorOption.id);
2358
+ setIsColorModalOpen(false);
2359
+ },
2360
+ className: `text-left px-4 py-3 text-[12px] tracking-wide transition-colors rounded-full flex items-center justify-between outline-none ${profileColor === colorOption.id ? "bg-neutral-100 text-black" : "text-neutral-500 hover:bg-neutral-50 hover:text-black"}`
2361
+ },
2362
+ /* @__PURE__ */ import_react45.default.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ import_react45.default.createElement("div", { className: `w-3.5 h-3.5 rounded-full border ${colorOption.bgClass} ${colorOption.borderClass}` }), /* @__PURE__ */ import_react45.default.createElement("span", { className: "truncate pr-2" }, colorOption.label)),
2363
+ profileColor === colorOption.id && /* @__PURE__ */ import_react45.default.createElement("div", { className: "w-1.5 h-1.5 rounded-full shrink-0 bg-black" })
2364
+ ))), /* @__PURE__ */ import_react45.default.createElement("div", { className: "w-full flex" }, /* @__PURE__ */ import_react45.default.createElement(
2365
+ "button",
2366
+ {
2367
+ type: "button",
2368
+ onClick: () => setIsColorModalOpen(false),
2369
+ className: "w-full py-2.5 text-[13px] text-neutral-600 hover:bg-neutral-50 transition-colors outline-none"
2370
+ },
2371
+ "Cancel"
2372
+ )))));
2373
+ };
2238
2374
  // Annotate the CommonJS export names for ESM import in node:
2239
2375
  0 && (module.exports = {
2240
2376
  AITranscriptionFeature,
@@ -2265,6 +2401,7 @@ var UniversalMembersPage = ({
2265
2401
  UniversalIdentityPage,
2266
2402
  UniversalMembersPage,
2267
2403
  UniversalOrganizationPage,
2404
+ UniversalProfileSettings,
2268
2405
  UniversalSidebar,
2269
2406
  ZairusAuth
2270
2407
  });
package/dist/index.mjs CHANGED
@@ -2184,6 +2184,141 @@ var UniversalMembersPage = ({
2184
2184
  "Cancel"
2185
2185
  )))), memberToDelete && canManage && /* @__PURE__ */ React29.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4" }, /* @__PURE__ */ React29.createElement("div", { className: "absolute inset-0 bg-black/30", onClick: () => !isDeleting && setMemberToDelete(null) }), /* @__PURE__ */ React29.createElement("div", { className: "relative w-72 bg-white shadow-2xl rounded-2xl flex flex-col items-center overflow-hidden animate-in zoom-in-95 duration-200" }, /* @__PURE__ */ React29.createElement("div", { className: "p-6 text-center w-full" }, /* @__PURE__ */ React29.createElement("h3", { className: "text-[14px] text-black tracking-tight mb-1" }, "Remove Member"), /* @__PURE__ */ React29.createElement("p", { className: "text-[12px] text-neutral-500 leading-snug mt-2" }, "Are you sure you want to remove this member? They will lose access instantly.")), /* @__PURE__ */ React29.createElement("div", { className: "w-full flex" }, /* @__PURE__ */ React29.createElement("button", { onClick: () => setMemberToDelete(null), disabled: isDeleting, className: "flex-1 py-2 text-[13px] text-neutral-600 hover:bg-neutral-50 transition-colors disabled:opacity-50 outline-none" }, "Cancel"), /* @__PURE__ */ React29.createElement("button", { onClick: handleDelete, disabled: isDeleting, className: "flex-1 py-2 text-[13px] text-red-600 hover:bg-neutral-50 transition-colors disabled:opacity-50 flex justify-center outline-none" }, isDeleting ? /* @__PURE__ */ React29.createElement(ButtonSpinner3, null) : "Remove")))));
2186
2186
  };
2187
+
2188
+ // src/components/UniversalProfileSettings.tsx
2189
+ import React30, { useState as useState14, useEffect as useEffect11 } from "react";
2190
+ import toast5 from "react-hot-toast";
2191
+ import { HugeiconsIcon as HugeiconsIcon16 } from "@hugeicons/react";
2192
+ import { ArrowDown01Icon as ArrowDown01Icon3 } from "@hugeicons/core-free-icons";
2193
+ var UniversalProfileSettings = ({
2194
+ initialFirstName,
2195
+ initialLastName,
2196
+ email,
2197
+ initialProfileColor,
2198
+ accountStatus = "GOOD",
2199
+ memberSince,
2200
+ isReadOnly = false,
2201
+ themeColors,
2202
+ onSaveProfile
2203
+ }) => {
2204
+ const [firstName, setFirstName] = useState14(initialFirstName);
2205
+ const [lastName, setLastName] = useState14(initialLastName);
2206
+ const [profileColor, setProfileColor] = useState14(initialProfileColor);
2207
+ const [isSubmitting, setIsSubmitting] = useState14(false);
2208
+ const [isColorModalOpen, setIsColorModalOpen] = useState14(false);
2209
+ useEffect11(() => {
2210
+ setFirstName(initialFirstName || "");
2211
+ setLastName(initialLastName || "");
2212
+ setProfileColor(initialProfileColor || "NONE");
2213
+ }, [initialFirstName, initialLastName, initialProfileColor]);
2214
+ const handleFirstNameChange = (val) => {
2215
+ setFirstName(val.replace(/[^a-zA-Z\s-]/g, "").substring(0, 50));
2216
+ };
2217
+ const handleLastNameChange = (val) => {
2218
+ setLastName(val.replace(/[^a-zA-Z\s-]/g, "").substring(0, 50));
2219
+ };
2220
+ const handleSave = async (e) => {
2221
+ e.preventDefault();
2222
+ if (isSubmitting || isReadOnly) return;
2223
+ setIsSubmitting(true);
2224
+ try {
2225
+ const res = await onSaveProfile({ firstName, lastName, profileColor });
2226
+ if (res.success) {
2227
+ toast5.success("Profile updated successfully.");
2228
+ setTimeout(() => window.location.reload(), 1e3);
2229
+ } else {
2230
+ toast5.error(res.error || "Failed to update profile.");
2231
+ setIsSubmitting(false);
2232
+ }
2233
+ } catch (error) {
2234
+ toast5.error("Service unavailable. Try again later.");
2235
+ setIsSubmitting(false);
2236
+ }
2237
+ };
2238
+ const hasChanges = firstName !== initialFirstName || lastName !== initialLastName || profileColor !== initialProfileColor;
2239
+ const isSaveDisabled = isSubmitting || isReadOnly || !hasChanges || firstName.trim().length === 0 || lastName.trim().length === 0;
2240
+ const selectedColorDef = themeColors.find((c) => c.id === profileColor) || themeColors[0] || { label: "Default", bgClass: "bg-neutral-100", borderClass: "border-neutral-200" };
2241
+ return /* @__PURE__ */ React30.createElement("div", { className: "flex flex-col max-w-3xl rounded-2xl p-6 bg-white gap-8 animate-in fade-in duration-300 min-h-full" }, /* @__PURE__ */ React30.createElement(ManagedToaster, null), /* @__PURE__ */ React30.createElement("div", { className: "flex flex-col sm:flex-row sm:items-start justify-between gap-3 sm:gap-4" }, /* @__PURE__ */ React30.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ React30.createElement("h1", { className: "text-xl text-black mb-1 truncate tracking-tight" }, "Personal Settings"), /* @__PURE__ */ React30.createElement("p", { className: "text-xs text-neutral-500 truncate" }, "Manage your personal account profile.")), isReadOnly && /* @__PURE__ */ React30.createElement("span", { className: "px-3 py-1 bg-neutral-50 text-neutral-500 rounded-full text-[10px] tracking-[0.2em] shrink-0 w-fit" }, "Read Only Access")), /* @__PURE__ */ React30.createElement("div", { className: "w-full max-w-2xl" }, /* @__PURE__ */ React30.createElement("form", { className: "flex flex-col gap-8", onSubmit: handleSave, autoComplete: "off" }, /* @__PURE__ */ React30.createElement("div", { className: "flex flex-col sm:flex-row gap-6" }, /* @__PURE__ */ React30.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ React30.createElement(
2242
+ TextInput,
2243
+ {
2244
+ label: "First Name",
2245
+ value: firstName,
2246
+ onChange: handleFirstNameChange,
2247
+ disabled: isReadOnly || isSubmitting,
2248
+ placeholder: "System"
2249
+ }
2250
+ )), /* @__PURE__ */ React30.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ React30.createElement(
2251
+ TextInput,
2252
+ {
2253
+ label: "Last Name",
2254
+ value: lastName,
2255
+ onChange: handleLastNameChange,
2256
+ disabled: isReadOnly || isSubmitting,
2257
+ placeholder: "Admin"
2258
+ }
2259
+ ))), /* @__PURE__ */ React30.createElement("div", { className: "space-y-2 min-w-0" }, /* @__PURE__ */ React30.createElement(
2260
+ TextInput,
2261
+ {
2262
+ label: "Email ID",
2263
+ value: email,
2264
+ onChange: () => {
2265
+ },
2266
+ disabled: true
2267
+ }
2268
+ ), /* @__PURE__ */ React30.createElement("p", { className: "text-[10px] text-neutral-400 mt-1 truncate" }, "To change your email address, please contact support.")), /* @__PURE__ */ React30.createElement("div", { className: "space-y-2 min-w-0" }, /* @__PURE__ */ React30.createElement("label", { className: "text-[10px] text-neutral-400 tracking-[0.2em] truncate block uppercase" }, "Profile Color"), /* @__PURE__ */ React30.createElement(
2269
+ "button",
2270
+ {
2271
+ type: "button",
2272
+ onClick: () => !isReadOnly && setIsColorModalOpen(true),
2273
+ disabled: isReadOnly || isSubmitting,
2274
+ className: "w-full flex items-center justify-between px-2 py-3 text-sm bg-transparent border-b border-neutral-200 text-black transition-all outline-none focus:border-black disabled:opacity-50 disabled:cursor-not-allowed text-left"
2275
+ },
2276
+ /* @__PURE__ */ React30.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ React30.createElement("div", { className: `w-4 h-4 rounded-full border ${selectedColorDef.bgClass} ${selectedColorDef.borderClass}` }), /* @__PURE__ */ React30.createElement("span", null, selectedColorDef.label)),
2277
+ /* @__PURE__ */ React30.createElement(HugeiconsIcon16, { icon: ArrowDown01Icon3, size: 14, className: "text-neutral-400 shrink-0" })
2278
+ )), /* @__PURE__ */ React30.createElement("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between pt-8 mt-2 gap-6 sm:gap-4 border-t border-neutral-100" }, /* @__PURE__ */ React30.createElement("div", { className: "flex items-center gap-6 min-w-0" }, /* @__PURE__ */ React30.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ React30.createElement("span", { className: "text-[10px] text-neutral-400 tracking-[0.2em] block truncate uppercase" }, "Account Status"), /* @__PURE__ */ React30.createElement("span", { className: "text-xs text-black block truncate" }, accountStatus)), /* @__PURE__ */ React30.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ React30.createElement("span", { className: "text-[10px] text-neutral-400 tracking-[0.2em] block truncate uppercase" }, "Member Since"), /* @__PURE__ */ React30.createElement("span", { className: "text-xs text-black block truncate" }, memberSince ? new Date(memberSince).toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" }) : "N/A"))), /* @__PURE__ */ React30.createElement("div", { className: "flex flex-col-reverse sm:flex-row items-center gap-3 sm:gap-4 w-full sm:w-auto shrink-0" }, hasChanges && !isSubmitting && !isReadOnly && /* @__PURE__ */ React30.createElement(
2279
+ "button",
2280
+ {
2281
+ type: "button",
2282
+ onClick: () => {
2283
+ setFirstName(initialFirstName);
2284
+ setLastName(initialLastName);
2285
+ setProfileColor(initialProfileColor);
2286
+ },
2287
+ className: "text-[11px] tracking-widest text-neutral-500 hover:text-black transition-colors w-full sm:w-auto py-2 sm:py-0 outline-none"
2288
+ },
2289
+ "Cancel"
2290
+ ), /* @__PURE__ */ React30.createElement(
2291
+ ThreeDActionButton,
2292
+ {
2293
+ type: "submit",
2294
+ disabled: isSaveDisabled,
2295
+ isLoading: isSubmitting,
2296
+ className: "min-w-32 w-full sm:w-auto"
2297
+ },
2298
+ "Save Changes"
2299
+ ))))), isColorModalOpen && !isReadOnly && /* @__PURE__ */ React30.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4" }, /* @__PURE__ */ React30.createElement("div", { className: "absolute inset-0 bg-black/30", onClick: () => setIsColorModalOpen(false) }), /* @__PURE__ */ React30.createElement("div", { className: "relative w-72 bg-white shadow-2xl rounded-2xl flex flex-col items-center overflow-hidden animate-in zoom-in-95 duration-200" }, /* @__PURE__ */ React30.createElement("div", { className: "p-6 text-center w-full" }, /* @__PURE__ */ React30.createElement("h3", { className: "text-[14px] text-black tracking-tight" }, "Pick Profile Color")), /* @__PURE__ */ React30.createElement("div", { className: "w-full flex flex-col pl-2 pr-2 pb-2" }, themeColors.map((colorOption) => /* @__PURE__ */ React30.createElement(
2300
+ "button",
2301
+ {
2302
+ type: "button",
2303
+ key: colorOption.id,
2304
+ onClick: () => {
2305
+ setProfileColor(colorOption.id);
2306
+ setIsColorModalOpen(false);
2307
+ },
2308
+ className: `text-left px-4 py-3 text-[12px] tracking-wide transition-colors rounded-full flex items-center justify-between outline-none ${profileColor === colorOption.id ? "bg-neutral-100 text-black" : "text-neutral-500 hover:bg-neutral-50 hover:text-black"}`
2309
+ },
2310
+ /* @__PURE__ */ React30.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ React30.createElement("div", { className: `w-3.5 h-3.5 rounded-full border ${colorOption.bgClass} ${colorOption.borderClass}` }), /* @__PURE__ */ React30.createElement("span", { className: "truncate pr-2" }, colorOption.label)),
2311
+ profileColor === colorOption.id && /* @__PURE__ */ React30.createElement("div", { className: "w-1.5 h-1.5 rounded-full shrink-0 bg-black" })
2312
+ ))), /* @__PURE__ */ React30.createElement("div", { className: "w-full flex" }, /* @__PURE__ */ React30.createElement(
2313
+ "button",
2314
+ {
2315
+ type: "button",
2316
+ onClick: () => setIsColorModalOpen(false),
2317
+ className: "w-full py-2.5 text-[13px] text-neutral-600 hover:bg-neutral-50 transition-colors outline-none"
2318
+ },
2319
+ "Cancel"
2320
+ )))));
2321
+ };
2187
2322
  export {
2188
2323
  AITranscriptionFeature,
2189
2324
  AppBento2,
@@ -2213,6 +2348,7 @@ export {
2213
2348
  UniversalIdentityPage,
2214
2349
  UniversalMembersPage,
2215
2350
  UniversalOrganizationPage,
2351
+ UniversalProfileSettings,
2216
2352
  UniversalSidebar,
2217
2353
  ZairusAuth
2218
2354
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retinalabsllc/zairusjs",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "A perceptive, Ai data driven Next.js UI component library.",
5
5
  "author": "Retina Labs Company",
6
6
  "license": "MIT",