@myrjfa/ui 2.0.1 → 2.1.1

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.
Files changed (67) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +2 -2
  3. package/dist/chat/ChatMain.d.ts +3 -1
  4. package/dist/chat/ChatMain.d.ts.map +1 -1
  5. package/dist/chat/ChatMain.js +2 -1
  6. package/dist/chat/MessageBubble.js +4 -4
  7. package/dist/chat/MessageInput.d.ts +1 -1
  8. package/dist/chat/MessageInput.d.ts.map +1 -1
  9. package/dist/chat/components/ParticipantSelector.d.ts +1 -1
  10. package/dist/chat/components/ParticipantSelector.d.ts.map +1 -1
  11. package/dist/dashboard/app-sidebar.js +3 -3
  12. package/dist/dashboard/data-table.d.ts +2 -1
  13. package/dist/dashboard/data-table.d.ts.map +1 -1
  14. package/dist/dashboard/data-table.js +3 -3
  15. package/dist/index.d.ts +6 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +7 -1
  18. package/dist/main/navbar.js +5 -5
  19. package/dist/main/review-page.d.ts +1 -1
  20. package/dist/main/review-page.d.ts.map +1 -1
  21. package/dist/main/review-page.js +49 -9
  22. package/dist/misc/alertdialogclaude.d.ts.map +1 -1
  23. package/dist/misc/alertdialogclaude.js +1 -1
  24. package/dist/misc/command.js +1 -1
  25. package/dist/misc/dashboard/action-buttons.js +31 -0
  26. package/dist/misc/document-upload-button.d.ts +12 -0
  27. package/dist/misc/document-upload-button.d.ts.map +1 -0
  28. package/dist/misc/document-upload-button.js +27 -0
  29. package/dist/misc/empty-state.d.ts +10 -0
  30. package/dist/misc/empty-state.d.ts.map +1 -0
  31. package/dist/misc/empty-state.js +5 -0
  32. package/dist/misc/filter.d.ts.map +1 -1
  33. package/dist/misc/filter.js +1 -1
  34. package/dist/misc/image-compressor.d.ts +29 -0
  35. package/dist/misc/image-compressor.d.ts.map +1 -0
  36. package/dist/misc/image-compressor.js +70 -0
  37. package/dist/misc/image-cropper.d.ts +10 -0
  38. package/dist/misc/image-cropper.d.ts.map +1 -0
  39. package/dist/misc/image-cropper.js +44 -0
  40. package/dist/misc/input.d.ts.map +1 -1
  41. package/dist/misc/input.js +1 -1
  42. package/dist/misc/misc/alertdialogclaude.js +221 -0
  43. package/dist/misc/misc/button.js +46 -0
  44. package/dist/misc/misc/dropdown-menu.js +136 -0
  45. package/dist/misc/multiImageUploader.d.ts +2 -1
  46. package/dist/misc/multiImageUploader.d.ts.map +1 -1
  47. package/dist/misc/multiImageUploader.js +26 -2
  48. package/dist/misc/newsLetter.js +1 -1
  49. package/dist/misc/notification.js +2 -2
  50. package/dist/misc/popover.d.ts.map +1 -1
  51. package/dist/misc/popover.js +1 -1
  52. package/dist/misc/pwa-install-button.d.ts +9 -0
  53. package/dist/misc/pwa-install-button.d.ts.map +1 -0
  54. package/dist/misc/pwa-install-button.js +158 -0
  55. package/dist/misc/select.d.ts.map +1 -1
  56. package/dist/misc/select.js +3 -3
  57. package/dist/misc/skeleton.d.ts +36 -1
  58. package/dist/misc/skeleton.d.ts.map +1 -1
  59. package/dist/misc/skeleton.js +40 -3
  60. package/dist/misc/tile.js +3 -3
  61. package/dist/misc/whatsapp-help.d.ts +9 -0
  62. package/dist/misc/whatsapp-help.d.ts.map +1 -0
  63. package/dist/misc/whatsapp-help.js +13 -0
  64. package/dist/profile/socialLink.d.ts +1 -1
  65. package/dist/profile/socialLink.d.ts.map +1 -1
  66. package/dist/profile/socialLink.js +49 -19
  67. package/package.json +5 -4
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,0BAA0B,CAAC;AACzC,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACpG,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,0BAA0B,CAAC;AACzC,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACpG,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AAGrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- // Export all your shared UI components
2
1
  export * from './misc/button';
2
+ export * from './misc/empty-state';
3
3
  export * from './misc/accordion';
4
4
  export * from './misc/alert';
5
5
  export * from './misc/alertdialogclaude';
@@ -57,3 +57,9 @@ export * from './main/footer';
57
57
  export * from './main/navbar';
58
58
  export * from './main/paginationBar';
59
59
  export * from './main/review-page';
60
+ export * from './misc/image-cropper';
61
+ // New components — features #9, #10, #21, #26
62
+ export * from './misc/pwa-install-button';
63
+ export * from './misc/whatsapp-help';
64
+ export * from './misc/image-compressor';
65
+ export * from './misc/skeleton';
@@ -2,11 +2,11 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Popover, PopoverContent, PopoverTrigger } from "@radix-ui/react-popover";
4
4
  import { Separator } from "@radix-ui/react-separator";
5
- import { logoutUser } from "@myrjfa/state";
6
- import { isLoggedInAtom, userAtom, userLoadingAtom } from "@myrjfa/state";
7
- import { opportunityTypeOptions } from "@myrjfa/state";
5
+ import { logoutUser } from "@myrjfa/state/dist/lib/actions/auth";
6
+ import { isLoggedInAtom, userAtom, userLoadingAtom } from "@myrjfa/state/dist/lib/userAtom";
7
+ import { opportunityTypeOptions } from "@myrjfa/state/dist/lib/models/opportunities/opportunity";
8
8
  import { useAtom, useAtomValue } from "jotai";
9
- import { ChevronDown, Globe, Heart, LayoutDashboardIcon, Store, Target, Luggage, MessageCircle, Compass, Mountain, Users, Sparkles, BedDouble, Ticket, Car } from "lucide-react";
9
+ import { ChevronDown, Globe, Heart, LayoutDashboardIcon, Store, Target, Luggage, Compass, Mountain, Users, Sparkles, BedDouble, Ticket, Car } from "lucide-react";
10
10
  import Link from "next/link";
11
11
  import { useRouter, usePathname } from "next/navigation";
12
12
  import { useEffect, useState } from "react";
@@ -66,7 +66,7 @@ export function Navbar({ dark = false }) {
66
66
  const navItemColor = effectiveDark
67
67
  ? "text-white/90 hover:text-white"
68
68
  : "text-muted-foreground hover:text-foreground";
69
- return (_jsx("header", { className: `fixed top-0 left-0 z-[100] mx-auto transition-all duration-300 w-full ${navbarBg} ${textColor} ${navbarBorder}`, children: _jsxs("div", { className: "mx-auto flex items-center justify-between gap-10 py-4 px-4 lg:px-8", children: [_jsxs(Link, { href: "/", className: "flex items-center gap-3", children: [_jsxs(Avatar, { className: "ml-2 -mr-4.5", children: [_jsx(AvatarImage, { src: "/images/logoicon.webp" }), _jsxs(AvatarFallback, { children: [(currentUser === null || currentUser === void 0 ? void 0 : currentUser.firstName.charAt(0)) || "D", (currentUser === null || currentUser === void 0 ? void 0 : currentUser.lastName.charAt(0)) || "P"] })] }), _jsx("span", { className: "font-heading text-xl font-bold", children: "rippeaze" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("nav", { className: "hidden md:flex items-center gap-10 justify-end", children: [_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { className: `flex items-center gap-1 text-sm font-medium cursor-pointer ${navItemColor}`, children: [_jsx(Target, { className: "h-5 w-5" }), _jsx("span", { children: "Opportunities" }), _jsx(ChevronDown, { className: "h-4 w-4" })] }) }), _jsx(PopoverContent, { className: "w-56 p-2 mt-3 bg-white rounded-lg shadow-lg border", align: "start", sideOffset: 5, children: _jsx("div", { className: "flex flex-col", children: opportunityTypeOptions.map((opt) => (_jsxs(Link, { href: `/opportunities?type=${opt.value}`, className: "px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-md flex flex-col", children: [_jsx("span", { className: "font-medium", children: opt.label }), _jsx("span", { className: "text-xs text-gray-500", children: opt.description })] }, opt.value))) }) })] }), _jsx(NavItem, { icon: _jsx(Luggage, { className: "h-5 w-5" }), label: "Packages", href: "/packages", className: navItemColor }), _jsx(NavItem, { icon: _jsx(Globe, { className: "h-5 w-5" }), label: "Blogs", href: "/blogs", className: navItemColor }), _jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { className: `flex items-center gap-1 text-sm font-medium cursor-pointer ${navItemColor}`, children: [_jsx(Compass, { className: "h-5 w-5" }), _jsx("span", { children: "Explore" }), _jsx(ChevronDown, { className: "h-4 w-4" })] }) }), _jsx(PopoverContent, { className: "w-64 p-2 mt-3 bg-white rounded-xl shadow-xl border", align: "start", sideOffset: 5, children: _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("p", { className: "text-[10px] font-black uppercase tracking-widest text-gray-400 px-3 pt-1 pb-0.5", children: "Travel" }), _jsxs(Link, { href: "/stays", className: "px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg flex items-center gap-3", children: [_jsx(BedDouble, { className: "h-4 w-4 text-primary flex-shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold", children: "Stays" }), _jsx("p", { className: "text-xs text-gray-400", children: "Hotels, hostels & homestays" })] })] }), _jsxs(Link, { href: "/events", className: "px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg flex items-center gap-3", children: [_jsx(Ticket, { className: "h-4 w-4 text-primary flex-shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold", children: "Events" }), _jsx("p", { className: "text-xs text-gray-400", children: "Concerts, workshops & more" })] })] }), _jsxs(Link, { href: "/adventures", className: "px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg flex items-center gap-3", children: [_jsx(Mountain, { className: "h-4 w-4 text-primary flex-shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold", children: "Adventures" }), _jsx("p", { className: "text-xs text-gray-400", children: "Tours & thrilling activities" })] })] }), _jsxs(Link, { href: "/rentals", className: "px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg flex items-center gap-3", children: [_jsx(Car, { className: "h-4 w-4 text-primary flex-shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold", children: "Rentals" }), _jsx("p", { className: "text-xs text-gray-400", children: "Bikes, cars & vehicles" })] })] }), _jsx("p", { className: "text-[10px] font-black uppercase tracking-widest text-gray-400 px-3 pt-2 pb-0.5", children: "For You" }), _jsxs(Link, { href: "/find-companion", className: "px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg flex items-center gap-3", children: [_jsx(Users, { className: "h-4 w-4 text-primary flex-shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold", children: "Find Companions" }), _jsx("p", { className: "text-xs text-gray-400", children: "Connect with travel buddies" })] })] }), _jsxs(Link, { href: "/plan", className: "px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg flex items-center gap-3", children: [_jsx(Sparkles, { className: "h-4 w-4 text-primary flex-shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold", children: "Plan a Trip" }), _jsx("p", { className: "text-xs text-gray-400", children: "AI-powered itinerary builder" })] })] })] }) })] }), isLoggedIn && _jsx(NavItem, { icon: _jsx(MessageCircle, { className: "h-5 w-5" }), label: "Chat", href: "/chat", className: navItemColor, external: true }), currentUser ? _jsx(NavItem, { icon: _jsx(Store, { className: "h-5 w-5" }), label: "Become a Partner", href: "/contact", className: navItemColor })
69
+ return (_jsx("header", { className: `fixed top-0 left-0 z-[100] mx-auto transition-all duration-300 w-full ${navbarBg} ${textColor} ${navbarBorder}`, children: _jsxs("div", { className: "mx-auto flex items-center justify-between gap-10 py-4 px-4 lg:px-8", children: [_jsxs(Link, { href: "/", className: "flex items-center gap-3", children: [_jsxs(Avatar, { className: "ml-2 -mr-4.5", children: [_jsx(AvatarImage, { src: "/images/logoicon.webp" }), _jsxs(AvatarFallback, { children: [(currentUser === null || currentUser === void 0 ? void 0 : currentUser.firstName.charAt(0)) || "D", (currentUser === null || currentUser === void 0 ? void 0 : currentUser.lastName.charAt(0)) || "P"] })] }), _jsx("span", { className: "font-heading text-xl font-bold", children: "rippeaze" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("nav", { className: "hidden md:flex items-center gap-10 justify-end", children: [_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { className: `flex items-center gap-1 text-sm font-medium cursor-pointer ${navItemColor}`, children: [_jsx(Target, { className: "h-5 w-5" }), _jsx("span", { children: "Opportunities" }), _jsx(ChevronDown, { className: "h-4 w-4" })] }) }), _jsx(PopoverContent, { className: "w-56 p-2 mt-3 bg-white rounded-lg shadow-lg border", align: "start", sideOffset: 5, children: _jsx("div", { className: "flex flex-col", children: opportunityTypeOptions.map((opt) => (_jsxs(Link, { href: `/opportunities?type=${opt.value}`, className: "px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-md flex flex-col", children: [_jsx("span", { className: "font-medium", children: opt.label }), _jsx("span", { className: "text-xs text-gray-500", children: opt.description })] }, opt.value))) }) })] }), _jsx(NavItem, { icon: _jsx(Luggage, { className: "h-5 w-5" }), label: "Packages", href: "/packages", className: navItemColor }), _jsx(NavItem, { icon: _jsx(Globe, { className: "h-5 w-5" }), label: "Blogs", href: "/blogs", className: navItemColor }), _jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { className: `flex items-center gap-1 text-sm font-medium cursor-pointer ${navItemColor}`, children: [_jsx(Compass, { className: "h-5 w-5" }), _jsx("span", { children: "Explore" }), _jsx(ChevronDown, { className: "h-4 w-4" })] }) }), _jsx(PopoverContent, { className: "w-64 p-2 mt-3 bg-white rounded-xl shadow-xl border", align: "start", sideOffset: 5, children: _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("p", { className: "text-[10px] font-black uppercase tracking-widest text-gray-400 px-3 pt-1 pb-0.5", children: "Travel" }), _jsxs(Link, { href: "/stays", className: "px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg flex items-center gap-3", children: [_jsx(BedDouble, { className: "h-4 w-4 text-primary flex-shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold", children: "Stays" }), _jsx("p", { className: "text-xs text-gray-400", children: "Hotels, hostels & homestays" })] })] }), _jsxs(Link, { href: "/events", className: "px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg flex items-center gap-3", children: [_jsx(Ticket, { className: "h-4 w-4 text-primary flex-shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold", children: "Events" }), _jsx("p", { className: "text-xs text-gray-400", children: "Concerts, workshops & more" })] })] }), _jsxs(Link, { href: "/adventures", className: "px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg flex items-center gap-3", children: [_jsx(Mountain, { className: "h-4 w-4 text-primary flex-shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold", children: "Adventures" }), _jsx("p", { className: "text-xs text-gray-400", children: "Tours & thrilling activities" })] })] }), _jsxs(Link, { href: "/rentals", className: "px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg flex items-center gap-3", children: [_jsx(Car, { className: "h-4 w-4 text-primary flex-shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold", children: "Rentals" }), _jsx("p", { className: "text-xs text-gray-400", children: "Bikes, cars & vehicles" })] })] }), _jsx("p", { className: "text-[10px] font-black uppercase tracking-widest text-gray-400 px-3 pt-2 pb-0.5", children: "For You" }), _jsxs(Link, { href: "/find-companion", className: "px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg flex items-center gap-3", children: [_jsx(Users, { className: "h-4 w-4 text-primary flex-shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold", children: "Find Companions" }), _jsx("p", { className: "text-xs text-gray-400", children: "Connect with travel buddies" })] })] }), _jsxs(Link, { href: "/plan", className: "px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-lg flex items-center gap-3", children: [_jsx(Sparkles, { className: "h-4 w-4 text-primary flex-shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold", children: "Plan a Trip" }), _jsx("p", { className: "text-xs text-gray-400", children: "AI-powered itinerary builder" })] })] })] }) })] }), currentUser ? _jsx(NavItem, { icon: _jsx(Store, { className: "h-5 w-5" }), label: "Become a Partner", href: "/contact", className: navItemColor })
70
70
  : _jsx(NavItem, { icon: _jsx(Store, { className: "h-5 w-5" }), label: "Register as Business", href: "/auth/register?role=host", className: navItemColor }), isLoggedIn && _jsx(NotificationBell, { navItemColor: navItemColor })] }), _jsx("div", { className: "hidden md:flex items-center gap-2", children: _jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "link", className: "flex w-full gap-1 cursor-pointer", children: _jsxs(Avatar, { className: "ml-5 mr-4.5", children: [_jsx(AvatarImage, { src: (_a = currentUser === null || currentUser === void 0 ? void 0 : currentUser.profilePic) !== null && _a !== void 0 ? _a : "/images/profile_placeholder.webp" }), _jsxs(AvatarFallback, { children: [(currentUser === null || currentUser === void 0 ? void 0 : currentUser.firstName.charAt(0)) || "D", (currentUser === null || currentUser === void 0 ? void 0 : currentUser.lastName.charAt(0)) || "P"] })] }) }) }), _jsx(PopoverContent, { className: `w-full p-0 mt-3 bg-${dark ? "primary" : "white"} rounded-lg shadow-lg`, align: "end", sideOffset: 5, children: _jsxs("div", { className: "py-2 w-full", children: [_jsxs("div", { className: "px-4 py-3 border-b w-full", children: [_jsx("p", { className: "text-sm font-medium", children: (currentUser === null || currentUser === void 0 ? void 0 : currentUser.username) || "Guest" }), _jsx("p", { className: "text-xs text-gray-500", children: (currentUser === null || currentUser === void 0 ? void 0 : currentUser.email) || "user@example.com" })] }), _jsxs("div", { className: "flex flex-col", children: [isLoggedIn ?
71
71
  _jsxs(Link, { href: `/profile/${(currentUser === null || currentUser === void 0 ? void 0 : currentUser.role) || "user"}/${(currentUser === null || currentUser === void 0 ? void 0 : currentUser.username) || "Guest"}`, className: "w-full py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 flex items-center gap-2", children: [_jsxs(Avatar, { className: "w-4 h-4", children: [_jsx(AvatarImage, { src: (_b = currentUser === null || currentUser === void 0 ? void 0 : currentUser.profilePic) !== null && _b !== void 0 ? _b : "/images/profile_placeholder.webp" }), _jsx(AvatarFallback, { children: "U" })] }), "Profile"] }) :
72
72
  _jsxs(Button, { variant: "ghost", onClick: () => router.push('/auth/login?role=user'), className: "w-full py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 flex items-center gap-2 justify-start", children: [_jsxs(Avatar, { className: "w-4 h-4", children: [_jsx(AvatarImage, { src: "/images/profile_placeholder.webp" }), _jsx(AvatarFallback, { children: "U" })] }), "Login As Volunteer"] }), isLoggedIn && _jsxs(Link, { href: (currentUser === null || currentUser === void 0 ? void 0 : currentUser.role) === 'host' || (currentUser === null || currentUser === void 0 ? void 0 : currentUser.role) === 'admin' ? `/dashboard/host/overview` : `/overview/${(currentUser === null || currentUser === void 0 ? void 0 : currentUser.role) || 'user'}`, className: "w-full py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 flex items-center gap-2", children: [_jsx(LayoutDashboardIcon, { className: "h-4 w-4" }), "Dashboard"] }), isLoggedIn && ((currentUser === null || currentUser === void 0 ? void 0 : currentUser.role) === "user" || (currentUser === null || currentUser === void 0 ? void 0 : currentUser.role) == null) &&
@@ -1,4 +1,4 @@
1
- import { Review, reviewTargetType } from "@myrjfa/state";
1
+ import { Review, reviewTargetType } from "@myrjfa/state/dist/lib/models/review";
2
2
  interface ReviewPageProps {
3
3
  title?: string;
4
4
  subtitle?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"review-page.d.ts","sourceRoot":"","sources":["../../src/main/review-page.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAqB,gBAAgB,EAAc,MAAM,eAAe,CAAC;AAoDxF,UAAU,eAAe;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CACzC;AAED,wBAAgB,UAAU,CAAC,EACvB,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,UAA0B,EAC1B,QAAgB,EAChB,cAAmB,EACnB,cAAyB,GAC5B,EAAE,eAAe,2CAsNjB"}
1
+ {"version":3,"file":"review-page.d.ts","sourceRoot":"","sources":["../../src/main/review-page.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAqB,gBAAgB,EAAc,MAAM,sCAAsC,CAAC;AAoD/G,UAAU,eAAe;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CACzC;AAED,wBAAgB,UAAU,CAAC,EACvB,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,UAA0B,EAC1B,QAAgB,EAChB,cAAmB,EACnB,cAAyB,GAC5B,EAAE,eAAe,2CAwQjB"}
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { zodResolver } from "@hookform/resolvers/zod";
4
- import { addReview, deleteReview, editReview, getReviewsById } from "@myrjfa/state";
5
- import { reviewBasicSchema } from "@myrjfa/state";
6
- import { userAtom, userLoadingAtom } from "@myrjfa/state";
7
- import { formatDate } from "@myrjfa/state";
4
+ import { addReview, deleteReview, editReview, getReviewsById } from "@myrjfa/state/dist/lib/actions/actions";
5
+ import { reviewBasicSchema } from "@myrjfa/state/dist/lib/models/review";
6
+ import { userAtom, userLoadingAtom } from "@myrjfa/state/dist/lib/userAtom";
7
+ import { formatDate } from "@myrjfa/state/dist/lib/utils";
8
8
  import { useAtomValue } from "jotai";
9
9
  import { StarIcon } from "lucide-react";
10
10
  import { useEffect, useState } from "react";
@@ -23,13 +23,17 @@ export function ReviewPage({ title, subtitle, targetId, targetType = "opportunit
23
23
  var _a;
24
24
  const user = useAtomValue(userAtom);
25
25
  const loading = useAtomValue(userLoadingAtom);
26
- const [review, setReview] = useState((_a = initialReviews.find((r) => r.reviewerUsername === (user === null || user === void 0 ? void 0 : user.username))) !== null && _a !== void 0 ? _a : null);
26
+ const [review, setReview] = useState(Array.isArray(initialReviews) ? ((_a = initialReviews.find((r) => r.reviewerUsername === (user === null || user === void 0 ? void 0 : user.username))) !== null && _a !== void 0 ? _a : null) : null);
27
27
  const [reviews, setReviews] = useState(initialReviews);
28
28
  const [displayReviews, setDisplayReviews] = useState([]);
29
+ const [page, setPage] = useState(1);
30
+ const [hasMore, setHasMore] = useState(false);
31
+ const [totalCount, setTotalCount] = useState(Array.isArray(initialReviews) ? initialReviews.length : 0);
29
32
  const [hoveredRating, setHoveredRating] = useState(null);
30
33
  const [isSubmitting, setIsSubmitting] = useState(false);
31
34
  const [isDeleting, setIsDeleting] = useState(false);
32
35
  const [isFormInitialized, setIsFormInitialized] = useState(false);
36
+ const [isLoadingMore, setIsLoadingMore] = useState(false);
33
37
  const form = useForm({
34
38
  resolver: zodResolver(reviewBasicSchema),
35
39
  defaultValues: {
@@ -42,17 +46,25 @@ export function ReviewPage({ title, subtitle, targetId, targetType = "opportunit
42
46
  if (loading)
43
47
  return;
44
48
  const fetchData = async () => {
45
- const response = await getReviewsById(targetId, targetType);
49
+ // Cast to any to bypass stale type definitions in @myrjfa/state/dist
50
+ const response = await getReviewsById(targetId, targetType, { page: 1, limit: 10 });
46
51
  if (response === null || response === void 0 ? void 0 : response.error) {
47
52
  console.error("Error: " + response.error);
48
53
  }
49
- else {
54
+ else if (Array.isArray(response.reviews)) {
50
55
  setReviews(response.reviews);
56
+ setTotalCount(response.totalCount);
57
+ setHasMore(response.hasMore);
58
+ setPage(1);
51
59
  const myReview = response.reviews.find((r) => r.reviewerUsername === (user === null || user === void 0 ? void 0 : user.username));
52
60
  setReview(myReview !== null && myReview !== void 0 ? myReview : null);
53
61
  form.reset({ rating: reviewCategory === "comment" ? 1 : ((myReview === null || myReview === void 0 ? void 0 : myReview.rating) || 0), comment: (myReview === null || myReview === void 0 ? void 0 : myReview.comment) || "" });
54
62
  setIsFormInitialized(true);
55
63
  }
64
+ else {
65
+ setReviews([]);
66
+ setIsFormInitialized(true);
67
+ }
56
68
  };
57
69
  if (!initialReviews || initialReviews.length === 0) {
58
70
  fetchData();
@@ -61,6 +73,27 @@ export function ReviewPage({ title, subtitle, targetId, targetType = "opportunit
61
73
  setIsFormInitialized(true); // Initialize immediately if already present
62
74
  }
63
75
  }, [targetId, targetType, user, loading]);
76
+ const handleLoadMore = async () => {
77
+ if (isLoadingMore || !hasMore)
78
+ return;
79
+ setIsLoadingMore(true);
80
+ try {
81
+ const nextPage = page + 1;
82
+ // Cast to any to bypass stale type definitions in @myrjfa/state/dist
83
+ const response = await getReviewsById(targetId, targetType, { page: nextPage, limit: 10 });
84
+ if (response === null || response === void 0 ? void 0 : response.error) {
85
+ console.error("Error: " + response.error);
86
+ }
87
+ else if (Array.isArray(response.reviews)) {
88
+ setReviews([...reviews, ...response.reviews]);
89
+ setPage(nextPage);
90
+ setHasMore(response.hasMore);
91
+ }
92
+ }
93
+ finally {
94
+ setIsLoadingMore(false);
95
+ }
96
+ };
64
97
  useEffect(() => {
65
98
  if (review) {
66
99
  form.reset({
@@ -71,7 +104,12 @@ export function ReviewPage({ title, subtitle, targetId, targetType = "opportunit
71
104
  setIsFormInitialized(true);
72
105
  }, [review]);
73
106
  useEffect(() => {
74
- setDisplayReviews(reviews.filter((r) => r.comment));
107
+ if (Array.isArray(reviews)) {
108
+ setDisplayReviews(reviews.filter((r) => r.comment));
109
+ }
110
+ else {
111
+ setDisplayReviews([]);
112
+ }
75
113
  }, [reviews]);
76
114
  const onSubmit = async (data) => {
77
115
  setIsSubmitting(true);
@@ -91,6 +129,7 @@ export function ReviewPage({ title, subtitle, targetId, targetType = "opportunit
91
129
  if (newReview) {
92
130
  setReviews([newReview, ...reviews.filter((r) => r._id !== newReview._id)]);
93
131
  setReview(newReview);
132
+ setTotalCount(prev => review ? prev : prev + 1);
94
133
  form.reset({ rating: reviewCategory === "comment" ? 1 : newReview.rating, comment: newReview.comment || "" });
95
134
  }
96
135
  }
@@ -121,6 +160,7 @@ export function ReviewPage({ title, subtitle, targetId, targetType = "opportunit
121
160
  else {
122
161
  setReviews(reviews.filter((r) => r._id !== review._id));
123
162
  setReview(null);
163
+ setTotalCount(prev => Math.max(0, prev - 1));
124
164
  form.reset({ rating: reviewCategory === "comment" ? 1 : 0, comment: "" });
125
165
  }
126
166
  }
@@ -135,5 +175,5 @@ export function ReviewPage({ title, subtitle, targetId, targetType = "opportunit
135
175
  if (loading || !isFormInitialized)
136
176
  return _jsx(Card, { className: "w-full h-50 flex items-center justify-center", children: "Loading Reviews..." });
137
177
  const averageRating = reviews.length ? reviews.reduce((acc, r) => acc + r.rating, 0) / reviews.length : 0;
138
- return (_jsxs(Card, { className: "w-full mb-10", children: [(title || subtitle) && _jsxs(CardHeader, { children: [title && _jsx(CardTitle, { children: title }), subtitle && _jsx(CardDescription, { children: subtitle })] }), _jsxs(CardContent, { children: [editable && _jsx(Form, { ...form, children: _jsxs("form", { onSubmit: form.handleSubmit(onSubmit), className: "space-y-6 pb-4", children: [_jsx(FormField, { control: form.control, name: "rating", render: ({ field }) => (_jsxs(FormItem, { className: reviewCategory === "comment" ? "hidden" : "", children: [_jsx(FormLabel, { children: "Your Rating" }), _jsx(FormControl, { children: _jsx(StarRating, { value: ratingValue, onChange: (val) => field.onChange(val), onHover: setHoveredRating, interactive: true }) }), _jsx(FormMessage, {})] })) }), _jsx(FormField, { control: form.control, name: "comment", render: ({ field }) => (_jsxs(FormItem, { children: [_jsxs(FormLabel, { children: ["Your ", reviewCategory == "review" ? "Review" : "Comment"] }), _jsx(FormControl, { children: _jsx(Textarea, { placeholder: `Share your ${reviewCategory == "review" ? "experience" : "thoughts"}...`, className: "resize-none", rows: 4, ...field }) }), _jsx(FormMessage, {})] })) }), form.formState.errors.root && (_jsx("p", { className: "text-sm font-medium text-destructive", children: form.formState.errors.root.message })), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Button, { type: "submit", disabled: isSubmitting, className: "w-full sm:w-auto", children: isSubmitting ? (reviewCategory == "review" ? "Submitting... Review" : "Posting... Comment") : (reviewCategory == "review" ? "Submit Review" : "Post Comment") }), review && _jsx(Button, { type: "button", variant: "destructive", className: "w-full sm:w-auto", disabled: isDeleting, onClick: handleDeleteReview, children: isDeleting ? "Deleting..." : reviewCategory == "review" ? "Delete Review" : "Delete Comment" })] })] }) }), displayReviews.length > 0 ? (_jsxs("div", { className: "mt-4", children: [_jsxs("div", { className: "flex justify-between items-center mb-4", children: [_jsxs("h3", { className: "text-lg font-medium", children: [reviewCategory == "review" ? "Reviews" : "Comments", " (", displayReviews.length, ")"] }), reviewCategory == "review" && _jsxs("div", { className: "flex items-center", children: [_jsx("span", { className: "font-medium mr-2", children: averageRating.toFixed(1) }), _jsx(StarRating, { value: Math.round(averageRating), size: 5 })] })] }), _jsx(Separator, { className: "my-4" }), _jsx("div", { className: "space-y-6", children: displayReviews.map((review) => (_jsxs("div", { className: "pb-4", children: [_jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "flex items-center", children: [_jsxs(Avatar, { className: "h-10 w-10 mr-3", children: [_jsx(AvatarImage, { src: review.reviewerPic || "/images/profile_placeholder.webp", alt: review.reviewerUsername }), _jsx(AvatarFallback, { children: review.reviewerUsername.charAt(0) })] }), _jsxs("div", { children: [_jsx("h4", { className: "font-medium", children: review.reviewerUsername }), _jsx("p", { className: "text-sm text-gray-500", children: formatDate(review.createdAt) })] })] }), reviewCategory == "review" && _jsx(StarRating, { value: review.rating, size: 4 })] }), _jsx("p", { className: "mt-2 text-gray-600 whitespace-pre-line", children: review.comment }), _jsx(Separator, { className: "mt-4" })] }, review._id))) })] })) : (_jsxs("div", { className: "text-center justify-center p-5", children: ["No ", reviewCategory == "comment" ? "comments" : "reviews", " yet"] }))] }), displayReviews.length > 0 && _jsx(CardFooter, { children: _jsx("p", { className: "text-sm text-gray-500", children: "Thank you for sharing your feedback. All reviews are moderated and typically appear within 24-48 hours." }) })] }));
178
+ return (_jsxs(Card, { className: "w-full mb-10", children: [(title || subtitle) && _jsxs(CardHeader, { children: [title && _jsx(CardTitle, { children: title }), subtitle && _jsx(CardDescription, { children: subtitle })] }), _jsxs(CardContent, { children: [editable && _jsx(Form, { ...form, children: _jsxs("form", { onSubmit: form.handleSubmit(onSubmit), className: "space-y-6 pb-4", children: [_jsx(FormField, { control: form.control, name: "rating", render: ({ field }) => (_jsxs(FormItem, { className: reviewCategory === "comment" ? "hidden" : "", children: [_jsx(FormLabel, { children: "Your Rating" }), _jsx(FormControl, { children: _jsx(StarRating, { value: ratingValue, onChange: (val) => field.onChange(val), onHover: setHoveredRating, interactive: true }) }), _jsx(FormMessage, {})] })) }), _jsx(FormField, { control: form.control, name: "comment", render: ({ field }) => (_jsxs(FormItem, { children: [_jsxs(FormLabel, { children: ["Your ", reviewCategory == "review" ? "Review" : "Comment"] }), _jsx(FormControl, { children: _jsx(Textarea, { placeholder: `Share your ${reviewCategory == "review" ? "experience" : "thoughts"}...`, className: "resize-none", rows: 4, ...field }) }), _jsx(FormMessage, {})] })) }), form.formState.errors.root && (_jsx("p", { className: "text-sm font-medium text-destructive", children: form.formState.errors.root.message })), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Button, { type: "submit", disabled: isSubmitting, className: "w-full sm:w-auto", children: isSubmitting ? (reviewCategory == "review" ? "Submitting... Review" : "Posting... Comment") : (reviewCategory == "review" ? "Submit Review" : "Post Comment") }), review && _jsx(Button, { type: "button", variant: "destructive", className: "w-full sm:w-auto", disabled: isDeleting, onClick: handleDeleteReview, children: isDeleting ? "Deleting..." : reviewCategory == "review" ? "Delete Review" : "Delete Comment" })] })] }) }), displayReviews.length > 0 ? (_jsxs("div", { className: "mt-4", children: [_jsxs("div", { className: "flex justify-between items-center mb-4", children: [_jsxs("h3", { className: "text-lg font-medium", children: [reviewCategory == "review" ? "Reviews" : "Comments", " (", totalCount || displayReviews.length, ")"] }), reviewCategory == "review" && _jsxs("div", { className: "flex items-center", children: [_jsx("span", { className: "font-medium mr-2", children: averageRating.toFixed(1) }), _jsx(StarRating, { value: Math.round(averageRating), size: 5 })] })] }), _jsx(Separator, { className: "my-4" }), _jsx("div", { className: "space-y-6", children: displayReviews.map((review) => (_jsxs("div", { className: "pb-4", children: [_jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "flex items-center", children: [_jsxs(Avatar, { className: "h-10 w-10 mr-3", children: [_jsx(AvatarImage, { src: review.reviewerPic || "/images/profile_placeholder.webp", alt: review.reviewerUsername }), _jsx(AvatarFallback, { children: review.reviewerUsername.charAt(0) })] }), _jsxs("div", { children: [_jsx("h4", { className: "font-medium", children: review.reviewerUsername }), _jsx("p", { className: "text-sm text-gray-500", children: formatDate(review.createdAt) })] })] }), reviewCategory == "review" && _jsx(StarRating, { value: review.rating, size: 4 })] }), _jsx("p", { className: "mt-2 text-gray-600 whitespace-pre-line", children: review.comment }), _jsx(Separator, { className: "mt-4" })] }, review._id))) }), hasMore && (_jsx("div", { className: "flex justify-center mt-6", children: _jsx(Button, { variant: "outline", onClick: handleLoadMore, disabled: isLoadingMore, className: "w-full sm:w-auto", children: isLoadingMore ? "Loading more..." : "View More" }) }))] })) : (_jsxs("div", { className: "text-center justify-center p-5", children: ["No ", reviewCategory == "comment" ? "comments" : "reviews", " yet"] }))] }), displayReviews.length > 0 && _jsx(CardFooter, { children: _jsx("p", { className: "text-sm text-gray-500", children: "Thank you for sharing your feedback. All reviews are moderated and typically appear within 24-48 hours." }) })] }));
139
179
  }
@@ -1 +1 @@
1
- {"version":3,"file":"alertdialogclaude.d.ts","sourceRoot":"","sources":["../../src/misc/alertdialogclaude.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,UAAU,gBAAgB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACzC;AAED,eAAO,MAAM,aAAa,GAAI,QAAQ,GAAG,KAapC,YAAY,EAAE,CAAC;AAEpB,eAAO,MAAM,cAAc,GAAI,QAAQ,GAAG,KAarC,YAAY,EAAE,CAAC;AAEpB,wBAAgB,SAAS,CACrB,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC,CAiCf;AAED,wBAAgB,WAAW,CAAC,EACxB,OAAO,EACP,KAAK,EACL,OAAY,EACZ,MAAM,EACN,YAAY,GACf,EAAE,gBAAgB,2CA0DlB;AAyBD,wBAAgB,eAAe,4CA2I9B"}
1
+ {"version":3,"file":"alertdialogclaude.d.ts","sourceRoot":"","sources":["../../src/misc/alertdialogclaude.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,UAAU,gBAAgB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACzC;AAED,eAAO,MAAM,aAAa,GAAI,QAAQ,GAAG,KAapC,YAAY,EAAE,CAAC;AAEpB,eAAO,MAAM,cAAc,GAAI,QAAQ,GAAG,KAarC,YAAY,EAAE,CAAC;AAEpB,wBAAgB,SAAS,CACrB,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC,CAiCf;AAED,wBAAgB,WAAW,CAAC,EACxB,OAAO,EACP,KAAK,EACL,OAAY,EACZ,MAAM,EACN,YAAY,GACf,EAAE,gBAAgB,2CA8DlB;AAyBD,wBAAgB,eAAe,4CA2I9B"}
@@ -59,7 +59,7 @@ export function showAlert(message, title, actions) {
59
59
  });
60
60
  }
61
61
  export function AlertDialog({ message, title, actions = [], isOpen, onOpenChange, }) {
62
- return (_jsx(AlertDialogPrimitive.Root, { open: isOpen, onOpenChange: onOpenChange, children: _jsxs(AlertDialogPrimitive.Portal, { children: [_jsx(AlertDialogPrimitive.Overlay, { className: "fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0" }), _jsxs(AlertDialogPrimitive.Content, { className: "fixed left-1/2 top-1/2 z-50 max-h-[85vh] w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border border-neutral-200 bg-white p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-top-[2%] data-[state=open]:slide-in-from-top-[2%] dark:border-neutral-800 dark:bg-neutral-950 sm:rounded-lg md:w-full", children: [_jsxs("div", { className: "flex flex-col space-y-2", children: [title && (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(AlertDialogPrimitive.Title, { className: "text-lg font-semibold text-neutral-900 dark:text-neutral-50 flex-grow text-center", children: title }), _jsx(Button, { variant: "ghost", onClick: () => onOpenChange(false), children: _jsx(X, {}) })] })), _jsx(AlertDialogPrimitive.Description, { className: "text-sm text-neutral-700 dark:text-neutral-300 text-center", children: message })] }), _jsx("div", { className: cn("mt-6 flex flex-col-reverse gap-2 sm:flex-row", actions.length > 0 ? "sm:justify-end" : "justify-center"), children: actions.length > 0 ? (actions.map((action, index) => (_jsx(AlertDialogButton, { variant: action.variant || 'default', onClick: () => {
62
+ return (_jsx(AlertDialogPrimitive.Root, { open: isOpen, onOpenChange: onOpenChange, children: _jsxs(AlertDialogPrimitive.Portal, { children: [_jsx(AlertDialogPrimitive.Overlay, { className: "fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0" }), _jsxs(AlertDialogPrimitive.Content, { className: "fixed left-1/2 top-1/2 z-50 max-h-[85vh] w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border border-neutral-200 bg-white p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-top-[2%] data-[state=open]:slide-in-from-top-[2%] dark:border-neutral-800 dark:bg-neutral-950 sm:rounded-lg md:w-full", children: [_jsxs("div", { className: "flex flex-col space-y-2", children: [title ? (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(AlertDialogPrimitive.Title, { className: "text-lg font-semibold text-neutral-900 dark:text-neutral-50 flex-grow text-center", children: title }), _jsx(Button, { variant: "ghost", onClick: () => onOpenChange(false), children: _jsx(X, {}) })] })) : (_jsx(AlertDialogPrimitive.Title, { className: "sr-only", children: "Alert" })), _jsx(AlertDialogPrimitive.Description, { className: "text-sm text-neutral-700 dark:text-neutral-300 text-center", children: message })] }), _jsx("div", { className: cn("mt-6 flex flex-col-reverse gap-2 sm:flex-row", actions.length > 0 ? "sm:justify-end" : "justify-center"), children: actions.length > 0 ? (actions.map((action, index) => (_jsx(AlertDialogButton, { variant: action.variant || 'default', onClick: () => {
63
63
  action.action();
64
64
  onOpenChange(false);
65
65
  }, children: action.label }, index)))) : (_jsx(AlertDialogButton, { onClick: () => onOpenChange(false), children: "OK" })) })] })] }) }));
@@ -14,7 +14,7 @@ function CommandInput({ className, ...props }) {
14
14
  return (_jsxs("div", { "data-slot": "command-input-wrapper", className: "flex h-9 items-center gap-2 border-b px-3", children: [_jsx(SearchIcon, { className: "size-4 shrink-0 opacity-50" }), _jsx(CommandPrimitive.Input, { "data-slot": "command-input", className: cn("placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50", className), ...props })] }));
15
15
  }
16
16
  function CommandList({ className, ...props }) {
17
- return (_jsx(CommandPrimitive.List, { "data-slot": "command-list", className: cn("max-h-[250px] scroll-py-1 overflow-x-hidden overflow-y-auto", className), ...props }));
17
+ return (_jsx(CommandPrimitive.List, { "data-slot": "command-list", className: cn("max-h-[350px] scroll-py-1 overflow-x-hidden overflow-y-auto touch-pan-y z-[300]", className), ...props }));
18
18
  }
19
19
  function CommandEmpty({ ...props }) {
20
20
  return (_jsx(CommandPrimitive.Empty, { "data-slot": "command-empty", className: "py-6 text-center text-sm", ...props }));
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ActionButtons = ActionButtons;
7
+ const lucide_react_1 = require("lucide-react");
8
+ const react_1 = __importDefault(require("react"));
9
+ const button_1 = require("../misc/button");
10
+ const dropdown_menu_1 = require("../misc/dropdown-menu");
11
+ function ActionButtons({ actions, includeMoreMenu = true, maxDisplayed = 0 }) {
12
+ const displayedActions = actions.slice(0, maxDisplayed);
13
+ const menuActions = includeMoreMenu ? actions.slice(maxDisplayed) : [];
14
+ return (react_1.default.createElement("div", { className: "flex items-center gap-2" },
15
+ displayedActions.map((action, index) => (react_1.default.createElement(button_1.Button, { key: index, variant: action.variant || 'outline', size: "sm", onClick: (e) => {
16
+ e.stopPropagation();
17
+ action.action();
18
+ }, className: 'cursor-pointer' },
19
+ action.icon,
20
+ react_1.default.createElement("span", { className: "ml-1" }, action.label)))),
21
+ menuActions.length > 0 && (react_1.default.createElement(dropdown_menu_1.DropdownMenu, null,
22
+ react_1.default.createElement(dropdown_menu_1.DropdownMenuTrigger, { asChild: true },
23
+ react_1.default.createElement(button_1.Button, { variant: "outline", size: "sm" },
24
+ react_1.default.createElement(lucide_react_1.MoreHorizontal, { className: "h-4 w-4 cursor-pointer" }))),
25
+ react_1.default.createElement(dropdown_menu_1.DropdownMenuContent, { align: "end" }, menuActions.map((action, index) => (react_1.default.createElement(dropdown_menu_1.DropdownMenuItem, { key: index, onClick: (e) => {
26
+ e.stopPropagation();
27
+ action.action();
28
+ } },
29
+ action.icon,
30
+ react_1.default.createElement("span", { className: "ml-2" }, action.label)))))))));
31
+ }
@@ -0,0 +1,12 @@
1
+ type UploadType = "image" | "document" | "both";
2
+ interface FileUploadProps {
3
+ label?: string;
4
+ required?: boolean;
5
+ type?: UploadType;
6
+ value?: File | null;
7
+ onChange: (file: File | null) => void;
8
+ className?: string;
9
+ }
10
+ export declare function FileUpload({ label, required, type, value, onChange, className, }: FileUploadProps): import("react/jsx-runtime").JSX.Element;
11
+ export {};
12
+ //# sourceMappingURL=document-upload-button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-upload-button.d.ts","sourceRoot":"","sources":["../../src/misc/document-upload-button.tsx"],"names":[],"mappings":"AAMA,KAAK,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;AAEhD,UAAU,eAAe;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,UAAU,CAAC,EACvB,KAAqB,EACrB,QAAQ,EACR,IAAa,EACb,KAAK,EACL,QAAQ,EACR,SAAS,GACZ,EAAE,eAAe,2CAmEjB"}
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRef } from "react";
3
+ import { cn } from "@myrjfa/state/dist/lib/utils";
4
+ import { FileUp, ImageIcon, FileText } from "lucide-react";
5
+ import { Input } from "./input";
6
+ import { Label } from "./label";
7
+ export function FileUpload({ label = "Upload File", required, type = "both", value, onChange, className, }) {
8
+ const inputRef = useRef(null);
9
+ const acceptMap = {
10
+ image: "image/*",
11
+ document: "application/pdf",
12
+ both: "application/pdf,image/*",
13
+ };
14
+ const helperTextMap = {
15
+ image: "Image only",
16
+ document: "PDF only",
17
+ both: "PDF or image",
18
+ };
19
+ const Icon = type === "image"
20
+ ? ImageIcon
21
+ : type === "document"
22
+ ? FileText
23
+ : FileUp;
24
+ return (_jsxs("div", { className: cn("w-full", className), children: [_jsxs(Label, { className: "text-sm font-medium", children: [label, " ", required && _jsx("span", { className: "text-destructive", children: "*" }), _jsxs("span", { className: "text-xs text-muted-foreground ml-2", children: ["(", helperTextMap[type], ")"] })] }), _jsxs("div", { onClick: () => { var _a; return (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, className: cn("mt-2 border-2 border-dashed rounded-lg cursor-pointer transition-all", "flex flex-col items-center justify-center text-center", "hover:border-primary/50",
25
+ // 📱 Responsive sizing
26
+ "p-3"), children: [_jsx(Icon, { className: "w-5 h-5 sm:w-6 sm:h-6 text-muted-foreground mb-1" }), value ? (_jsx("p", { className: "text-xs sm:text-sm text-primary font-medium break-all", children: value.name })) : (_jsx("p", { className: "text-xs sm:text-sm text-muted-foreground", children: "Tap or click to upload" })), _jsx(Input, { ref: inputRef, type: "file", accept: acceptMap[type], className: "hidden", onChange: (e) => { var _a, _b; return onChange((_b = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : null); } })] })] }));
27
+ }
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ interface EmptyStateProps {
3
+ title?: string;
4
+ description?: string;
5
+ icon?: React.ReactNode;
6
+ action?: React.ReactNode;
7
+ }
8
+ export declare function EmptyState({ title, description, icon, action, }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=empty-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty-state.d.ts","sourceRoot":"","sources":["../../src/misc/empty-state.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,UAAU,eAAe;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED,wBAAgB,UAAU,CAAC,EACvB,KAA0B,EAC1B,WAAW,EACX,IAAI,EACJ,MAAM,GACT,EAAE,eAAe,2CAajB"}
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Inbox } from 'lucide-react';
3
+ export function EmptyState({ title = 'Nothing here yet', description, icon, action, }) {
4
+ return (_jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-4 text-center gap-3", children: [_jsx("div", { className: "text-muted-foreground", children: icon !== null && icon !== void 0 ? icon : _jsx(Inbox, { className: "w-12 h-12 mx-auto mb-2 opacity-40" }) }), _jsx("h3", { className: "text-lg font-semibold text-foreground", children: title }), description && (_jsx("p", { className: "text-sm text-muted-foreground max-w-xs", children: description })), action && _jsx("div", { className: "mt-2", children: action })] }));
5
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/misc/filter.tsx"],"names":[],"mappings":"AAsBA,KAAK,WAAW,GAAG;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzC,MAAM,CAAC,EAAE,OAAO,CAAA;CACnB,CAAC;AACF,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,EAAE,aACwC,CAAC;AAElF,QAAA,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAgHjC,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,CAAC"}
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/misc/filter.tsx"],"names":[],"mappings":"AAsBA,KAAK,WAAW,GAAG;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzC,MAAM,CAAC,EAAE,OAAO,CAAA;CACnB,CAAC;AACF,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,EAAE,aACwC,CAAC;AAElF,QAAA,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAqHjC,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,CAAC"}
@@ -30,7 +30,7 @@ const Filter = ({ values, label, formType, selectedValue, onChange, others }) =>
30
30
  }, [open]);
31
31
  return (_jsx("div", { className: cn("filter-container", label), children: formType === "select" ? (_jsxs(Select, { value: selectedValue !== null && selectedValue !== void 0 ? selectedValue : "", onValueChange: (val) => onChange(val === "clear" ? null : val), children: [_jsx(SelectTrigger, { className: "w-full bg-transparent hover:bg-muted border-none shadow-none", children: !selectedValue || selectedValue === "clear" || selectedValue[0] == '0'
32
32
  ? `Choose ${label.toLowerCase()}...`
33
- : selectedValue }), _jsxs(SelectContent, { className: "w-full z-201", children: [_jsx(SelectItem, { value: "clear", children: _jsx("em", { children: "Clear" }) }), data.map((option) => (_jsx(SelectItem, { value: option, children: option }, option)))] })] })) : (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, className: "w-full overflow-y-auto", children: _jsxs(Button, { ref: triggerRef, variant: "ghost", role: "combobox", className: "filter-box justify-between w-full", children: [selectedValue || `Select ${label.toLowerCase()}...`, _jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })] }) }), _jsxs(PopoverContent, { className: "p-0 w-full z-201", style: { width: `${popoverWidth}px` }, align: "start", children: [_jsxs(Command, { children: [_jsx(CommandInput, { placeholder: `Search ${label.toLowerCase()}...` }), _jsx(CommandEmpty, { children: "No results found." }), _jsx(CommandList, { children: data.map((option) => (_jsxs(CommandItem, { value: option, onSelect: () => {
33
+ : selectedValue }), _jsxs(SelectContent, { className: "w-full z-[301]", children: [_jsx(SelectItem, { value: "clear", children: _jsx("em", { children: "Clear" }) }), data.map((option) => (_jsx(SelectItem, { value: option, children: option }, option)))] })] })) : (_jsxs(Popover, { open: open, onOpenChange: setOpen, modal: false, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { ref: triggerRef, variant: "ghost", role: "combobox", className: "filter-box justify-between w-full", children: [selectedValue || `Select ${label.toLowerCase()}...`, _jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })] }) }), _jsxs(PopoverContent, { className: "p-0 z-[310] pointer-events-auto overflow-hidden", style: { width: popoverWidth > 0 ? `${popoverWidth}px` : 'auto', minWidth: 'min(300px, 90vw)' }, align: "start", onWheel: (e) => e.stopPropagation(), children: [_jsxs(Command, { children: [_jsx(CommandInput, { placeholder: `Search ${label.toLowerCase()}...` }), _jsx(CommandEmpty, { children: "No results found." }), _jsx(CommandList, { children: data.map((option) => (_jsxs(CommandItem, { value: option, onSelect: () => {
34
34
  onChange(option);
35
35
  setOpen(false);
36
36
  }, children: [_jsx(Check, { className: cn("mr-2 h-4 w-4", selectedValue === option ? "opacity-100" : "opacity-0") }), option] }, option))) })] }), others &&
@@ -0,0 +1,29 @@
1
+ export interface CompressOptions {
2
+ quality?: number;
3
+ maxWidth?: number;
4
+ maxHeight?: number;
5
+ }
6
+ /**
7
+ * Compress an image File using Canvas API.
8
+ * Returns a new File object with the same name but compressed content.
9
+ */
10
+ export declare function compressImage(file: File, options?: CompressOptions): Promise<File>;
11
+ export interface ImageCompressorProps {
12
+ enableCompression?: boolean;
13
+ quality?: number;
14
+ maxWidth?: number;
15
+ maxHeight?: number;
16
+ accept?: string;
17
+ multiple?: boolean;
18
+ onChange: (files: File[]) => void;
19
+ children?: React.ReactNode;
20
+ className?: string;
21
+ id?: string;
22
+ }
23
+ /**
24
+ * #26 — Image Compressor Input Component
25
+ * Drop-in replacement for a file input that optionally compresses images
26
+ * before passing them to the onChange handler.
27
+ */
28
+ export declare function ImageCompressorInput({ enableCompression, quality, maxWidth, maxHeight, accept, multiple, onChange, children, className, id, }: ImageCompressorProps): import("react/jsx-runtime").JSX.Element;
29
+ //# sourceMappingURL=image-compressor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-compressor.d.ts","sourceRoot":"","sources":["../../src/misc/image-compressor.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,eAAe;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAC/B,IAAI,EAAE,IAAI,EACV,OAAO,GAAE,eAAoB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAkDf;AAED,MAAM,WAAW,oBAAoB;IACjC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,iBAAwB,EACxB,OAAa,EACb,QAAe,EACf,SAAgB,EAChB,MAAoD,EACpD,QAAgB,EAChB,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,EAAE,GACL,EAAE,oBAAoB,2CAmCtB"}
@@ -0,0 +1,70 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useRef, useCallback } from 'react';
4
+ /**
5
+ * Compress an image File using Canvas API.
6
+ * Returns a new File object with the same name but compressed content.
7
+ */
8
+ export async function compressImage(file, options = {}) {
9
+ const { quality = 0.8, maxWidth = 1920, maxHeight = 1920 } = options;
10
+ return new Promise((resolve, reject) => {
11
+ const img = new Image();
12
+ const url = URL.createObjectURL(file);
13
+ img.onload = () => {
14
+ URL.revokeObjectURL(url);
15
+ let { width, height } = img;
16
+ if (width > maxWidth) {
17
+ height = Math.round((height * maxWidth) / width);
18
+ width = maxWidth;
19
+ }
20
+ if (height > maxHeight) {
21
+ width = Math.round((width * maxHeight) / height);
22
+ height = maxHeight;
23
+ }
24
+ const canvas = document.createElement('canvas');
25
+ canvas.width = width;
26
+ canvas.height = height;
27
+ const ctx = canvas.getContext('2d');
28
+ if (!ctx) {
29
+ resolve(file); // fallback: return original
30
+ return;
31
+ }
32
+ ctx.drawImage(img, 0, 0, width, height);
33
+ canvas.toBlob((blob) => {
34
+ if (!blob) {
35
+ resolve(file); // fallback
36
+ return;
37
+ }
38
+ resolve(new File([blob], file.name, { type: 'image/webp', lastModified: Date.now() }));
39
+ }, 'image/webp', quality);
40
+ };
41
+ img.onerror = () => {
42
+ URL.revokeObjectURL(url);
43
+ reject(new Error(`Failed to load image: ${file.name}`));
44
+ };
45
+ img.src = url;
46
+ });
47
+ }
48
+ /**
49
+ * #26 — Image Compressor Input Component
50
+ * Drop-in replacement for a file input that optionally compresses images
51
+ * before passing them to the onChange handler.
52
+ */
53
+ export function ImageCompressorInput({ enableCompression = true, quality = 0.8, maxWidth = 1920, maxHeight = 1920, accept = 'image/jpeg,image/jpg,image/png,image/webp', multiple = false, onChange, children, className, id, }) {
54
+ const inputRef = useRef(null);
55
+ const handleChange = useCallback(async (e) => {
56
+ const rawFiles = Array.from(e.target.files || []);
57
+ if (!rawFiles.length)
58
+ return;
59
+ if (!enableCompression) {
60
+ onChange(rawFiles);
61
+ return;
62
+ }
63
+ const compressed = await Promise.all(rawFiles.map(f => compressImage(f, { quality, maxWidth, maxHeight }).catch(() => f)));
64
+ onChange(compressed);
65
+ // Reset input so the same file can be re-selected
66
+ if (inputRef.current)
67
+ inputRef.current.value = '';
68
+ }, [enableCompression, quality, maxWidth, maxHeight, onChange]);
69
+ return (_jsxs("label", { className: className, style: { cursor: 'pointer' }, children: [children, _jsx("input", { ref: inputRef, id: id, type: "file", accept: accept, multiple: multiple, onChange: handleChange, style: { display: 'none' } })] }));
70
+ }
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ interface ImageCropperProps {
3
+ image: string;
4
+ onCancel: () => void;
5
+ onCropComplete: (croppedImage: Blob) => void;
6
+ open: boolean;
7
+ }
8
+ declare const ImageCropper: React.FC<ImageCropperProps>;
9
+ export default ImageCropper;
10
+ //# sourceMappingURL=image-cropper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-cropper.d.ts","sourceRoot":"","sources":["../../src/misc/image-cropper.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAMrD,UAAU,iBAAiB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,EAAE,CAAC,YAAY,EAAE,IAAI,KAAK,IAAI,CAAC;IAC7C,IAAI,EAAE,OAAO,CAAC;CACjB;AAED,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAgG7C,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState, useCallback } from "react";
4
+ import Cropper from "react-easy-crop";
5
+ import { Button } from "./button";
6
+ import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "./dialog";
7
+ import { Slider } from "./slider";
8
+ const ImageCropper = ({ image, onCancel, onCropComplete, open }) => {
9
+ const [crop, setCrop] = useState({ x: 0, y: 0 });
10
+ const [zoom, setZoom] = useState(1);
11
+ const [croppedAreaPixels, setCroppedAreaPixels] = useState(null);
12
+ const onCropChange = (crop) => {
13
+ setCrop(crop);
14
+ };
15
+ const onZoomChange = (zoom) => {
16
+ setZoom(zoom);
17
+ };
18
+ const onCropCompleteCallback = useCallback((_, croppedAreaPixels) => {
19
+ setCroppedAreaPixels(croppedAreaPixels);
20
+ }, []);
21
+ const createCroppedImage = async () => {
22
+ if (!croppedAreaPixels || !image)
23
+ return;
24
+ const img = new Image();
25
+ img.src = image;
26
+ await new Promise((resolve) => {
27
+ img.onload = resolve;
28
+ });
29
+ const canvas = document.createElement("canvas");
30
+ const ctx = canvas.getContext("2d");
31
+ if (!ctx)
32
+ return;
33
+ canvas.width = croppedAreaPixels.width;
34
+ canvas.height = croppedAreaPixels.height;
35
+ ctx.drawImage(img, croppedAreaPixels.x, croppedAreaPixels.y, croppedAreaPixels.width, croppedAreaPixels.height, 0, 0, croppedAreaPixels.width, croppedAreaPixels.height);
36
+ canvas.toBlob((blob) => {
37
+ if (blob) {
38
+ onCropComplete(blob);
39
+ }
40
+ }, "image/jpeg");
41
+ };
42
+ return (_jsx(Dialog, { open: open, onOpenChange: (isOpen) => !isOpen && onCancel(), children: _jsxs(DialogContent, { className: "sm:max-w-[500px] z-[300]", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: "Crop Profile Picture" }) }), _jsx("div", { className: "relative h-[300px] w-full bg-gray-100 rounded-md overflow-hidden", children: _jsx(Cropper, { image: image, crop: crop, zoom: zoom, aspect: 1, cropShape: "round", showGrid: false, onCropChange: onCropChange, onCropComplete: onCropCompleteCallback, onZoomChange: onZoomChange }) }), _jsx("div", { className: "py-4", children: _jsxs("div", { className: "flex items-center gap-4", children: [_jsx("span", { className: "text-sm font-medium", children: "Zoom" }), _jsx(Slider, { value: [zoom], min: 1, max: 5, step: 0.1, onValueChange: (values) => { var _a; return setZoom((_a = values[0]) !== null && _a !== void 0 ? _a : 1); }, className: "flex-1" })] }) }), _jsxs(DialogFooter, { className: "flex gap-2", children: [_jsx(Button, { variant: "outline", onClick: onCancel, children: "Cancel" }), _jsx(Button, { onClick: createCroppedImage, children: "Set Profile Picture" })] })] }) }));
43
+ };
44
+ export default ImageCropper;
@@ -1 +1 @@
1
- {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/misc/input.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,iBAAS,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,2CAc1E;AAED,OAAO,EAAE,KAAK,EAAE,CAAA"}
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/misc/input.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,iBAAS,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,2CAgB1E;AAED,OAAO,EAAE,KAAK,EAAE,CAAA"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { cn } from "@myrjfa/state";
3
3
  function Input({ className, type, ...props }) {
4
- return (_jsx("input", { type: type, "data-slot": "input", className: cn("border-input file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", className), ...props }));
4
+ return (_jsx("input", { type: type, "data-slot": "input", onWheel: (e) => e.currentTarget.blur(), className: cn("border-input file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", "[&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none", className), ...props }));
5
5
  }
6
6
  export { Input };