ikoncomponents 1.2.0 → 1.2.2

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 (63) hide show
  1. package/dist/ikoncomponents/activity-sheet/index.d.ts +11 -0
  2. package/dist/ikoncomponents/activity-sheet/index.js +23 -0
  3. package/dist/ikoncomponents/big-calendar/big-calender-event/index.d.ts +5 -0
  4. package/dist/ikoncomponents/big-calendar/big-calender-event/index.js +16 -0
  5. package/dist/ikoncomponents/big-calendar/big-calender-toolbar/index.d.ts +2 -0
  6. package/dist/ikoncomponents/big-calendar/big-calender-toolbar/index.js +39 -0
  7. package/dist/ikoncomponents/big-calendar/index.d.ts +4 -0
  8. package/dist/ikoncomponents/big-calendar/index.js +35 -0
  9. package/dist/ikoncomponents/big-calendar/type.d.ts +31 -0
  10. package/dist/ikoncomponents/big-calendar/type.js +1 -0
  11. package/dist/ikoncomponents/form-fields/combobox-input-value/index.js +1 -0
  12. package/dist/ikoncomponents/image-cropper-upload/components/newCropper.d.ts +15 -0
  13. package/dist/ikoncomponents/image-cropper-upload/components/newCropper.js +85 -0
  14. package/dist/ikoncomponents/image-cropper-upload/components/newImageUploadForm.d.ts +7 -0
  15. package/dist/ikoncomponents/image-cropper-upload/components/newImageUploadForm.js +145 -0
  16. package/dist/ikoncomponents/image-cropper-upload/cropper-form/index.d.ts +6 -0
  17. package/dist/ikoncomponents/image-cropper-upload/cropper-form/index.js +92 -0
  18. package/dist/ikoncomponents/image-cropper-upload/cropper-form-with-modal/index.d.ts +6 -0
  19. package/dist/ikoncomponents/image-cropper-upload/cropper-form-with-modal/index.js +14 -0
  20. package/dist/ikoncomponents/image-cropper-upload/image-cropper/index.d.ts +14 -0
  21. package/dist/ikoncomponents/image-cropper-upload/image-cropper/index.js +87 -0
  22. package/dist/ikoncomponents/image-cropper-upload/index.d.ts +27 -0
  23. package/dist/ikoncomponents/image-cropper-upload/index.js +49 -0
  24. package/dist/ikoncomponents/image-cropper-upload/utils/index.d.ts +16 -0
  25. package/dist/ikoncomponents/image-cropper-upload/utils/index.js +73 -0
  26. package/dist/ikoncomponents/main-layout/main-sidebar.d.ts +5 -9
  27. package/dist/ikoncomponents/main-layout/main-sidebar.js +2 -2
  28. package/dist/ikoncomponents/provider-wrapper/index.d.ts +5 -0
  29. package/dist/ikoncomponents/provider-wrapper/index.js +10 -0
  30. package/dist/ikoncomponents/resource-spreadsheet/index.d.ts +21 -21
  31. package/dist/ikoncomponents/resource-spreadsheet/index.js +36 -36
  32. package/dist/index.d.ts +15 -0
  33. package/dist/index.js +9 -0
  34. package/dist/styles.css +95 -0
  35. package/dist/utils/actions/account/index.d.ts +5 -0
  36. package/dist/utils/actions/account/index.js +28 -0
  37. package/dist/utils/actions/account/type.d.ts +4 -0
  38. package/dist/utils/actions/account/type.js +1 -0
  39. package/dist/utils/actions/auth/index.d.ts +7 -0
  40. package/dist/utils/actions/auth/index.js +58 -0
  41. package/dist/utils/actions/common/utils.d.ts +5 -0
  42. package/dist/utils/actions/common/utils.js +25 -0
  43. package/dist/utils/actions/software/index.d.ts +11 -0
  44. package/dist/utils/actions/software/index.js +75 -0
  45. package/dist/utils/api/accountService/index.d.ts +23 -0
  46. package/dist/utils/api/accountService/index.js +64 -0
  47. package/dist/utils/api/accountService/type.d.ts +4 -0
  48. package/dist/utils/api/accountService/type.js +1 -0
  49. package/dist/utils/api/file-upload/index.d.ts +5 -0
  50. package/dist/utils/api/file-upload/index.js +80 -0
  51. package/dist/utils/api/file-upload/type.d.ts +6 -0
  52. package/dist/utils/api/file-upload/type.js +1 -0
  53. package/dist/utils/api/ikonBaseApi.d.ts +12 -0
  54. package/dist/utils/api/ikonBaseApi.js +104 -0
  55. package/dist/utils/api/loginService/index.d.ts +12 -0
  56. package/dist/utils/api/loginService/index.js +72 -0
  57. package/dist/utils/api/loginService/type.d.ts +31 -0
  58. package/dist/utils/api/loginService/type.js +1 -0
  59. package/dist/utils/api/softwareService/index.d.ts +64 -0
  60. package/dist/utils/api/softwareService/index.js +212 -0
  61. package/dist/utils/api/softwareService/type.d.ts +54 -0
  62. package/dist/utils/api/softwareService/type.js +1 -0
  63. package/package.json +6 -2
@@ -0,0 +1,11 @@
1
+ export type ActivityLogProps = {
2
+ id: string;
3
+ activity: string;
4
+ updatedBy: string;
5
+ updatedOn: string;
6
+ source: string;
7
+ parentId: string;
8
+ };
9
+ export declare function ActivitySheet({ activityLogs }: {
10
+ activityLogs?: ActivityLogProps[];
11
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,23 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { AlignJustify } from "lucide-react";
4
+ import { Tabs } from "../tabs";
5
+ import { NoDataComponent } from "../no-data";
6
+ import { UploadTab } from "../upload-tab";
7
+ import { SheetComponent } from "../sheet";
8
+ export function ActivitySheet({ activityLogs = [] }) {
9
+ const tabArray = [
10
+ {
11
+ tabName: "Activity",
12
+ tabId: "tab-activity",
13
+ default: true,
14
+ tabContent: _jsx("div", { className: "overflow-auto flex flex-col gap-2 h-full", children: activityLogs.length > 0 ? (activityLogs.map((log) => (_jsxs("div", { className: "border-b text-sm pb-2", children: [_jsx("p", { className: "font-medium pb-1", children: log.activity }), _jsxs("p", { className: "text-gray-500 pb-1", children: ["Updated On:", " ", _jsx("span", { className: "text-gray-700", children: new Date(log.updatedOn).toLocaleString() })] }), _jsxs("p", { className: "text-gray-500 pb-1", children: ["Updated By: ", _jsx("span", { className: "text-gray-700", children: log.updatedBy })] })] }, log.id)))) : (_jsx(NoDataComponent, { text: "No Activity Logs Available" })) })
15
+ }, {
16
+ tabName: "File Upload",
17
+ tabId: "tab-upload",
18
+ default: false,
19
+ tabContent: _jsx(UploadTab, {})
20
+ }
21
+ ];
22
+ return (_jsx(SheetComponent, { buttonText: "", buttonIcon: _jsx(AlignJustify, {}), sheetTitle: "", sheetContent: _jsx(Tabs, { tabArray: tabArray, tabListClass: '' }), closeButton: true }));
23
+ }
@@ -0,0 +1,5 @@
1
+ import { BigCalendarEventProps, ExtraParamsEvent } from "../type";
2
+ export default function BigCalenderEvent({ event, extraParamsEvent }: {
3
+ event: BigCalendarEventProps;
4
+ extraParamsEvent?: ExtraParamsEvent;
5
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Eye, SquarePen } from "lucide-react";
3
+ import { TooltipComponent as Tooltip } from "../../tooltip";
4
+ // Custom event component
5
+ export default function BigCalenderEvent({ event, extraParamsEvent }) {
6
+ return (_jsxs("div", { className: "custom-event flex flex-row justify-between", children: [_jsx("span", { className: "truncate", children: event.title }), _jsxs("span", { className: "flex flex-row gap-1", children: [((extraParamsEvent === null || extraParamsEvent === void 0 ? void 0 : extraParamsEvent.isEditableAll) || event.isEditable) &&
7
+ _jsx(Tooltip, { tooltipContent: "Edit", children: _jsx("button", { className: "event-edit-button", onClick: (e) => {
8
+ var _a;
9
+ e.stopPropagation(); // Prevent triggering other event handlers
10
+ (_a = extraParamsEvent === null || extraParamsEvent === void 0 ? void 0 : extraParamsEvent.onEditEventClick) === null || _a === void 0 ? void 0 : _a.call(extraParamsEvent, event);
11
+ }, children: _jsx(SquarePen, { size: 16 }) }) }), _jsx(Tooltip, { tooltipContent: "View", children: _jsx("button", { className: "event-view-button", onClick: (e) => {
12
+ var _a;
13
+ e.stopPropagation(); // Prevent triggering other event handlers
14
+ (_a = extraParamsEvent === null || extraParamsEvent === void 0 ? void 0 : extraParamsEvent.onViewEventClick) === null || _a === void 0 ? void 0 : _a.call(extraParamsEvent, event);
15
+ }, children: _jsx(Eye, { size: 16 }) }) })] })] }));
16
+ }
@@ -0,0 +1,2 @@
1
+ import { BigCalenderToolbarProps } from "../type";
2
+ export default function BigCalenderToolbar({ onNavigate, onView, label, extraTools, view }: BigCalenderToolbarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,39 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Views } from "react-big-calendar";
3
+ import { Fragment, useState } from "react";
4
+ import { ChevronLeft, ChevronRight } from "lucide-react";
5
+ import { ToggleGroup, ToggleGroupItem } from "../../../shadcn/toggle-group";
6
+ // Custom toolbar component
7
+ export default function BigCalenderToolbar({ onNavigate, onView, label, extraTools, view }) {
8
+ const [calViewsValue, setValue] = useState(view === Views.DAY ? "DAY" : view === Views.WEEK ? "WEEK" : "MONTH");
9
+ return (_jsx(_Fragment, { children: _jsxs("div", { className: "flex flex-col md:flex-row justify-between items-start md:items-center mb-3", children: [_jsxs(ToggleGroup, { type: "single", variant: 'outline', onValueChange: (value) => {
10
+ switch (value) {
11
+ case "PREV":
12
+ onNavigate("PREV");
13
+ break;
14
+ case "NEXT":
15
+ onNavigate("NEXT");
16
+ break;
17
+ case "TODAY":
18
+ onNavigate("TODAY");
19
+ break;
20
+ default:
21
+ break;
22
+ }
23
+ }, children: [_jsx(ToggleGroupItem, { className: "rounded-e-none", value: "PREV", children: _jsx(ChevronLeft, { size: 16 }) }), _jsx(ToggleGroupItem, { className: 'rounded-none border-x-0', value: "NEXT", children: _jsx(ChevronRight, { size: 16 }) }), _jsx(ToggleGroupItem, { className: 'rounded-s-none', value: "TODAY", children: "Today" })] }), _jsx("span", { className: "rbc-toolbar-label", children: label }), _jsxs("div", { className: "flex flex-row gap-2", children: [extraTools === null || extraTools === void 0 ? void 0 : extraTools.map((tool, index) => _jsx(Fragment, { children: tool }, index)), _jsxs(ToggleGroup, { type: "single", variant: 'outline', value: calViewsValue, onValueChange: (value) => {
24
+ setValue(value);
25
+ switch (value) {
26
+ case "DAY":
27
+ onView(Views.DAY);
28
+ break;
29
+ case "WEEK":
30
+ onView(Views.WEEK);
31
+ break;
32
+ case "MONTH":
33
+ onView(Views.MONTH);
34
+ break;
35
+ default:
36
+ break;
37
+ }
38
+ }, children: [_jsx(ToggleGroupItem, { className: "rounded-e-none", value: "DAY", children: "Day" }), _jsx(ToggleGroupItem, { className: 'rounded-none border-x-0', value: "WEEK", children: "Week" }), _jsx(ToggleGroupItem, { className: 'rounded-s-none', value: "MONTH", children: "Month" })] })] })] }) }));
39
+ }
@@ -0,0 +1,4 @@
1
+ import "react-big-calendar/lib/css/react-big-calendar.css";
2
+ import "./index.css";
3
+ import { BigCalendarProps } from "./type";
4
+ export declare function BigCalendar({ events, extraParamsEvent, extraTools }: BigCalendarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,35 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { format, getDay, parse, startOfWeek } from "date-fns";
4
+ import { Calendar, dateFnsLocalizer, Views } from "react-big-calendar";
5
+ import "react-big-calendar/lib/css/react-big-calendar.css";
6
+ import { useState } from "react";
7
+ import "./index.css";
8
+ import BigCalenderToolbar from "./big-calender-toolbar";
9
+ import BigCalenderEvent from "./big-calender-event";
10
+ // Localization settings
11
+ const locales = {
12
+ "en-US": require("date-fns/locale/en-US"),
13
+ };
14
+ const localizer = dateFnsLocalizer({
15
+ format,
16
+ parse,
17
+ startOfWeek,
18
+ getDay,
19
+ locales,
20
+ });
21
+ export function BigCalendar({ events, extraParamsEvent, extraTools }) {
22
+ const [view, setView] = useState((extraParamsEvent === null || extraParamsEvent === void 0 ? void 0 : extraParamsEvent.defaultView) === "day" ? Views.DAY :
23
+ (extraParamsEvent === null || extraParamsEvent === void 0 ? void 0 : extraParamsEvent.defaultView) === "week" ? Views.WEEK :
24
+ (extraParamsEvent === null || extraParamsEvent === void 0 ? void 0 : extraParamsEvent.defaultView) === "month" ? Views.MONTH :
25
+ (extraParamsEvent === null || extraParamsEvent === void 0 ? void 0 : extraParamsEvent.defaultView) === "work week" ? Views.WORK_WEEK :
26
+ (extraParamsEvent === null || extraParamsEvent === void 0 ? void 0 : extraParamsEvent.defaultView) === "agenda" ? Views.AGENDA : Views.MONTH);
27
+ const [date, setDate] = useState(new Date());
28
+ return (_jsx(Calendar, { localizer: localizer, events: events || [], startAccessor: "start", endAccessor: "end", views: [Views.DAY, Views.WEEK, Views.MONTH], view: view, onView: (view) => setView(view), date: date, onNavigate: (date) => setDate(date), components: {
29
+ event: (props) => _jsx(BigCalenderEvent, { event: props.event, extraParamsEvent: extraParamsEvent }),
30
+ toolbar: (props) => _jsx(BigCalenderToolbar, Object.assign({}, props, { extraTools: extraTools, view: view })),
31
+ }, style: {
32
+ height: (extraParamsEvent === null || extraParamsEvent === void 0 ? void 0 : extraParamsEvent.height) || "100%",
33
+ margin: (extraParamsEvent === null || extraParamsEvent === void 0 ? void 0 : extraParamsEvent.margin) || "0px",
34
+ } }));
35
+ }
@@ -0,0 +1,31 @@
1
+ import { ReactNode } from "react";
2
+ export interface BigCalendarProps {
3
+ events: BigCalendarEventProps[];
4
+ extraParamsEvent?: ExtraParamsEvent;
5
+ extraTools?: ReactNode[];
6
+ onDateClick?: (date: Date) => void;
7
+ }
8
+ export interface ExtraParamsEvent {
9
+ defaultView?: string;
10
+ isEditableAll?: boolean;
11
+ isViewable?: boolean;
12
+ onEditEventClick?: (event: BigCalendarEventProps) => void;
13
+ onViewEventClick?: (event: BigCalendarEventProps) => void;
14
+ height?: string;
15
+ margin?: string;
16
+ }
17
+ export interface BigCalendarEventProps extends Event {
18
+ title?: string;
19
+ isEditable?: boolean;
20
+ isViewable?: boolean;
21
+ start: Date;
22
+ end: Date;
23
+ onEventClick?: (event: any) => void;
24
+ }
25
+ export interface BigCalenderToolbarProps {
26
+ onNavigate: (view: any) => void;
27
+ onView: (view: any) => void;
28
+ label: string;
29
+ extraTools?: ReactNode[];
30
+ view: "month" | "week" | "work_week" | "day" | "agenda";
31
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { useController } from "react-hook-form";
3
4
  import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "../../../shadcn/form";
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+ import "cropperjs/dist/cropper.css";
3
+ export interface CropperImgProps {
4
+ imageSrc: string | undefined;
5
+ onCroppedImage: (imageUrl: string) => void;
6
+ aspectRatio: number;
7
+ rotationAngle: number;
8
+ zoomLevel: number;
9
+ moveDirection: {
10
+ x: number;
11
+ y: number;
12
+ };
13
+ currentState: string;
14
+ }
15
+ export declare const NewCropperImg: React.FC<CropperImgProps>;
@@ -0,0 +1,85 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef } from "react";
3
+ import Cropper from "react-cropper";
4
+ import "cropperjs/dist/cropper.css";
5
+ export const NewCropperImg = ({ imageSrc, onCroppedImage, aspectRatio, rotationAngle, zoomLevel, moveDirection, currentState }) => {
6
+ const cropperRef = useRef(null);
7
+ const onCrop = () => {
8
+ var _a;
9
+ const cropper = (_a = cropperRef.current) === null || _a === void 0 ? void 0 : _a.cropper;
10
+ if (cropper) {
11
+ cropper.setDragMode('move');
12
+ const croppedCanvas = cropper.getCroppedCanvas();
13
+ const croppedImageUrl = croppedCanvas.toDataURL(); // Data URL for preview
14
+ onCroppedImage(croppedImageUrl);
15
+ }
16
+ else {
17
+ console.log("Cropper instance is not available.");
18
+ }
19
+ };
20
+ useEffect(() => {
21
+ var _a;
22
+ // Rotate the image whenever the rotation angle changes
23
+ const cropper = (_a = cropperRef.current) === null || _a === void 0 ? void 0 : _a.cropper;
24
+ if (cropper) {
25
+ cropper.rotate(rotationAngle); // Apply the rotation to the image
26
+ }
27
+ }, [rotationAngle]); // Effect will run whenever rotationAngle changes
28
+ useEffect(() => {
29
+ var _a;
30
+ // Zoom the image whenever the zoom level changes
31
+ const cropper = (_a = cropperRef.current) === null || _a === void 0 ? void 0 : _a.cropper;
32
+ if (cropper) {
33
+ const cropBoxData = cropper.getCropBoxData();
34
+ if (cropBoxData.width) {
35
+ console.log('Inside cropper scale');
36
+ cropper.scale(zoomLevel); // Apply the zoom level
37
+ }
38
+ // Apply zoom directly without using getZoom method
39
+ }
40
+ }, [zoomLevel]); // Effect will run whenever zoomLevel changes
41
+ // Move the image based on the moveDirection prop
42
+ useEffect(() => {
43
+ var _a;
44
+ const cropper = (_a = cropperRef.current) === null || _a === void 0 ? void 0 : _a.cropper;
45
+ if (cropper) {
46
+ // Make sure moveDirection is available before calling move
47
+ const cropBoxData = cropper.getCropBoxData();
48
+ if (cropBoxData.width) {
49
+ const { x, y } = moveDirection;
50
+ if (typeof x === "number" && typeof y === "number") {
51
+ cropper.move(x, y); // Move the image
52
+ }
53
+ }
54
+ }
55
+ }, [moveDirection]); // This effect runs whenever moveDirection changes
56
+ useEffect(() => {
57
+ var _a;
58
+ const cropper = (_a = cropperRef.current) === null || _a === void 0 ? void 0 : _a.cropper;
59
+ if (cropper) {
60
+ cropper.setAspectRatio(aspectRatio); // Dynamically set the aspect ratio
61
+ if (aspectRatio === 1) {
62
+ // Get the displayed (canvas) dimensions of the image
63
+ const canvasData = cropper.getCanvasData();
64
+ const canvasWidth = canvasData.width; // Displayed width of the image
65
+ const canvasHeight = canvasData.height; // Displayed height of the image
66
+ const canvasLeft = canvasData.left; // Left offset of the image within the container
67
+ const canvasTop = canvasData.top; // Top offset of the image within the container
68
+ // Define the desired crop box dimensions
69
+ const cropBoxWidth = 200; // Desired crop box width
70
+ const cropBoxHeight = 100; // Desired crop box height
71
+ // Calculate the center position for the crop box
72
+ const left = canvasLeft + (canvasWidth - cropBoxWidth) / 2;
73
+ const top = canvasTop + (canvasHeight - cropBoxHeight) / 2;
74
+ // Set the crop box data
75
+ cropper.setCropBoxData({
76
+ left: left,
77
+ top: top,
78
+ width: cropBoxWidth,
79
+ height: cropBoxHeight,
80
+ });
81
+ }
82
+ }
83
+ }, [aspectRatio]); // Trigger this effect whenever aspectRatio changes
84
+ return (_jsx(Cropper, { src: imageSrc, style: { height: "100%", width: "100%", objectFit: "contain" }, guides: true, crop: onCrop, ref: cropperRef, dragMode: 'move', movable: true, zoomable: true, scalable: true, cropBoxMovable: true, cropBoxResizable: false }));
85
+ };
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ export interface ImageFormProps {
3
+ open: boolean;
4
+ setOpen: React.Dispatch<React.SetStateAction<boolean>>;
5
+ onImageSubmit: (data: string | null) => void;
6
+ }
7
+ export declare const NewImageForm: React.NamedExoticComponent<ImageFormProps>;
@@ -0,0 +1,145 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState, useEffect, memo } from "react";
3
+ import { ZoomIn, ZoomOut, RotateCw, RotateCcw, ArrowUp, ArrowDown, ArrowLeft, ArrowRight, ImageIcon, FileImage, Square, Upload, } from "lucide-react";
4
+ import { Label } from "../../../shadcn/label";
5
+ import { Input } from "../../../shadcn/input";
6
+ import { Button } from "../../../shadcn/button";
7
+ import { NewCropperImg } from "./newCropper";
8
+ import Image from "next/image";
9
+ const NewImageFormComponent = ({ open, setOpen, onImageSubmit, }) => {
10
+ const [imageSrc, setImageSrc] = useState(null);
11
+ const [croppedImage, setCroppedImage] = useState(null);
12
+ const [prevImages, setPrevImages] = useState({
13
+ first: null,
14
+ second: null,
15
+ third: null,
16
+ });
17
+ const [aspectRatio, setAspectRatio] = useState(4 / 3);
18
+ const [activeState, setActiveState] = useState("first");
19
+ const [rotationAngle, setRotationAngle] = useState(0);
20
+ const [scale, setScale] = useState(1);
21
+ const [moveDirection, setMoveDirection] = useState({
22
+ x: 0,
23
+ y: 0,
24
+ });
25
+ const [fileName, setFileName] = useState("");
26
+ const handleImageSubmit = () => {
27
+ console.log("Image Submit Button is pressed");
28
+ console.log(prevImages);
29
+ onImageSubmit(prevImages.third);
30
+ setOpen(false);
31
+ };
32
+ const rotateImage = (angle) => {
33
+ setRotationAngle((prevAngle) => prevAngle + angle);
34
+ };
35
+ const handleMoveUp = () => {
36
+ setMoveDirection({ x: 0, y: -5 });
37
+ };
38
+ const handleMoveDown = () => {
39
+ setMoveDirection({ x: 0, y: 5 });
40
+ };
41
+ const handleMoveLeft = () => {
42
+ setMoveDirection({ x: -5, y: 0 });
43
+ };
44
+ const handleMoveRight = () => {
45
+ setMoveDirection({ x: 5, y: 0 });
46
+ };
47
+ // Handle zoom in
48
+ const zoomIn = () => {
49
+ setScale((prevScale) => {
50
+ const newScale = prevScale + 0.2;
51
+ if (newScale <= 2) {
52
+ // Ensure scale does not exceed the max value
53
+ return newScale;
54
+ }
55
+ return prevScale;
56
+ });
57
+ };
58
+ // Handle zoom out
59
+ const zoomOut = () => {
60
+ setScale((prevScale) => {
61
+ const newScale = prevScale - 0.2;
62
+ if (newScale >= 0.2) {
63
+ // Ensure scale does not go below the min value
64
+ return newScale;
65
+ }
66
+ return prevScale;
67
+ });
68
+ };
69
+ const handleAspectRatioChange = (ratio, stateName) => {
70
+ setAspectRatio(ratio);
71
+ setActiveState(stateName);
72
+ };
73
+ const handleFileChange = (file) => {
74
+ if (file.type.startsWith("image/")) {
75
+ const reader = new FileReader();
76
+ reader.onloadend = () => {
77
+ setImageSrc(reader.result);
78
+ setFileName((prev) => prev || file.name);
79
+ };
80
+ reader.readAsDataURL(file);
81
+ }
82
+ else {
83
+ alert("Please drop a valid image file.");
84
+ }
85
+ };
86
+ const handleDrop = (event) => {
87
+ event.preventDefault();
88
+ handleFileChange(event.dataTransfer.files[0]);
89
+ };
90
+ const getImagePreview = (state) => {
91
+ const imgSource = croppedImage && activeState === state ? croppedImage : prevImages[state];
92
+ // const imgSource = prevImages[state];
93
+ return imgSource ? (_jsx("div", { className: `
94
+ ${state === "first"
95
+ ? "relative w-3/5 h-[200px] bg-slate-400"
96
+ : state === "second"
97
+ ? "relative w-1/2 h-[220px] bg-slate-400"
98
+ : "relative w-1/3 h-[120px] bg-slate-400"}`, children: _jsx(Image, { src: imgSource || "", alt: `Preview ${state}`, layout: "fill", objectFit: "70vh" }) })) : (_jsx("div", { className: `
99
+ ${state === "first"
100
+ ? "relative w-3/5 h-[200px] bg-slate-400"
101
+ : state === "second"
102
+ ? "relative w-1/2 h-[220px] bg-slate-400"
103
+ : "relative w-1/3 h-[120px] bg-slate-400"}` }));
104
+ };
105
+ useEffect(() => {
106
+ if (croppedImage) {
107
+ if (prevImages.first === null ||
108
+ prevImages.second === null ||
109
+ prevImages.third === null) {
110
+ setPrevImages({
111
+ first: croppedImage,
112
+ second: croppedImage,
113
+ third: croppedImage,
114
+ });
115
+ }
116
+ else {
117
+ setPrevImages((prev) => (Object.assign(Object.assign({}, prev), { [activeState]: croppedImage })));
118
+ }
119
+ }
120
+ }, [croppedImage]);
121
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-row gap-2", children: [_jsxs("div", { className: "flex-1", children: [_jsx(Label, { htmlFor: "imageName", children: "Image Name" }), _jsx(Input, { id: "imageName", placeholder: "Enter image name", value: fileName, onChange: (e) => setFileName(e.target.value) })] }), _jsxs("div", { className: "self-end", children: [_jsx(Button, { variant: "outline", onClick: () => { var _a; return (_a = document.getElementById("inputImage1")) === null || _a === void 0 ? void 0 : _a.click(); }, children: _jsx(Upload, {}) }), _jsx(Input, { id: "inputImage1", type: "file", accept: "image/png, image/jpeg", className: "hidden", onChange: (e) => {
122
+ var _a;
123
+ const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
124
+ if (file && file.type.startsWith("image/")) {
125
+ const reader = new FileReader();
126
+ reader.onloadend = () => {
127
+ setImageSrc(reader.result);
128
+ setFileName((prevFileName) => prevFileName || file.name);
129
+ };
130
+ reader.readAsDataURL(file);
131
+ setPrevImages({
132
+ first: null,
133
+ second: null,
134
+ third: null,
135
+ });
136
+ }
137
+ } })] }), _jsxs("div", { className: "flex-1", children: [_jsx(Label, { htmlFor: "imageDesc", children: "Image Description" }), _jsx(Input, { id: "imageDesc", placeholder: "Describe your image" })] })] }), _jsxs("div", { className: "flex flex-row gap-2", children: [_jsx("div", { className: "w-3/5 flex justify-center items-center border-2 border-dashed border-gray-400 bg-gray-100", style: { height: "70vh" }, onDrop: handleDrop, onDragOver: (e) => e.preventDefault(), children: imageSrc ? (_jsx(NewCropperImg, { imageSrc: imageSrc, onCroppedImage: setCroppedImage, aspectRatio: aspectRatio, rotationAngle: rotationAngle, zoomLevel: scale, moveDirection: moveDirection, currentState: activeState })) : (_jsxs("div", { className: "text-center", children: [_jsx(Label, { htmlFor: "inputImage", children: "Drag and drop an image here" }), _jsxs("div", { className: "mt-4", children: [_jsx(Button, { variant: "outline", onClick: () => { var _a; return (_a = document.getElementById("inputImage")) === null || _a === void 0 ? void 0 : _a.click(); }, children: "Upload Image" }), _jsx(Input, { id: "inputImage", type: "file", accept: "image/png, image/jpeg", className: "hidden", onChange: (e) => {
138
+ var _a;
139
+ const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
140
+ if (file) {
141
+ handleFileChange(file);
142
+ }
143
+ } })] })] })) }), _jsxs("div", { className: "w-2/5 flex flex-col gap-2", children: [_jsx("h3", { children: "Landscape" }), getImagePreview("first"), _jsx("h3", { children: "Potrait" }), getImagePreview("second"), _jsx("h3", { children: "Icon" }), getImagePreview("third")] })] }), _jsxs("div", { className: "flex flex-row gap-1", children: [_jsxs("div", { className: "w-3/5 flex flex-row justify-between", children: [_jsxs("div", { children: [_jsx(Button, { variant: "outline", onClick: () => handleAspectRatioChange(4 / 3, "first"), children: _jsx(ImageIcon, {}) }), _jsx(Button, { variant: "outline", onClick: () => handleAspectRatioChange(3 / 4, "second"), children: _jsx(FileImage, {}) }), _jsx(Button, { variant: "outline", onClick: () => handleAspectRatioChange(1 / 1, "third"), children: _jsx(Square, {}) })] }), _jsxs("div", { children: [_jsx(Button, { onClick: () => rotateImage(90), variant: "outline", children: _jsx(RotateCw, {}) }), _jsx(Button, { onClick: () => rotateImage(-90), variant: "outline", children: _jsx(RotateCcw, {}) })] }), _jsxs("div", { children: [_jsx(Button, { onClick: () => zoomIn(), variant: "outline", children: _jsx(ZoomIn, {}) }), _jsx(Button, { onClick: () => zoomOut(), variant: "outline", children: _jsx(ZoomOut, {}) })] }), _jsxs("div", { children: [_jsx(Button, { onClick: handleMoveUp, variant: "outline", children: _jsx(ArrowUp, {}) }), _jsx(Button, { onClick: handleMoveDown, variant: "outline", children: _jsx(ArrowDown, {}) }), _jsx(Button, { onClick: handleMoveLeft, variant: "outline", children: _jsx(ArrowLeft, {}) }), _jsx(Button, { onClick: handleMoveRight, variant: "outline", children: _jsx(ArrowRight, {}) })] })] }), _jsx("div", { className: "w-2/5 flex flex-row-reverse", children: _jsx(Button, { onClick: handleImageSubmit, children: "Save" }) })] })] }));
144
+ };
145
+ export const NewImageForm = memo(NewImageFormComponent);
@@ -0,0 +1,6 @@
1
+ interface Props {
2
+ onNewFileUpload?: (...args: any) => void;
3
+ }
4
+ declare function CropperFormComponent({ onNewFileUpload }: Props): import("react/jsx-runtime").JSX.Element;
5
+ export declare const CropperForm: import("react").MemoExoticComponent<typeof CropperFormComponent>;
6
+ export {};
@@ -0,0 +1,92 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Input } from '../../../shadcn/input';
3
+ import { Label } from '../../../shadcn/label';
4
+ import { ToggleGroup, ToggleGroupItem } from '../../../shadcn/toggle-group';
5
+ import { ArrowDown, ArrowLeft, ArrowRight, ArrowUp, FileImage, ImageIcon, RotateCcw, RotateCw, Square, ZoomIn, ZoomOut } from 'lucide-react';
6
+ import { memo, useEffect, useState } from 'react';
7
+ import { ImageCropper } from '../image-cropper';
8
+ import Image from 'next/image';
9
+ import { AspectRatio } from '../../../shadcn/aspect-ratio';
10
+ import { TextButton } from '../../buttons';
11
+ import { toast } from 'sonner';
12
+ import { FileInput } from '../../file-input';
13
+ import { useImageCropper } from '..';
14
+ const stateWiseAspectRatio = {
15
+ landscape: 4 / 3,
16
+ potrait: 3 / 4,
17
+ icon: 1 / 1
18
+ };
19
+ function CropperFormComponent({ onNewFileUpload }) {
20
+ const { originalImage, setOriginalImage, aspectRatioWiseImages, setAspectRatioWiseImages } = useImageCropper();
21
+ const [croppedImage, setCroppedImage] = useState(null);
22
+ const [activeState, setActiveState] = useState();
23
+ const [rotationAngle, setRotationAngle] = useState(0);
24
+ const [scale, setScale] = useState(1);
25
+ const [moveDirection, setMoveDirection] = useState({
26
+ x: 0,
27
+ y: 0,
28
+ });
29
+ const [imageSrc, setImageSrc] = useState(null);
30
+ const handleDrop = (event) => {
31
+ event.preventDefault();
32
+ handleFileChange(event.dataTransfer.files[0]);
33
+ };
34
+ const handleFileChange = (file) => {
35
+ var _a;
36
+ if (typeof file === "string") {
37
+ setImageSrc(file);
38
+ }
39
+ else {
40
+ if ((_a = file === null || file === void 0 ? void 0 : file.type) === null || _a === void 0 ? void 0 : _a.startsWith("image/")) {
41
+ onNewFileUpload === null || onNewFileUpload === void 0 ? void 0 : onNewFileUpload();
42
+ const reader = new FileReader();
43
+ reader.onloadend = () => {
44
+ setImageSrc(reader.result);
45
+ setActiveState(undefined);
46
+ };
47
+ reader.readAsDataURL(file);
48
+ setOriginalImage(Object.assign(Object.assign({}, originalImage), { image: file, name: file.name }));
49
+ }
50
+ else {
51
+ toast.error("Please select a valid image file.");
52
+ }
53
+ }
54
+ };
55
+ useEffect(() => {
56
+ if (originalImage.image) {
57
+ handleFileChange(originalImage.image);
58
+ }
59
+ }, [originalImage.image]);
60
+ const getImagePreview = (state) => {
61
+ const imgSource = croppedImage && activeState === state ? croppedImage : aspectRatioWiseImages[state];
62
+ return (_jsxs(_Fragment, { children: [_jsx("h3", { className: 'mb-3', children: state }), _jsx(AspectRatio, { ratio: stateWiseAspectRatio[state], className: 'bg-muted', children: imgSource &&
63
+ _jsx(Image, { src: imgSource || "", alt: `Preview ${state}`, fill: true }) })] }));
64
+ };
65
+ useEffect(() => {
66
+ if (croppedImage) {
67
+ if (activeState) {
68
+ setAspectRatioWiseImages(Object.assign(Object.assign({}, aspectRatioWiseImages), { [activeState]: croppedImage }));
69
+ }
70
+ else {
71
+ setAspectRatioWiseImages({
72
+ landscape: croppedImage,
73
+ potrait: croppedImage,
74
+ icon: croppedImage
75
+ });
76
+ }
77
+ }
78
+ }, [croppedImage]);
79
+ return (_jsx(_Fragment, { children: _jsxs("div", { className: 'flex flex-col gap-3 h-full overflow-auto', children: [_jsxs("div", { className: 'flex flex-col lg:flex-row gap-3 justify-between', children: [_jsxs("div", { className: 'w-full flex flex-col gap-4', children: [_jsx(Label, { htmlFor: "imageName", children: "Image Name" }), _jsx(FileInput, { id: "inputImage", accept: "image/*", fileNamePlaceholder: "Enter image name", fileName: (originalImage === null || originalImage === void 0 ? void 0 : originalImage.name) || "", onChange: (e) => {
80
+ var _a;
81
+ const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
82
+ if (file) {
83
+ handleFileChange(file);
84
+ }
85
+ }, onFileNameChange: (e) => {
86
+ setOriginalImage(Object.assign(Object.assign({}, originalImage), { name: e.target.value }));
87
+ } })] }), _jsxs("div", { className: 'w-full flex flex-col gap-4', children: [_jsx(Label, { htmlFor: "imageDescription", children: "Image Description" }), _jsx(Input, { id: "imageDescription", placeholder: "Enter image Description", value: (originalImage === null || originalImage === void 0 ? void 0 : originalImage.description) || "", onChange: (e) => setOriginalImage(Object.assign(Object.assign({}, originalImage), { description: e.target.value })) })] })] }), _jsxs("div", { className: 'flex flex-col lg:flex-row gap-3', children: [_jsxs("div", { className: 'flex-grow flex flex-col gap-3', children: [_jsxs("div", { children: [_jsx("h3", { className: 'mb-3', children: "Original Image" }), _jsx(AspectRatio, { ratio: 4 / 3, className: 'flex justify-center items-center bg-muted text-muted-foreground', onDrop: handleDrop, onDragOver: (e) => e.preventDefault(), children: imageSrc ?
88
+ _jsx(ImageCropper, { src: imageSrc, onCroppedImage: setCroppedImage, aspectRatio: stateWiseAspectRatio[activeState || "icon"], rotationAngle: rotationAngle, zoomLevel: scale, moveDirection: moveDirection })
89
+ :
90
+ _jsxs("div", { className: "text-center", children: [_jsx(Label, { htmlFor: "inputImage", children: "Drag and drop an image here" }), _jsx("div", { className: "mt-3", children: _jsx(TextButton, { variant: "outline", onClick: () => { var _a; return (_a = document.getElementById("inputImage")) === null || _a === void 0 ? void 0 : _a.click(); }, children: "Browse Image" }) })] }) })] }), _jsxs("div", { className: "flex flex-col lg:flex-row gap-3 justify-between", children: [_jsx("div", { children: _jsxs(ToggleGroup, { type: "single", variant: 'outline', value: activeState, onValueChange: (value) => setActiveState(value), children: [_jsx(ToggleGroupItem, { className: "rounded-e-none", value: "landscape", children: _jsx(ImageIcon, {}) }), _jsx(ToggleGroupItem, { className: "rounded-none border-x-0", value: "potrait", children: _jsx(FileImage, {}) }), _jsx(ToggleGroupItem, { className: 'rounded-s-none', value: "icon", children: _jsx(Square, {}) })] }) }), _jsxs("div", { className: 'flex flex-col lg:flex-row gap-3 justify-between', children: [_jsxs(ToggleGroup, { type: "single", variant: 'outline', value: "", onValueChange: (value) => setRotationAngle(parseInt(value)), children: [_jsx(ToggleGroupItem, { className: "rounded-e-none", value: "90", children: _jsx(RotateCw, {}) }), _jsx(ToggleGroupItem, { className: 'rounded-s-none border-s-0', value: "-90", children: _jsx(RotateCcw, {}) })] }), _jsxs(ToggleGroup, { type: "single", variant: 'outline', value: '', children: [_jsx(ToggleGroupItem, { className: "rounded-e-none", value: "up", onClick: () => setMoveDirection({ x: 0, y: -5 }), children: _jsx(ArrowUp, {}) }), _jsx(ToggleGroupItem, { className: "rounded-none border-x-0", value: "down", onClick: () => setMoveDirection({ x: 0, y: 5 }), children: _jsx(ArrowDown, {}) }), _jsx(ToggleGroupItem, { className: 'rounded-none border-e-0', value: "left", onClick: () => setMoveDirection({ x: -5, y: 0 }), children: _jsx(ArrowLeft, {}) }), _jsx(ToggleGroupItem, { className: 'rounded-s-none', value: "right", onClick: () => setMoveDirection({ x: 5, y: 0 }), children: _jsx(ArrowRight, {}) })] }), _jsxs(ToggleGroup, { type: "single", variant: 'outline', value: "", onValueChange: (value) => setScale(pre => pre + parseFloat(value)), children: [_jsx(ToggleGroupItem, { className: "rounded-e-none", value: "0.1", children: _jsx(ZoomIn, {}) }), _jsx(ToggleGroupItem, { className: 'rounded-s-none border-s-0', value: "-0.1", children: _jsx(ZoomOut, {}) })] })] })] })] }), _jsxs("div", { className: "flex flex-row lg:flex-col gap-3 w-full lg:w-48", children: [_jsx("div", { className: 'w-5/5', children: getImagePreview("landscape") }), _jsx("div", { className: 'w-4/5', children: getImagePreview("potrait") }), _jsx("div", { className: 'w-3/5', children: getImagePreview("icon") })] })] })] }) }));
91
+ }
92
+ export const CropperForm = memo(CropperFormComponent);
@@ -0,0 +1,6 @@
1
+ import { AspectRatioWiseImagesProps, OriginalImageProps } from '..';
2
+ export declare function CropperFormWithModal({ open, onOpenChange, onCropperChange }: Readonly<{
3
+ open: boolean;
4
+ onOpenChange: (open: boolean) => void;
5
+ onCropperChange: (originalImage: OriginalImageProps, aspectRatioWiseImages: AspectRatioWiseImagesProps) => void;
6
+ }>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '../../../shadcn/dialog';
3
+ import { CropperForm } from '../cropper-form';
4
+ import { TextButton } from '../../buttons';
5
+ import { useImageCropper } from '..';
6
+ export function CropperFormWithModal({ open, onOpenChange, onCropperChange }) {
7
+ const { originalImage, aspectRatioWiseImages } = useImageCropper();
8
+ return (_jsx(Dialog, { modal: true, open: open, onOpenChange: (isOpen) => {
9
+ onOpenChange(isOpen);
10
+ }, children: _jsxs(DialogContent, { className: "max-w-full lg:max-w-5xl max-h-full overflow-auto", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: "Image to upload" }) }), _jsx(CropperForm, {}), _jsx(DialogFooter, { children: _jsx(TextButton, { onClick: () => {
11
+ onCropperChange(originalImage, aspectRatioWiseImages);
12
+ onOpenChange(false);
13
+ }, children: "Save Changes" }) })] }) }));
14
+ }
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+ import "cropperjs/dist/cropper.css";
3
+ export interface CropperImgProps {
4
+ src: string | undefined;
5
+ onCroppedImage: (imageUrl: string) => void;
6
+ aspectRatio: number;
7
+ rotationAngle: number;
8
+ zoomLevel: number;
9
+ moveDirection: {
10
+ x: number;
11
+ y: number;
12
+ };
13
+ }
14
+ export declare const ImageCropper: React.NamedExoticComponent<CropperImgProps>;