@sirendesign/markup 1.0.8 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -850,6 +850,7 @@ const initialState = {
850
850
  config: defaultConfig,
851
851
  currentUser: null,
852
852
  isAuthenticated: false,
853
+ viewportMode: null,
853
854
  };
854
855
  const useMarkupStore = create()(persist((set, get) => ({
855
856
  ...initialState,
@@ -857,6 +858,7 @@ const useMarkupStore = create()(persist((set, get) => ({
857
858
  setIsCapturing: (isCapturing) => set({ isCapturing }),
858
859
  setIsAnnotating: (isAnnotating) => set({ isAnnotating }),
859
860
  setCurrentScreenshot: (screenshot) => set({ currentScreenshot: screenshot }),
861
+ setAnnotations: (annotations) => set({ annotations }),
860
862
  addAnnotation: (annotation) => set((state) => ({
861
863
  annotations: [...state.annotations, annotation],
862
864
  })),
@@ -895,6 +897,7 @@ const useMarkupStore = create()(persist((set, get) => ({
895
897
  console.log('Store: Setting authenticated:', isAuthenticated);
896
898
  set({ isAuthenticated });
897
899
  },
900
+ setViewportMode: (mode) => set({ viewportMode: mode }),
898
901
  addComment: (feedbackId, comment) => set((state) => ({
899
902
  feedbackItems: state.feedbackItems.map((f) => f.id === feedbackId
900
903
  ? { ...f, comments: [...f.comments, comment], updatedAt: new Date().toISOString() }
@@ -8740,7 +8743,65 @@ var parseBackgroundColor = function (context, element, backgroundColorOverride)
8740
8743
  : defaultBackgroundColor;
8741
8744
  };
8742
8745
 
8743
- async function captureScreenshot() {
8746
+ const identifyComponent = (element) => {
8747
+ var _a, _b;
8748
+ if (!element)
8749
+ return undefined;
8750
+ let current = element;
8751
+ const depth = 5; // Search up 5 levels
8752
+ for (let i = 0; i < depth; i++) {
8753
+ if (!current)
8754
+ break;
8755
+ // 1. Check for data-component attribute (common pattern)
8756
+ if (current.getAttribute('data-component')) {
8757
+ return current.getAttribute('data-component') || undefined;
8758
+ }
8759
+ // 2. Check for data-testid
8760
+ if (current.getAttribute('data-testid')) {
8761
+ return current.getAttribute('data-testid') || undefined;
8762
+ }
8763
+ // 3. React DevTools internals (brittle, but sometimes works)
8764
+ // @ts-ignore
8765
+ const key = Object.keys(current).find(k => k.startsWith('__reactFiber$'));
8766
+ if (key) {
8767
+ // @ts-ignore
8768
+ const fiber = current[key];
8769
+ if ((_a = fiber === null || fiber === void 0 ? void 0 : fiber.type) === null || _a === void 0 ? void 0 : _a.displayName) {
8770
+ return fiber.type.displayName;
8771
+ }
8772
+ if ((_b = fiber === null || fiber === void 0 ? void 0 : fiber.type) === null || _b === void 0 ? void 0 : _b.name) {
8773
+ return fiber.type.name;
8774
+ }
8775
+ }
8776
+ // 4. ID or specific classes
8777
+ if (current.id)
8778
+ return `#${current.id}`;
8779
+ if (current.parentElement) {
8780
+ current = current.parentElement;
8781
+ }
8782
+ else {
8783
+ break;
8784
+ }
8785
+ }
8786
+ return undefined;
8787
+ };
8788
+ const getElementInfo = (element) => {
8789
+ if (!element)
8790
+ return undefined;
8791
+ const tagName = element.tagName.toLowerCase();
8792
+ const classes = element.className && typeof element.className === 'string'
8793
+ ? element.className.split(' ').filter(c => c.trim()).slice(0, 3).join(' ')
8794
+ : '';
8795
+ let info = `<${tagName}`;
8796
+ if (element.id)
8797
+ info += ` id="${element.id}"`;
8798
+ if (classes)
8799
+ info += ` class="${classes}"`;
8800
+ info += '>';
8801
+ return info;
8802
+ };
8803
+
8804
+ async function captureScreenshot(clickElement) {
8744
8805
  try {
8745
8806
  // Hide the markup widget before capturing
8746
8807
  const widget = document.querySelector('[data-markup-widget]');
@@ -8753,6 +8814,12 @@ async function captureScreenshot() {
8753
8814
  scale: window.devicePixelRatio,
8754
8815
  logging: false,
8755
8816
  backgroundColor: null,
8817
+ width: window.innerWidth,
8818
+ height: window.innerHeight,
8819
+ x: window.scrollX,
8820
+ y: window.scrollY,
8821
+ windowWidth: window.innerWidth,
8822
+ windowHeight: window.innerHeight,
8756
8823
  ignoreElements: (element) => {
8757
8824
  return element.hasAttribute('data-markup-widget');
8758
8825
  },
@@ -8768,7 +8835,20 @@ async function captureScreenshot() {
8768
8835
  throw error;
8769
8836
  }
8770
8837
  }
8771
- function getPageMetadata() {
8838
+ const detectDeviceType = () => {
8839
+ const width = window.innerWidth;
8840
+ const userAgent = navigator.userAgent.toLowerCase();
8841
+ // Check user agent for mobile/tablet indicators
8842
+ const isMobileUA = /mobile|android|iphone|ipod|blackberry|iemobile|opera mini/i.test(userAgent);
8843
+ const isTabletUA = /tablet|ipad|playbook|silk|kindle/i.test(userAgent);
8844
+ // Prioritize user agent, then fall back to screen width
8845
+ if (isMobileUA && width < 768)
8846
+ return 'mobile';
8847
+ if (isTabletUA || (width >= 768 && width < 1024))
8848
+ return 'tablet';
8849
+ return 'desktop';
8850
+ };
8851
+ function getPageMetadata(clickElement) {
8772
8852
  return {
8773
8853
  url: window.location.href,
8774
8854
  title: document.title,
@@ -8777,6 +8857,9 @@ function getPageMetadata() {
8777
8857
  devicePixelRatio: window.devicePixelRatio,
8778
8858
  userAgent: navigator.userAgent,
8779
8859
  timestamp: new Date().toISOString(),
8860
+ deviceType: detectDeviceType(),
8861
+ componentName: clickElement ? identifyComponent(clickElement) : undefined,
8862
+ elementInfo: clickElement ? getElementInfo(clickElement) : undefined,
8780
8863
  };
8781
8864
  }
8782
8865
  function getElementSelector(element) {
@@ -11446,6 +11529,7 @@ const UndoIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { classNam
11446
11529
  const CheckIcon = ({ className, ...props }) => (jsxRuntime.jsx("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) }));
11447
11530
  const TrashIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("polyline", { points: "3 6 5 6 21 6" }), jsxRuntime.jsx("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })] }));
11448
11531
  const EditIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("path", { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" }), jsxRuntime.jsx("path", { d: "M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" })] }));
11532
+ const CopyIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }), jsxRuntime.jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })] }));
11449
11533
  const InboxIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("polyline", { points: "22 12 16 12 14 15 10 15 8 12 2 12" }), jsxRuntime.jsx("path", { d: "M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" })] }));
11450
11534
  const SendIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }), jsxRuntime.jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })] }));
11451
11535
  const PlusIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }), jsxRuntime.jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })] }));
@@ -11458,6 +11542,9 @@ const UserIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { classNam
11458
11542
  const ZoomInIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("circle", { cx: "11", cy: "11", r: "8" }), jsxRuntime.jsx("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" }), jsxRuntime.jsx("line", { x1: "11", y1: "8", x2: "11", y2: "14" }), jsxRuntime.jsx("line", { x1: "8", y1: "11", x2: "14", y2: "11" })] }));
11459
11543
  const CalendarIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }), jsxRuntime.jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }), jsxRuntime.jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }), jsxRuntime.jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" })] }));
11460
11544
  const ChevronRightIcon = ({ className, ...props }) => (jsxRuntime.jsx("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: jsxRuntime.jsx("polyline", { points: "9 18 15 12 9 6" }) }));
11545
+ const DesktopIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2", ry: "2" }), jsxRuntime.jsx("line", { x1: "8", y1: "21", x2: "16", y2: "21" }), jsxRuntime.jsx("line", { x1: "12", y1: "17", x2: "12", y2: "21" })] }));
11546
+ const TabletIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("rect", { x: "5", y: "2", width: "14", height: "20", rx: "2", ry: "2" }), jsxRuntime.jsx("line", { x1: "12", y1: "18", x2: "12.01", y2: "18" })] }));
11547
+ const MobileIcon = ({ className, ...props }) => (jsxRuntime.jsxs("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [jsxRuntime.jsx("rect", { x: "7", y: "2", width: "10", height: "20", rx: "2", ry: "2" }), jsxRuntime.jsx("line", { x1: "12", y1: "18", x2: "12.01", y2: "18" })] }));
11461
11548
 
11462
11549
  const tools = [
11463
11550
  { id: 'pen', icon: PencilIcon, label: 'Draw' },
@@ -11774,22 +11861,43 @@ const AnnotationOverlay = ({ screenshot, onComplete, onCancel, }) => {
11774
11861
  : 'Click and drag to annotate • Use tools above to switch modes' })] }), document.body);
11775
11862
  };
11776
11863
 
11777
- const FeedbackForm = ({ onSubmit, onCancel, }) => {
11864
+ const FeedbackForm = ({ onSubmit, onCancel, initialData, getSessionEvents, lastClickedElement, lastClickedText, }) => {
11778
11865
  var _a, _b;
11779
- const { config, currentScreenshot, setCurrentScreenshot, annotations, clearAnnotations, setIsCapturing, isCapturing, currentUser, } = useMarkupStore();
11780
- const [title, setTitle] = require$$0.useState("");
11781
- const [description, setDescription] = require$$0.useState("");
11782
- const [priority, setPriority] = require$$0.useState("medium");
11783
- const [feedbackType, setFeedbackType] = require$$0.useState("general");
11784
- const [currentCopy, setCurrentCopy] = require$$0.useState("");
11785
- const [newCopy, setNewCopy] = require$$0.useState("");
11786
- const [selectedTags, setSelectedTags] = require$$0.useState([]);
11866
+ const { config, currentScreenshot, setCurrentScreenshot, annotations, setAnnotations, clearAnnotations, setIsCapturing, isCapturing, currentUser, } = useMarkupStore();
11867
+ const [title, setTitle] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.title) || "");
11868
+ const [description, setDescription] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.description) || "");
11869
+ const [priority, setPriority] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.priority) || "medium");
11870
+ const [feedbackType, setFeedbackType] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.type) || "general");
11871
+ const [currentCopy, setCurrentCopy] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.currentCopy) || "");
11872
+ const [newCopy, setNewCopy] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.newCopy) || "");
11873
+ const [designMockup, setDesignMockup] = require$$0.useState(initialData === null || initialData === void 0 ? void 0 : initialData.designMockup);
11874
+ const [selectedTags, setSelectedTags] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.tags) || []);
11787
11875
  const [isAnnotating, setIsAnnotating] = require$$0.useState(false);
11788
11876
  const [isSubmitting, setIsSubmitting] = require$$0.useState(false);
11789
- const [annotatedScreenshot, setAnnotatedScreenshot] = require$$0.useState(null);
11790
- // Auto-capture selected text when component mounts
11877
+ const [annotatedScreenshot, setAnnotatedScreenshot] = require$$0.useState((initialData === null || initialData === void 0 ? void 0 : initialData.screenshot) || null);
11878
+ // Screen recording states
11879
+ const [isRecording, setIsRecording] = require$$0.useState(false);
11880
+ const [recordedVideo, setRecordedVideo] = require$$0.useState(initialData === null || initialData === void 0 ? void 0 : initialData.screenRecording);
11881
+ const [mediaRecorder, setMediaRecorder] = require$$0.useState(null);
11882
+ const [recordingStream, setRecordingStream] = require$$0.useState(null);
11883
+ // Load initial annotations into store if editing
11884
+ require$$0.useEffect(() => {
11885
+ if (initialData === null || initialData === void 0 ? void 0 : initialData.annotations) {
11886
+ setAnnotations(initialData.annotations);
11887
+ }
11888
+ }, [initialData, setAnnotations]);
11889
+ // Auto-capture selected text when component mounts (only if creating new)
11791
11890
  require$$0.useEffect(() => {
11792
11891
  var _a;
11892
+ if (initialData)
11893
+ return;
11894
+ // First check if user clicked on text element
11895
+ if (lastClickedText && lastClickedText.length > 0) {
11896
+ setCurrentCopy(lastClickedText);
11897
+ setFeedbackType("copy-amendment");
11898
+ return;
11899
+ }
11900
+ // Fallback to selected text
11793
11901
  const selectedText = (_a = window.getSelection()) === null || _a === void 0 ? void 0 : _a.toString().trim();
11794
11902
  if (selectedText &&
11795
11903
  selectedText.length > 0 &&
@@ -11797,7 +11905,7 @@ const FeedbackForm = ({ onSubmit, onCancel, }) => {
11797
11905
  setCurrentCopy(selectedText);
11798
11906
  setFeedbackType("copy-amendment");
11799
11907
  }
11800
- }, []);
11908
+ }, [initialData, lastClickedText]);
11801
11909
  const handleCaptureScreenshot = async () => {
11802
11910
  try {
11803
11911
  setIsCapturing(true);
@@ -11812,6 +11920,57 @@ const FeedbackForm = ({ onSubmit, onCancel, }) => {
11812
11920
  setIsCapturing(false);
11813
11921
  }
11814
11922
  };
11923
+ const handleStartRecording = async () => {
11924
+ try {
11925
+ const stream = await navigator.mediaDevices.getDisplayMedia({
11926
+ video: { mediaSource: 'screen' },
11927
+ audio: false,
11928
+ });
11929
+ setRecordingStream(stream);
11930
+ const recorder = new MediaRecorder(stream, {
11931
+ mimeType: 'video/webm;codecs=vp8',
11932
+ });
11933
+ const chunks = [];
11934
+ recorder.ondataavailable = (e) => {
11935
+ if (e.data.size > 0) {
11936
+ chunks.push(e.data);
11937
+ }
11938
+ };
11939
+ recorder.onstop = () => {
11940
+ const blob = new Blob(chunks, { type: 'video/webm' });
11941
+ // Convert blob to base64 data URL for storage
11942
+ const reader = new FileReader();
11943
+ reader.onloadend = () => {
11944
+ const base64data = reader.result;
11945
+ setRecordedVideo(base64data);
11946
+ };
11947
+ reader.readAsDataURL(blob);
11948
+ // Stop all tracks
11949
+ stream.getTracks().forEach(track => track.stop());
11950
+ setRecordingStream(null);
11951
+ };
11952
+ recorder.start();
11953
+ setMediaRecorder(recorder);
11954
+ setIsRecording(true);
11955
+ }
11956
+ catch (error) {
11957
+ console.error('Failed to start recording:', error);
11958
+ alert('Screen recording is not supported or permission was denied.');
11959
+ }
11960
+ };
11961
+ const handleStopRecording = () => {
11962
+ if (mediaRecorder && mediaRecorder.state !== 'inactive') {
11963
+ mediaRecorder.stop();
11964
+ setIsRecording(false);
11965
+ }
11966
+ };
11967
+ const handleDeleteRecording = () => {
11968
+ setRecordedVideo(undefined);
11969
+ if (recordingStream) {
11970
+ recordingStream.getTracks().forEach(track => track.stop());
11971
+ setRecordingStream(null);
11972
+ }
11973
+ };
11815
11974
  const handleAnnotationComplete = (newAnnotations, screenshot) => {
11816
11975
  setAnnotatedScreenshot(screenshot);
11817
11976
  setIsAnnotating(false);
@@ -11834,6 +11993,23 @@ const FeedbackForm = ({ onSubmit, onCancel, }) => {
11834
11993
  const toggleTag = (tag) => {
11835
11994
  setSelectedTags((prev) => prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag]);
11836
11995
  };
11996
+ const priorityColors = {
11997
+ low: "bg-brand-green/30 text-gray-700",
11998
+ medium: "bg-brand-blue/50 text-gray-800",
11999
+ high: "bg-brand-pink/30 text-gray-800",
12000
+ critical: "bg-brand-pink text-gray-800",
12001
+ };
12002
+ const handleMockupUpload = (e) => {
12003
+ var _a;
12004
+ const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
12005
+ if (file) {
12006
+ const reader = new FileReader();
12007
+ reader.onloadend = () => {
12008
+ setDesignMockup(reader.result);
12009
+ };
12010
+ reader.readAsDataURL(file);
12011
+ }
12012
+ };
11837
12013
  const handleSubmit = async (e) => {
11838
12014
  var _a, _b, _c, _d;
11839
12015
  e.preventDefault();
@@ -11843,7 +12019,7 @@ const FeedbackForm = ({ onSubmit, onCancel, }) => {
11843
12019
  return;
11844
12020
  setIsSubmitting(true);
11845
12021
  const feedback = {
11846
- id: generateId(),
12022
+ id: (initialData === null || initialData === void 0 ? void 0 : initialData.id) || generateId(),
11847
12023
  type: feedbackType,
11848
12024
  title: title.trim() || (feedbackType === "copy-amendment" ? "Copy Amendment" : ""),
11849
12025
  description: description.trim(),
@@ -11853,19 +12029,22 @@ const FeedbackForm = ({ onSubmit, onCancel, }) => {
11853
12029
  newCopy: feedbackType === "copy-amendment" ? newCopy.trim() : undefined,
11854
12030
  screenshot: annotatedScreenshot || currentScreenshot || undefined,
11855
12031
  annotations: annotations,
11856
- status: "open",
12032
+ status: (initialData === null || initialData === void 0 ? void 0 : initialData.status) || "open",
11857
12033
  priority,
11858
- pageMetadata: getPageMetadata(),
11859
- createdAt: new Date().toISOString(),
12034
+ pageMetadata: (initialData === null || initialData === void 0 ? void 0 : initialData.pageMetadata) || getPageMetadata(lastClickedElement || undefined),
12035
+ createdAt: (initialData === null || initialData === void 0 ? void 0 : initialData.createdAt) || new Date().toISOString(),
11860
12036
  updatedAt: new Date().toISOString(),
11861
- createdBy: currentUser || {
12037
+ createdBy: (initialData === null || initialData === void 0 ? void 0 : initialData.createdBy) || currentUser || {
11862
12038
  id: ((_a = config.user) === null || _a === void 0 ? void 0 : _a.id) || "anonymous",
11863
12039
  name: ((_b = config.user) === null || _b === void 0 ? void 0 : _b.name) || "Anonymous",
11864
12040
  email: ((_c = config.user) === null || _c === void 0 ? void 0 : _c.email) || "",
11865
12041
  role: ((_d = config.user) === null || _d === void 0 ? void 0 : _d.role) || "default",
11866
12042
  },
11867
- comments: [],
12043
+ comments: (initialData === null || initialData === void 0 ? void 0 : initialData.comments) || [],
11868
12044
  tags: selectedTags,
12045
+ sessionEvents: getSessionEvents ? getSessionEvents() : undefined,
12046
+ designMockup,
12047
+ screenRecording: recordedVideo,
11869
12048
  };
11870
12049
  try {
11871
12050
  if (config.onSubmit) {
@@ -11895,7 +12074,9 @@ const FeedbackForm = ({ onSubmit, onCancel, }) => {
11895
12074
  { id: "copy-amendment", label: "Copy Change" },
11896
12075
  ].map((type) => (jsxRuntime.jsx("div", { onClick: () => setFeedbackType(type.id), className: cn("flex-1 py-2 px-3 rounded-xl text-xs font-medium cursor-pointer transition-all text-center", feedbackType === type.id
11897
12076
  ? "bg-[#C2D1D9] text-black shadow-md shadow-[#C2D1D9]/30"
11898
- : "bg-gray-100 text-gray-700 hover:bg-gray-200 hover:shadow-sm"), children: type.label }, type.id))) })] }), feedbackType === "copy-amendment" && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Current Copy" }), jsxRuntime.jsx("textarea", { placeholder: "Select text on page or paste current copy here...", value: currentCopy, onChange: (e) => setCurrentCopy(e.target.value), className: "w-full px-4 py-3 bg-red-50 border border-red-200 rounded-xl text-sm min-h-[80px] resize-y focus:outline-none focus:bg-white focus:border-red-500 focus:shadow-lg focus:shadow-red-500/10 transition-all" })] }), jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "New Copy *" }), jsxRuntime.jsx("textarea", { placeholder: "Enter the replacement text...", value: newCopy, onChange: (e) => setNewCopy(e.target.value), required: feedbackType === "copy-amendment", className: "w-full px-4 py-3 bg-green-50 border border-green-200 rounded-xl text-sm min-h-[80px] resize-y focus:outline-none focus:bg-white focus:border-green-500 focus:shadow-lg focus:shadow-green-500/10 transition-all" })] })] })), feedbackType !== "copy-amendment" && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Title *" }), jsxRuntime.jsx("input", { type: "text", placeholder: "Brief description of the issue", value: title, onChange: (e) => setTitle(e.target.value), required: true, className: "w-full px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-sm focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all" })] })), feedbackType !== "copy-amendment" && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Description" }), jsxRuntime.jsx("textarea", { placeholder: "Provide more details about the issue...", value: description, onChange: (e) => setDescription(e.target.value), className: "w-full px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-sm min-h-[100px] resize-y focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all" })] })), annotatedScreenshot || currentScreenshot ? (jsxRuntime.jsxs("div", { className: "relative rounded-xl overflow-hidden shadow-md mb-5 group", children: [jsxRuntime.jsx("img", { src: annotatedScreenshot || currentScreenshot || "", alt: "Screenshot", className: "w-full block" }), jsxRuntime.jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/40 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" }), jsxRuntime.jsxs("div", { className: "absolute top-3 right-3 flex gap-2", children: [jsxRuntime.jsxs("button", { type: "button", onClick: handleEditScreenshot, className: "bg-white text-gray-700 border-none px-3 py-1.5 rounded-lg cursor-pointer text-xs font-medium flex items-center gap-1.5 hover:bg-gray-100 shadow-lg transition-all", children: [jsxRuntime.jsx(EditIcon, { className: "w-3.5 h-3.5" }), " Edit"] }), jsxRuntime.jsxs("button", { type: "button", onClick: handleRemoveScreenshot, className: "bg-white text-red-600 border-none px-3 py-1.5 rounded-lg cursor-pointer text-xs font-medium flex items-center gap-1.5 hover:bg-red-50 shadow-lg transition-all", children: [jsxRuntime.jsx(TrashIcon, { className: "w-3.5 h-3.5" }), " Remove"] })] })] })) : (jsxRuntime.jsx("div", { onClick: handleCaptureScreenshot, className: "w-full p-4 bg-white border-2 border-dashed border-gray-300 rounded-xl cursor-pointer flex items-center justify-center gap-2.5 text-gray-600 text-sm font-medium mb-5 hover:border-indigo-400 hover:text-indigo-600 hover:bg-indigo-50 hover:shadow-md transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isCapturing ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: "w-5 h-5 border-2 border-indigo-200 border-t-indigo-600 rounded-full animate-spin" }), "Capturing..."] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(CameraIcon, { className: "w-5 h-5" }), " Capture Screenshot"] })) })), config.availableTags && config.availableTags.length > 0 && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Tags" }), jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: config.availableTags.map((tag) => (jsxRuntime.jsx("div", { onClick: () => toggleTag(tag), className: cn("px-3 py-1.5 rounded-full text-xs font-medium cursor-pointer transition-all", selectedTags.includes(tag)
12077
+ : "bg-gray-100 text-gray-700 hover:bg-gray-200 hover:shadow-sm"), children: type.label }, type.id))) })] }), feedbackType === "copy-amendment" && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Current Copy" }), jsxRuntime.jsx("textarea", { placeholder: "Select text on page or paste current copy here...", value: currentCopy, onChange: (e) => setCurrentCopy(e.target.value), className: "w-full px-4 py-3 bg-red-50 border border-red-200 rounded-xl text-sm min-h-[80px] resize-y focus:outline-none focus:bg-white focus:border-red-500 focus:shadow-lg focus:shadow-red-500/10 transition-all" })] }), jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "New Copy *" }), jsxRuntime.jsx("textarea", { placeholder: "Enter the replacement text...", value: newCopy, onChange: (e) => setNewCopy(e.target.value), required: feedbackType === "copy-amendment", className: "w-full px-4 py-3 bg-green-50 border border-green-200 rounded-xl text-sm min-h-[80px] resize-y focus:outline-none focus:bg-white focus:border-green-500 focus:shadow-lg focus:shadow-green-500/10 transition-all" })] })] })), feedbackType !== "copy-amendment" && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Title *" }), jsxRuntime.jsx("input", { type: "text", placeholder: "Brief description of the issue", value: title, onChange: (e) => setTitle(e.target.value), required: true, className: "w-full px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-sm focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all" })] })), feedbackType !== "copy-amendment" && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Description" }), jsxRuntime.jsx("textarea", { placeholder: "Provide more details about the issue...", value: description, onChange: (e) => setDescription(e.target.value), required: true, className: "w-full px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-sm focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all min-h-[100px] resize-y" })] })), jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Priority" }), jsxRuntime.jsx("div", { className: "flex gap-2", children: Object.keys(priorityColors).map((p) => (jsxRuntime.jsx("div", { onClick: () => setPriority(p), className: cn("flex-1 py-2 px-2 rounded-xl text-xs font-medium cursor-pointer transition-all text-center capitalize border border-transparent", priority === p
12078
+ ? cn(priorityColors[p], "border-transparent shadow-sm")
12079
+ : "bg-gray-100 text-gray-600 hover:bg-gray-200"), children: p }, p))) })] }), annotatedScreenshot || currentScreenshot ? (jsxRuntime.jsxs("div", { className: "relative rounded-xl overflow-hidden shadow-md mb-5 group", children: [jsxRuntime.jsx("img", { src: annotatedScreenshot || currentScreenshot || "", alt: "Screenshot", className: "w-full block" }), jsxRuntime.jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/40 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" }), jsxRuntime.jsxs("div", { className: "absolute top-3 right-3 flex gap-2", children: [jsxRuntime.jsxs("button", { type: "button", onClick: handleEditScreenshot, className: "bg-white text-gray-700 border-none px-3 py-1.5 rounded-lg cursor-pointer text-xs font-medium flex items-center gap-1.5 hover:bg-gray-100 shadow-lg transition-all", children: [jsxRuntime.jsx(EditIcon, { className: "w-3.5 h-3.5" }), " Edit"] }), jsxRuntime.jsxs("button", { type: "button", onClick: handleRemoveScreenshot, className: "bg-white text-red-600 border-none px-3 py-1.5 rounded-lg cursor-pointer text-xs font-medium flex items-center gap-1.5 hover:bg-red-50 shadow-lg transition-all", children: [jsxRuntime.jsx(TrashIcon, { className: "w-3.5 h-3.5" }), " Remove"] })] })] })) : (jsxRuntime.jsxs("div", { className: "flex gap-3 mb-5", children: [jsxRuntime.jsx("div", { onClick: handleCaptureScreenshot, className: "flex-1 p-4 bg-white border-2 border-dashed border-gray-300 rounded-xl cursor-pointer flex items-center justify-center gap-2.5 text-gray-600 text-sm font-medium hover:border-indigo-400 hover:text-indigo-600 hover:bg-indigo-50 hover:shadow-md transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isCapturing ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: "w-5 h-5 border-2 border-indigo-200 border-t-indigo-600 rounded-full animate-spin" }), "Capturing..."] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(CameraIcon, { className: "w-5 h-5" }), " Screenshot"] })) }), jsxRuntime.jsx("div", { onClick: isRecording ? handleStopRecording : handleStartRecording, className: "flex-1 p-4 bg-white border-2 border-dashed border-gray-300 rounded-xl cursor-pointer flex items-center justify-center gap-2.5 text-gray-600 text-sm font-medium hover:border-red-400 hover:text-red-600 hover:bg-red-50 hover:shadow-md transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isRecording ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: "w-2.5 h-2.5 bg-red-600 rounded-sm animate-pulse" }), "Stop Recording"] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", strokeWidth: "2" }), jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "4", fill: "currentColor" })] }), "Record Screen"] })) })] })), recordedVideo && (jsxRuntime.jsxs("div", { className: "mb-5 relative rounded-xl overflow-hidden shadow-md border border-gray-200", children: [jsxRuntime.jsx("video", { src: recordedVideo, controls: true, className: "w-full h-auto" }), jsxRuntime.jsx("button", { type: "button", onClick: handleDeleteRecording, className: "absolute top-2 right-2 bg-white text-red-500 p-1.5 rounded-lg shadow hover:bg-gray-100 cursor-pointer border-none", children: jsxRuntime.jsx(TrashIcon, { className: "w-3.5 h-3.5" }) })] })), jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Design Mockup" }), designMockup ? (jsxRuntime.jsxs("div", { className: "relative rounded-xl overflow-hidden shadow-md group border border-gray-200", children: [jsxRuntime.jsx("img", { src: designMockup, className: "w-full h-32 object-cover", alt: "Mockup" }), jsxRuntime.jsx("button", { type: "button", onClick: () => setDesignMockup(undefined), className: "absolute top-2 right-2 bg-white text-red-500 p-1.5 rounded-lg shadow hover:bg-gray-100 cursor-pointer border-none", children: jsxRuntime.jsx(TrashIcon, { className: "w-3.5 h-3.5" }) })] })) : (jsxRuntime.jsxs("div", { className: "border-2 border-dashed border-gray-200 rounded-xl p-4 bg-gray-50 flex items-center justify-center relative hover:bg-white hover:border-[#C2D1D9] transition-all", children: [jsxRuntime.jsx("input", { type: "file", accept: "image/*", onChange: handleMockupUpload, className: "absolute inset-0 opacity-0 cursor-pointer w-full h-full" }), jsxRuntime.jsxs("span", { className: "text-sm text-gray-500 flex items-center gap-2 font-medium", children: [jsxRuntime.jsx(PlusIcon, { className: "w-4 h-4" }), " Upload Mockup"] })] }))] }), config.availableTags && config.availableTags.length > 0 && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-sm font-semibold mb-2 text-gray-800", children: "Tags" }), jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: config.availableTags.map((tag) => (jsxRuntime.jsx("div", { onClick: () => toggleTag(tag), className: cn("px-3 py-1.5 rounded-full text-xs font-medium cursor-pointer transition-all", selectedTags.includes(tag)
11899
12080
  ? "bg-[#C2D1D9] text-white shadow-md shadow-[#C2D1D9]/30"
11900
12081
  : "bg-gray-100 text-gray-700 hover:bg-gray-200 hover:shadow-sm"), children: tag }, tag))) })] })), jsxRuntime.jsxs("div", { className: "flex gap-3 mt-6 pt-6 border-t border-gray-100", children: [jsxRuntime.jsx("div", { onClick: onCancel, className: "flex-1 py-3 px-5 rounded-xl text-sm font-semibold cursor-pointer transition-all bg-gray-100 text-gray-700 hover:bg-gray-200 hover:shadow-md text-center", children: ((_a = config.labels) === null || _a === void 0 ? void 0 : _a.cancelButton) || "Cancel" }), jsxRuntime.jsx("div", { onClick: (e) => {
11901
12082
  const isValid = feedbackType === "copy-amendment" ? newCopy.trim() : title.trim();
@@ -11914,7 +12095,7 @@ const FeedbackForm = ({ onSubmit, onCancel, }) => {
11914
12095
  backgroundColor: (feedbackType === "copy-amendment" ? !newCopy.trim() : !title.trim()) || isSubmitting
11915
12096
  ? "#9ca3af"
11916
12097
  : "green-500",
11917
- }, children: isSubmitting ? (jsxRuntime.jsx("span", { className: "w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin mx-auto block" })) : (((_b = config.labels) === null || _b === void 0 ? void 0 : _b.submitButton) || "Submit Feedback") })] })] }));
12098
+ }, children: isSubmitting ? (jsxRuntime.jsx("span", { className: "w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin mx-auto block" })) : (((_b = config.labels) === null || _b === void 0 ? void 0 : _b.submitButton) || (initialData ? "Update Feedback" : "Submit Feedback")) })] })] }));
11918
12099
  };
11919
12100
 
11920
12101
  const statusOptions$1 = [
@@ -11925,16 +12106,16 @@ const statusOptions$1 = [
11925
12106
  { value: "closed", label: "Closed" },
11926
12107
  ];
11927
12108
  const priorityColors$1 = {
11928
- low: "bg-gray-100 text-gray-700",
11929
- medium: "bg-yellow-100 text-yellow-800",
11930
- high: "bg-orange-100 text-orange-800",
11931
- critical: "bg-red-100 text-red-800",
12109
+ low: "bg-brand-green/30 text-gray-700",
12110
+ medium: "bg-brand-blue/50 text-gray-800",
12111
+ high: "bg-brand-pink/30 text-gray-800",
12112
+ critical: "bg-brand-pink text-gray-800",
11932
12113
  };
11933
12114
  const statusColors = {
11934
- open: "bg-blue-100 text-blue-800",
11935
- "in-progress": "bg-purple-100 text-purple-800",
11936
- resolved: "bg-green-100 text-green-800",
11937
- closed: "bg-gray-100 text-gray-600",
12115
+ open: "bg-brand-blue/50 text-gray-800",
12116
+ "in-progress": "bg-yellow-100 text-gray-800",
12117
+ resolved: "bg-brand-green/50 text-gray-900",
12118
+ closed: "bg-brand-pink/30 text-gray-800",
11938
12119
  };
11939
12120
  const FeedbackList = ({ feedbackItems, onSelectFeedback, }) => {
11940
12121
  const { config } = useMarkupStore();
@@ -11972,7 +12153,10 @@ const FeedbackList = ({ feedbackItems, onSelectFeedback, }) => {
11972
12153
  }, [feedbackItems, statusFilter, sortBy]);
11973
12154
  return (jsxRuntime.jsxs("div", { className: "flex flex-col h-full", children: [jsxRuntime.jsxs("div", { className: "flex gap-2 pb-4 mb-4", children: [jsxRuntime.jsxs("div", { className: "relative flex-1", children: [jsxRuntime.jsx(FilterIcon, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 pointer-events-none" }), jsxRuntime.jsx("select", { value: statusFilter, onChange: (e) => setStatusFilter(e.target.value), className: "w-full pl-9 pr-3 py-2.5 bg-gray-50 border border-gray-200 rounded-xl text-xs font-medium appearance-none focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all", children: statusOptions$1.map((option) => (jsxRuntime.jsx("option", { value: option.value, children: option.label }, option.value))) })] }), jsxRuntime.jsxs("div", { className: "relative flex-1", children: [jsxRuntime.jsx(CalendarIcon, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 pointer-events-none" }), jsxRuntime.jsxs("select", { value: sortBy, onChange: (e) => setSortBy(e.target.value), className: "w-full pl-9 pr-3 py-2.5 bg-gray-50 border border-gray-200 rounded-xl text-xs font-medium appearance-none focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all", children: [jsxRuntime.jsx("option", { value: "newest", children: "Newest First" }), jsxRuntime.jsx("option", { value: "oldest", children: "Oldest First" }), jsxRuntime.jsx("option", { value: "priority", children: "Priority" })] })] })] }), jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto -mx-1 px-1", children: filteredAndSortedItems.length === 0 ? (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-10 text-gray-400", children: [jsxRuntime.jsx(InboxIcon, { className: "w-12 h-12 mb-3 opacity-50" }), jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-500", children: "No feedback items" }), jsxRuntime.jsx("p", { className: "text-xs text-gray-400 mt-1", children: statusFilter !== "all"
11974
12155
  ? "Try changing the filter"
11975
- : "Be the first to add feedback!" })] })) : (jsxRuntime.jsx("div", { className: "flex flex-col gap-3", children: filteredAndSortedItems.map((item) => (jsxRuntime.jsxs("div", { onClick: () => onSelectFeedback(item), className: "w-full p-4 bg-white rounded-xl border border-gray-200 cursor-pointer text-left transition-all hover:shadow-lg hover:shadow-gray-200 hover:border-gray-300", children: [jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2 mb-2", children: [jsxRuntime.jsx("h4", { className: "text-sm font-semibold text-gray-900 m-0 flex-1 line-clamp-2", children: item.title }), jsxRuntime.jsx(ChevronRightIcon, { className: "w-4 h-4 text-gray-400 flex-shrink-0 mt-0.5" })] }), item.description && (jsxRuntime.jsx("p", { className: "text-xs text-gray-600 m-0 mb-3 line-clamp-2", children: item.description })), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [jsxRuntime.jsx("span", { className: cn("px-2.5 py-1 rounded-lg text-[10px] font-semibold uppercase tracking-wide", statusColors[item.status]), children: item.status.replace("-", " ") }), jsxRuntime.jsx("span", { className: cn("px-2.5 py-1 rounded-lg text-[10px] font-semibold uppercase tracking-wide", priorityColors$1[item.priority]), children: item.priority }), item.createdBy && (jsxRuntime.jsxs("span", { className: "text-[10px] text-gray-600 font-medium", children: ["by ", item.createdBy.name] })), jsxRuntime.jsx("span", { className: "text-[10px] text-gray-500 ml-auto font-medium", children: formatDate(item.createdAt) })] }), item.tags && item.tags.length > 0 && (jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1.5 mt-3", children: [item.tags.slice(0, 3).map((tag) => (jsxRuntime.jsx("span", { className: "px-2 py-1 bg-gray-100 text-gray-700 rounded-md text-[10px] font-medium", children: tag }, tag))), item.tags.length > 3 && (jsxRuntime.jsxs("span", { className: "px-2 py-1 text-gray-500 text-[10px] font-medium", children: ["+", item.tags.length - 3, " more"] }))] }))] }, item.id))) })) }), feedbackItems.length > 0 && (jsxRuntime.jsxs("div", { className: "pt-3 mt-3 border-t border-gray-200 text-xs text-gray-400 text-center", children: ["Showing ", filteredAndSortedItems.length, " of", " ", feedbackItems.length, " items"] }))] }));
12156
+ : "Be the first to add feedback!" })] })) : (jsxRuntime.jsx("div", { className: "flex flex-col gap-3", children: filteredAndSortedItems.map((item) => {
12157
+ var _a;
12158
+ return (jsxRuntime.jsxs("div", { onClick: () => onSelectFeedback(item), className: "w-full p-4 bg-white rounded-xl border border-gray-200 cursor-pointer text-left transition-all hover:shadow-lg hover:shadow-gray-200 hover:border-gray-300", children: [jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2 mb-2", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-1", children: [jsxRuntime.jsx("h4", { className: "text-sm font-semibold text-gray-900 m-0 flex-1 line-clamp-2", children: item.title }), ((_a = item.pageMetadata) === null || _a === void 0 ? void 0 : _a.deviceType) && (jsxRuntime.jsxs("div", { className: "flex-shrink-0", children: [item.pageMetadata.deviceType === 'desktop' && (jsxRuntime.jsx(DesktopIcon, { className: "w-4 h-4 text-gray-400", title: "Desktop" })), item.pageMetadata.deviceType === 'tablet' && (jsxRuntime.jsx(TabletIcon, { className: "w-4 h-4 text-gray-400", title: "Tablet" })), item.pageMetadata.deviceType === 'mobile' && (jsxRuntime.jsx(MobileIcon, { className: "w-4 h-4 text-gray-400", title: "Mobile" }))] }))] }), jsxRuntime.jsx(ChevronRightIcon, { className: "w-4 h-4 text-gray-400 flex-shrink-0 mt-0.5" })] }), item.description && (jsxRuntime.jsx("p", { className: "text-xs text-gray-600 m-0 mb-3 line-clamp-2", children: item.description })), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [jsxRuntime.jsx("span", { className: cn("px-2.5 py-1 rounded-lg text-[10px] font-semibold uppercase tracking-wide", statusColors[item.status]), children: item.status.replace("-", " ") }), jsxRuntime.jsx("span", { className: cn("px-2.5 py-1 rounded-lg text-[10px] font-semibold uppercase tracking-wide", priorityColors$1[item.priority]), children: item.priority }), item.createdBy && (jsxRuntime.jsxs("span", { className: "text-[10px] text-gray-600 font-medium", children: ["by ", item.createdBy.name] })), jsxRuntime.jsx("span", { className: "text-[10px] text-gray-500 ml-auto font-medium", children: formatDate(item.createdAt) })] }), item.tags && item.tags.length > 0 && (jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1.5 mt-3", children: [item.tags.slice(0, 3).map((tag) => (jsxRuntime.jsx("span", { className: "px-2 py-1 bg-gray-100 text-gray-700 rounded-md text-[10px] font-medium", children: tag }, tag))), item.tags.length > 3 && (jsxRuntime.jsxs("span", { className: "px-2 py-1 text-gray-500 text-[10px] font-medium", children: ["+", item.tags.length - 3, " more"] }))] }))] }, item.id));
12159
+ }) })) }), feedbackItems.length > 0 && (jsxRuntime.jsxs("div", { className: "pt-3 mt-3 border-t border-gray-200 text-xs text-gray-400 text-center", children: ["Showing ", filteredAndSortedItems.length, " of", " ", feedbackItems.length, " items"] }))] }));
11976
12160
  };
11977
12161
 
11978
12162
  const getDefaultsFromPostinstall = () => (undefined);
@@ -37136,6 +37320,7 @@ const subscribeFeedback = (projectId, callback) => {
37136
37320
  devicePixelRatio: 1,
37137
37321
  userAgent: '',
37138
37322
  timestamp: new Date().toISOString(),
37323
+ deviceType: 'desktop',
37139
37324
  },
37140
37325
  createdAt: data.createdAt.toDate().toISOString(),
37141
37326
  updatedAt: data.createdAt.toDate().toISOString(),
@@ -37143,9 +37328,13 @@ const subscribeFeedback = (projectId, callback) => {
37143
37328
  id: data.userId,
37144
37329
  name: 'User',
37145
37330
  email: '',
37146
- role: 'client',
37331
+ role: 'default',
37147
37332
  },
37148
37333
  tags: data.tags || [],
37334
+ sessionEvents: data.sessionEvents,
37335
+ componentName: data.componentName,
37336
+ designMockup: data.designMockup,
37337
+ screenRecording: data.screenRecording,
37149
37338
  };
37150
37339
  });
37151
37340
  callback(feedbackItems);
@@ -37205,30 +37394,114 @@ const canDeleteFeedback = (currentUser, feedbackCreatorId) => {
37205
37394
  }
37206
37395
  return false;
37207
37396
  };
37397
+ /**
37398
+ * Check if a user can edit/amend feedback
37399
+ * Only the creator, developers, or admins can edit
37400
+ */
37401
+ const canEditFeedback = (currentUser, feedbackCreatorId) => {
37402
+ // Creator can edit their own feedback
37403
+ if (currentUser.id === feedbackCreatorId) {
37404
+ return true;
37405
+ }
37406
+ // Admins and developers can edit any feedback
37407
+ if (currentUser.role === 'admin' || currentUser.role === 'developer') {
37408
+ return true;
37409
+ }
37410
+ return false;
37411
+ };
37208
37412
 
37209
37413
  const statusOptions = [
37210
- { value: "open", label: "Open", color: "bg-blue-500" },
37211
- { value: "in-progress", label: "In Progress", color: "bg-purple-500" },
37212
- { value: "resolved", label: "Resolved", color: "bg-green-500" },
37213
- { value: "closed", label: "Closed", color: "bg-gray-500" },
37414
+ { value: "open", label: "Open", color: "bg-brand-blue text-gray-900" },
37415
+ {
37416
+ value: "in-progress",
37417
+ label: "In Progress",
37418
+ color: "bg-yellow-100 text-gray-900",
37419
+ },
37420
+ {
37421
+ value: "resolved",
37422
+ label: "Resolved",
37423
+ color: "bg-brand-green text-white",
37424
+ },
37425
+ {
37426
+ value: "closed",
37427
+ label: "Closed",
37428
+ color: "bg-brand-pink text-gray-900",
37429
+ },
37214
37430
  ];
37215
37431
  const priorityColors = {
37216
- low: "bg-gray-100 text-gray-700",
37217
- medium: "bg-yellow-100 text-yellow-800",
37218
- high: "bg-orange-100 text-orange-800",
37219
- critical: "bg-red-100 text-red-800",
37432
+ low: "bg-brand-green/30 text-gray-700",
37433
+ medium: "bg-brand-blue/50 text-gray-800",
37434
+ high: "bg-brand-pink/30 text-gray-800",
37435
+ critical: "bg-brand-pink text-gray-800",
37220
37436
  };
37221
37437
  const FeedbackDetail = ({ feedback: initialFeedback, onBack, onDelete, onUpdate, }) => {
37222
- var _a, _b;
37438
+ var _a, _b, _c;
37223
37439
  const { config, updateFeedback: updateFeedback$1, currentUser } = useMarkupStore();
37224
37440
  const [feedback, setFeedback] = require$$0.useState(initialFeedback);
37225
37441
  const [newComment, setNewComment] = require$$0.useState("");
37226
37442
  const [isAddingComment, setIsAddingComment] = require$$0.useState(false);
37227
37443
  const [showFullScreenshot, setShowFullScreenshot] = require$$0.useState(false);
37228
37444
  const [copied, setCopied] = require$$0.useState(false);
37445
+ const [isEditing, setIsEditing] = require$$0.useState(false);
37446
+ // Feature 2 & 5 states
37447
+ const [showReplay, setShowReplay] = require$$0.useState(false);
37448
+ const [showOverlay, setShowOverlay] = require$$0.useState(false);
37449
+ const [overlayOpacity, setOverlayOpacity] = require$$0.useState(50);
37450
+ // Parse session actions
37451
+ const sessionActions = require$$0.useMemo(() => {
37452
+ if (!feedback.sessionEvents)
37453
+ return null;
37454
+ try {
37455
+ return JSON.parse(feedback.sessionEvents);
37456
+ }
37457
+ catch (e) {
37458
+ console.error("Failed to parse session events", e);
37459
+ return null;
37460
+ }
37461
+ }, [feedback.sessionEvents]);
37462
+ // Format timestamp
37463
+ const formatTimestamp = (timestamp) => {
37464
+ const date = new Date(timestamp);
37465
+ return date.toLocaleTimeString('en-US', {
37466
+ hour: '2-digit',
37467
+ minute: '2-digit',
37468
+ second: '2-digit',
37469
+ hour12: false
37470
+ });
37471
+ };
37472
+ // Get relative time
37473
+ const getRelativeTime = (timestamp, baseTimestamp) => {
37474
+ const diff = Math.floor((timestamp - baseTimestamp) / 1000);
37475
+ if (diff === 0)
37476
+ return 'start';
37477
+ return `+${diff}s`;
37478
+ };
37229
37479
  const isReadOnly = ((_a = config.user) === null || _a === void 0 ? void 0 : _a.role) === "default" || config.allowStatusChange === false;
37230
- // Check if current user can delete this feedback
37231
- const canDelete = currentUser ? canDeleteFeedback(currentUser, feedback.createdBy.id) : false;
37480
+ // Check if current user can delete/edit this feedback
37481
+ const canDelete = currentUser
37482
+ ? canDeleteFeedback(currentUser, feedback.createdBy.id)
37483
+ : false;
37484
+ const canEdit = currentUser
37485
+ ? canEditFeedback(currentUser, feedback.createdBy.id)
37486
+ : false;
37487
+ const handleEditSubmit = async (updatedFeedback) => {
37488
+ setFeedback(updatedFeedback);
37489
+ updateFeedback$1(updatedFeedback);
37490
+ // Update in Firebase if initialized
37491
+ try {
37492
+ await updateFeedback(feedback.id, updatedFeedback);
37493
+ }
37494
+ catch (error) {
37495
+ console.warn("Failed to update feedback in Firebase:", error);
37496
+ }
37497
+ if (onUpdate) {
37498
+ onUpdate(updatedFeedback);
37499
+ }
37500
+ setIsEditing(false);
37501
+ };
37502
+ if (isEditing) {
37503
+ return (jsxRuntime.jsxs("div", { className: "flex flex-col h-full", children: [jsxRuntime.jsx("div", { className: "flex items-center justify-between p-5 pb-3 mb-3 border-b border-gray-200", children: jsxRuntime.jsxs("div", { onClick: () => setIsEditing(false), className: "flex items-center gap-1.5 text-sm text-gray-600 bg-transparent border-none cursor-pointer hover:text-gray-900 transition-colors", children: [jsxRuntime.jsx(ArrowLeftIcon, { className: "w-4 h-4" }), "Cancel Editing"] }) }), jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto px-5", children: jsxRuntime.jsx(FeedbackForm, { initialData: feedback, onSubmit: handleEditSubmit, onCancel: () => setIsEditing(false) }) })] }));
37504
+ }
37232
37505
  const handleCopy = async () => {
37233
37506
  const feedbackText = `
37234
37507
  📝 ${feedback.title}
@@ -37272,7 +37545,7 @@ ${feedback.comments && feedback.comments.length > 0
37272
37545
  await updateFeedback(feedback.id, { status: newStatus });
37273
37546
  }
37274
37547
  catch (error) {
37275
- console.warn('Failed to update status in Firebase:', error);
37548
+ console.warn("Failed to update status in Firebase:", error);
37276
37549
  }
37277
37550
  if (config.onStatusChange) {
37278
37551
  await config.onStatusChange(feedback.id, newStatus);
@@ -37308,11 +37581,11 @@ ${feedback.comments && feedback.comments.length > 0
37308
37581
  // Update in Firebase if initialized
37309
37582
  try {
37310
37583
  await updateFeedback(feedback.id, {
37311
- comments: updatedFeedback.comments
37584
+ comments: updatedFeedback.comments,
37312
37585
  });
37313
37586
  }
37314
37587
  catch (error) {
37315
- console.warn('Failed to add comment in Firebase:', error);
37588
+ console.warn("Failed to add comment in Firebase:", error);
37316
37589
  }
37317
37590
  if (config.onCommentAdd) {
37318
37591
  await config.onCommentAdd(feedback.id, comment);
@@ -37331,7 +37604,7 @@ ${feedback.comments && feedback.comments.length > 0
37331
37604
  await deleteFeedback(feedback.id);
37332
37605
  }
37333
37606
  catch (error) {
37334
- console.warn('Failed to delete from Firebase:', error);
37607
+ console.warn("Failed to delete from Firebase:", error);
37335
37608
  }
37336
37609
  if (config.onDelete) {
37337
37610
  await config.onDelete(feedback.id);
@@ -37340,22 +37613,28 @@ ${feedback.comments && feedback.comments.length > 0
37340
37613
  onDelete(feedback.id);
37341
37614
  }
37342
37615
  };
37343
- return (jsxRuntime.jsxs("div", { className: "flex flex-col h-full px-5", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between pb-3 mb-3 border-b border-gray-200", children: [jsxRuntime.jsxs("div", { onClick: onBack, className: "flex items-center gap-1.5 text-sm text-gray-600 bg-transparent border-none cursor-pointer hover:text-gray-900 transition-colors", children: [jsxRuntime.jsx(ArrowLeftIcon, { className: "w-4 h-4" }), "Back"] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("div", { onClick: handleCopy, className: "flex items-center gap-1.5 text-sm text-indigo-600 bg-transparent border-none cursor-pointer hover:text-indigo-700 transition-colors", children: copied ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(CheckIcon, { className: "w-4 h-4" }), "Copied!"] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("svg", { className: "w-4 h-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }), jsxRuntime.jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })] }), "Copy"] })) }), canDelete && onDelete && (jsxRuntime.jsxs("div", { onClick: handleDelete, className: "flex items-center gap-1.5 text-sm text-red-600 bg-transparent border-none cursor-pointer hover:text-red-700 transition-colors", children: [jsxRuntime.jsx(TrashIcon, { className: "w-4 h-4" }), "Delete"] }))] })] }), jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto pr-1", children: [jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h3", { className: "text-base font-semibold text-gray-900 m-0 mb-2", children: feedback.title }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [feedback.type && (jsxRuntime.jsx("span", { className: cn("px-2 py-0.5 rounded-full text-[10px] font-medium uppercase", feedback.type === "copy-amendment"
37344
- ? "bg-purple-100 text-purple-800"
37616
+ return (jsxRuntime.jsxs("div", { className: "flex flex-col h-full px-5", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between pb-3 mb-3 border-b border-gray-200", children: [jsxRuntime.jsxs("div", { onClick: onBack, className: "flex items-center gap-1.5 text-sm text-gray-600 bg-transparent border-none cursor-pointer hover:text-gray-900 transition-colors", children: [jsxRuntime.jsx(ArrowLeftIcon, { className: "w-4 h-4" }), "Back"] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("div", { onClick: handleCopy, className: "flex items-center gap-1.5 text-sm text-gray-600 bg-transparent border-none cursor-pointer hover:text-gray-900 transition-colors", children: copied ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(CheckIcon, { className: "w-4 h-4" }), "Copied!"] })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(CopyIcon, { className: "w-4 h-4" }) })) }), canEdit && (jsxRuntime.jsx("div", { onClick: () => setIsEditing(true), className: "flex items-center gap-1.5 text-sm text-gray-600 bg-transparent border-none cursor-pointer hover:text-gray-900 transition-colors", children: jsxRuntime.jsx(EditIcon, { className: "w-4 h-4" }) })), canDelete && onDelete && (jsxRuntime.jsx("div", { onClick: handleDelete, className: "flex items-center gap-1.5 text-sm text-red-600 bg-transparent border-none cursor-pointer hover:text-red-700 transition-colors", children: jsxRuntime.jsx(TrashIcon, { className: "w-4 h-4" }) }))] })] }), jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto pr-1", children: [jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsxs("div", { className: "flex items-start gap-2 mb-2", children: [jsxRuntime.jsx("h3", { className: "text-base font-semibold text-gray-900 m-0 flex-1", children: feedback.title }), ((_b = feedback.pageMetadata) === null || _b === void 0 ? void 0 : _b.deviceType) && (jsxRuntime.jsxs("div", { className: "flex-shrink-0 mt-0.5", children: [feedback.pageMetadata.deviceType === 'desktop' && (jsxRuntime.jsx(DesktopIcon, { className: "w-5 h-5 text-gray-500", title: "Desktop" })), feedback.pageMetadata.deviceType === 'tablet' && (jsxRuntime.jsx(TabletIcon, { className: "w-5 h-5 text-gray-500", title: "Tablet" })), feedback.pageMetadata.deviceType === 'mobile' && (jsxRuntime.jsx(MobileIcon, { className: "w-5 h-5 text-gray-500", title: "Mobile" }))] }))] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [feedback.type && (jsxRuntime.jsx("span", { className: cn("px-2 py-0.5 rounded-full text-[10px] font-medium uppercase", feedback.type === "copy-amendment"
37617
+ ? "bg-brand-blue/50 text-gray-800"
37345
37618
  : feedback.type === "bug"
37346
- ? "bg-red-100 text-red-800"
37619
+ ? "bg-brand-pink/30 text-gray-800"
37347
37620
  : feedback.type === "feature"
37348
- ? "bg-blue-100 text-blue-800"
37621
+ ? "bg-brand-green/30 text-gray-800"
37349
37622
  : "bg-gray-100 text-gray-700"), children: feedback.type === "copy-amendment"
37350
37623
  ? "Copy"
37351
37624
  : "General" })), jsxRuntime.jsx("span", { className: cn("px-2 py-0.5 rounded-full text-[10px] font-medium uppercase", priorityColors[feedback.priority]), children: feedback.priority }), jsxRuntime.jsx("span", { className: "text-xs text-gray-400", children: formatDate(feedback.createdAt) })] })] }), !isReadOnly && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Status" }), jsxRuntime.jsx("div", { className: "flex gap-1.5", children: statusOptions.map((option) => (jsxRuntime.jsx("div", { onClick: () => handleStatusChange(option.value), className: cn("flex-1 py-1.5 px-2 rounded-lg text-[10px] font-medium border cursor-pointer transition-all text-center", feedback.status === option.value
37352
- ? "bg-[#C2D1D9] text-white border-[#C2D1D9]"
37353
- : "bg-white text-gray-600 border-gray-200 hover:border-indigo-300"), children: option.label }, option.value))) })] })), feedback.screenshot && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-xs font-semibold text-gray-800 mb-2 uppercase tracking-wide", children: "Screenshot" }), jsxRuntime.jsxs("div", { className: "relative rounded-xl overflow-hidden shadow-md cursor-pointer group", onClick: () => setShowFullScreenshot(true), children: [jsxRuntime.jsx("img", { src: feedback.screenshot, alt: "Feedback screenshot", className: "w-full block" }), jsxRuntime.jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/60 via-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-all flex items-center justify-center", children: jsxRuntime.jsx("div", { className: "bg-white rounded-full p-3 shadow-xl transform scale-90 group-hover:scale-100 transition-transform", children: jsxRuntime.jsx(ZoomInIcon, { className: "w-6 h-6 text-gray-700" }) }) })] })] })), feedback.description && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Description" }), jsxRuntime.jsx("p", { className: "text-sm text-gray-600 m-0 whitespace-pre-wrap", children: feedback.description })] })), feedback.tags && feedback.tags.length > 0 && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Tags" }), jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5", children: feedback.tags.map((tag) => (jsxRuntime.jsx("span", { className: "px-2 py-1 bg-gray-100 text-gray-700 rounded-full text-xs", children: tag }, tag))) })] })), feedback.pageMetadata && (jsxRuntime.jsxs("div", { className: "mb-4 p-2.5 bg-gray-50 rounded-lg", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Page Info" }), jsxRuntime.jsxs("div", { className: "text-xs text-gray-500 space-y-1", children: [jsxRuntime.jsxs("div", { className: "truncate", children: [jsxRuntime.jsx("span", { className: "font-medium", children: "URL:" }), " ", feedback.pageMetadata.url] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("span", { className: "font-medium", children: "Screen:" }), " ", feedback.pageMetadata.screenWidth, "x", feedback.pageMetadata.screenHeight] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("span", { className: "font-medium", children: "User Agent:" }), " ", feedback.pageMetadata.userAgent] })] })] })), jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsxs("label", { className: "block text-xs font-medium text-gray-700 mb-2", children: ["Comments (", ((_b = feedback.comments) === null || _b === void 0 ? void 0 : _b.length) || 0, ")"] }), feedback.comments && feedback.comments.length > 0 && (jsxRuntime.jsx("div", { className: "space-y-3 mb-4", children: feedback.comments.map((comment) => (jsxRuntime.jsxs("div", { className: "p-3 bg-white border border-gray-200 rounded-xl shadow-sm", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-2", children: [jsxRuntime.jsx("div", { className: "w-8 h-8 rounded-full bg-gradient-to-br from-[#C2D1D9] to-purple-500 flex items-center justify-center shadow-md", children: jsxRuntime.jsx(UserIcon, { className: "w-4 h-4 text-white" }) }), jsxRuntime.jsx("span", { className: "text-xs font-semibold text-gray-900", children: comment.createdBy.name }), jsxRuntime.jsx("span", { className: "text-[10px] text-gray-500 font-medium", children: formatDate(comment.createdAt) })] }), jsxRuntime.jsx("p", { className: "text-sm text-gray-700 m-0 ml-10 whitespace-pre-wrap", children: comment.content || comment.text })] }, comment.id))) })), jsxRuntime.jsxs("div", { className: "flex gap-2", children: [jsxRuntime.jsx("input", { type: "text", value: newComment, onChange: (e) => setNewComment(e.target.value), placeholder: "Add a comment...", className: "flex-1 px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl text-sm focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all", onKeyDown: (e) => {
37625
+ ? cn(option.color, "border-transparent")
37626
+ : "bg-white text-gray-600 border-gray-200 hover:border-brand-blue"), children: option.label }, option.value))) })] })), feedback.screenshot && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-xs font-semibold text-gray-800 mb-2 uppercase tracking-wide", children: "Screenshot" }), jsxRuntime.jsxs("div", { className: "relative rounded-xl overflow-hidden shadow-md cursor-pointer group", onClick: () => setShowFullScreenshot(true), children: [jsxRuntime.jsx("img", { src: feedback.screenshot, alt: "Feedback screenshot", className: "w-full block" }), jsxRuntime.jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/60 via-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-all flex items-center justify-center", children: jsxRuntime.jsx("div", { className: "bg-white rounded-full p-3 shadow-xl transform scale-90 group-hover:scale-100 transition-transform", children: jsxRuntime.jsx(ZoomInIcon, { className: "w-6 h-6 text-gray-700" }) }) })] })] })), feedback.screenRecording && (jsxRuntime.jsxs("div", { className: "mb-5", children: [jsxRuntime.jsx("label", { className: "block text-xs font-semibold text-gray-800 mb-2 uppercase tracking-wide", children: "Screen Recording" }), jsxRuntime.jsx("div", { className: "relative rounded-xl overflow-hidden shadow-md border border-gray-200", children: jsxRuntime.jsx("video", { src: feedback.screenRecording, controls: true, className: "w-full h-auto bg-black" }) })] })), (feedback.designMockup || feedback.sessionEvents) && (jsxRuntime.jsxs("div", { className: "flex gap-2 mb-5", children: [feedback.sessionEvents && (jsxRuntime.jsx("button", { onClick: () => setShowReplay(true), className: "flex-1 bg-gray-100 text-gray-700 py-2.5 rounded-xl text-xs font-semibold hover:bg-gray-200 transition-colors flex items-center justify-center gap-2 border border-gray-200 cursor-pointer", children: "Play Session" })), feedback.designMockup && (jsxRuntime.jsx("button", { onClick: () => setShowOverlay(true), className: "flex-1 bg-gray-100 text-gray-700 py-2.5 rounded-xl text-xs font-semibold hover:bg-gray-200 transition-colors flex items-center justify-center gap-2 border border-gray-200 cursor-pointer", children: "Overlay Mockup" }))] })), feedback.type === "copy-amendment" && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [feedback.currentCopy && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Current Copy" }), jsxRuntime.jsx("div", { className: "bg-red-50 border border-red-200 rounded-lg p-3", children: jsxRuntime.jsx("p", { className: "text-sm text-gray-800 m-0 whitespace-pre-wrap", children: feedback.currentCopy }) })] })), feedback.newCopy && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "New Copy" }), jsxRuntime.jsx("div", { className: "bg-green-50 border border-green-200 rounded-lg p-3", children: jsxRuntime.jsx("p", { className: "text-sm text-gray-800 m-0 whitespace-pre-wrap", children: feedback.newCopy }) })] }))] })), feedback.description && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Description" }), jsxRuntime.jsx("p", { className: "text-sm text-gray-600 m-0 whitespace-pre-wrap", children: feedback.description })] })), feedback.tags && feedback.tags.length > 0 && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Tags" }), jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5", children: feedback.tags.map((tag) => (jsxRuntime.jsx("span", { className: "px-2 py-1 bg-gray-100 text-gray-700 rounded-full text-xs", children: tag }, tag))) })] })), feedback.pageMetadata && (jsxRuntime.jsxs("div", { className: "mb-4 p-2.5 bg-gray-50 rounded-lg", children: [jsxRuntime.jsx("label", { className: "block text-xs font-medium text-gray-700 mb-1.5", children: "Page Info" }), jsxRuntime.jsxs("div", { className: "text-xs text-gray-500 space-y-1", children: [jsxRuntime.jsxs("div", { className: "truncate", children: [jsxRuntime.jsx("span", { className: "font-medium", children: "URL:" }), " ", feedback.pageMetadata.url] }), feedback.pageMetadata.componentName && (jsxRuntime.jsxs("div", { className: "truncate", children: [jsxRuntime.jsx("span", { className: "font-medium", children: "Component:" }), " ", jsxRuntime.jsx("code", { className: "bg-gray-200 px-1.5 py-0.5 rounded text-xs font-mono text-gray-800", children: feedback.pageMetadata.componentName })] })), feedback.pageMetadata.elementInfo && (jsxRuntime.jsxs("div", { className: "truncate", children: [jsxRuntime.jsx("span", { className: "font-medium", children: "Element:" }), " ", jsxRuntime.jsx("code", { className: "bg-blue-50 px-1.5 py-0.5 rounded text-xs font-mono text-blue-800", children: feedback.pageMetadata.elementInfo })] })), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("span", { className: "font-medium", children: "Screen:" }), " ", feedback.pageMetadata.screenWidth, "x", feedback.pageMetadata.screenHeight] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("span", { className: "font-medium", children: "User Agent:" }), " ", feedback.pageMetadata.userAgent] })] })] })), jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsxs("label", { className: "block text-xs font-medium text-gray-700 mb-2", children: ["Comments (", ((_c = feedback.comments) === null || _c === void 0 ? void 0 : _c.length) || 0, ")"] }), feedback.comments && feedback.comments.length > 0 && (jsxRuntime.jsx("div", { className: "space-y-3 mb-4", children: feedback.comments.map((comment) => (jsxRuntime.jsxs("div", { className: "p-3 bg-white border border-gray-200 rounded-xl shadow-sm", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-2", children: [jsxRuntime.jsx("div", { className: "w-8 h-8 rounded-full bg-gradient-to-br from-[#C2D1D9] to-purple-500 flex items-center justify-center shadow-md", children: jsxRuntime.jsx(UserIcon, { className: "w-4 h-4 text-white" }) }), jsxRuntime.jsx("span", { className: "text-xs font-semibold text-gray-900", children: comment.createdBy.name }), jsxRuntime.jsx("span", { className: "text-[10px] text-gray-500 font-medium", children: formatDate(comment.createdAt) })] }), jsxRuntime.jsx("p", { className: "text-sm text-gray-700 m-0 ml-10 whitespace-pre-wrap", children: comment.content || comment.text })] }, comment.id))) })), jsxRuntime.jsxs("div", { className: "flex gap-2", children: [jsxRuntime.jsx("input", { type: "text", value: newComment, onChange: (e) => setNewComment(e.target.value), placeholder: "Add a comment...", className: "flex-1 px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl text-sm focus:outline-none focus:bg-white focus:border-[#C2D1D9] focus:shadow-lg focus:shadow-[#C2D1D9]/10 transition-all", onKeyDown: (e) => {
37354
37627
  if (e.key === "Enter" && !e.shiftKey) {
37355
37628
  e.preventDefault();
37356
37629
  handleAddComment();
37357
37630
  }
37358
- } }), jsxRuntime.jsx("button", { onClick: handleAddComment, disabled: !newComment.trim() || isAddingComment, className: "p-2.5 rounded-xl border-none text-white cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed hover:shadow-lg transition-all", style: { backgroundColor: "var(--markup-primary)" }, children: jsxRuntime.jsx(SendIcon, { className: "w-5 h-5" }) })] })] })] }), showFullScreenshot && feedback.screenshot && (jsxRuntime.jsxs("div", { className: "fixed inset-0 bg-black z-[1000001] flex items-center justify-center", onClick: () => setShowFullScreenshot(false), children: [jsxRuntime.jsx("button", { onClick: () => setShowFullScreenshot(false), className: "absolute top-4 right-4 p-3 bg-white/10 rounded-full border-none cursor-pointer hover:bg-white/20 transition-colors z-10", children: jsxRuntime.jsx(CloseIcon, { className: "w-8 h-8 text-white" }) }), jsxRuntime.jsx("img", { src: feedback.screenshot, alt: "Feedback screenshot", className: "w-full h-full object-contain", onClick: (e) => e.stopPropagation() })] }))] }));
37631
+ } }), jsxRuntime.jsx("button", { onClick: handleAddComment, disabled: !newComment.trim() || isAddingComment, className: "p-2.5 rounded-xl border-none text-white cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed hover:shadow-lg transition-all", style: { backgroundColor: "var(--markup-primary)" }, children: jsxRuntime.jsx(SendIcon, { className: "w-5 h-5" }) })] })] })] }), showFullScreenshot &&
37632
+ feedback.screenshot &&
37633
+ reactDom.createPortal(jsxRuntime.jsxs("div", { className: "fixed inset-0 bg-black/90 backdrop-blur-sm z-[2147483647] flex items-center justify-center p-10 animate-in fade-in duration-200", onClick: () => setShowFullScreenshot(false), children: [jsxRuntime.jsx("button", { onClick: () => setShowFullScreenshot(false), className: "absolute top-6 right-6 p-2 bg-white/10 rounded-full border-none cursor-pointer hover:bg-white/20 transition-colors z-10", children: jsxRuntime.jsx(CloseIcon, { className: "w-8 h-8 text-white" }) }), jsxRuntime.jsx("img", { src: feedback.screenshot, alt: "Feedback screenshot", className: "max-w-full max-h-full object-contain rounded-lg shadow-2xl", onClick: (e) => e.stopPropagation() })] }), document.body), showReplay && sessionActions && sessionActions.length > 0 && reactDom.createPortal(jsxRuntime.jsx("div", { className: "fixed inset-0 z-[10000] bg-black/80 backdrop-blur-sm flex items-center justify-center p-5 animate-in fade-in duration-200", onClick: () => setShowReplay(false), children: jsxRuntime.jsxs("div", { className: "bg-white rounded-2xl overflow-hidden shadow-2xl max-w-[900px] w-full flex flex-col max-h-[90vh]", onClick: (e) => e.stopPropagation(), children: [jsxRuntime.jsxs("div", { className: "p-4 border-b border-gray-100 flex items-center justify-between bg-gray-50", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("h3", { className: "font-semibold text-gray-900", children: "Session Activity Timeline" }), jsxRuntime.jsx("p", { className: "text-xs text-gray-600 mt-1", children: "User actions recorded during feedback creation" })] }), jsxRuntime.jsx("button", { onClick: () => setShowReplay(false), className: "p-2 hover:bg-gray-200 rounded-full transition-colors cursor-pointer text-gray-500 hover:text-gray-900 border-none bg-transparent", children: jsxRuntime.jsx(CloseIcon, { className: "w-5 h-5" }) })] }), jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto p-4", children: jsxRuntime.jsx("div", { className: "space-y-2", children: sessionActions.map((action, idx) => {
37634
+ var _a;
37635
+ const baseTime = ((_a = sessionActions[0]) === null || _a === void 0 ? void 0 : _a.timestamp) || action.timestamp;
37636
+ return (jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-3 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors", children: [jsxRuntime.jsxs("div", { className: "flex-shrink-0 w-20 text-xs font-mono text-gray-600", children: [jsxRuntime.jsx("div", { children: formatTimestamp(action.timestamp) }), jsxRuntime.jsx("div", { className: "text-gray-400", children: getRelativeTime(action.timestamp, baseTime) })] }), jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [action.type === 'click' && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsxRuntime.jsx("span", { className: "inline-block w-2 h-2 bg-blue-500 rounded-full" }), jsxRuntime.jsx("span", { className: "font-medium text-gray-900", children: "Clicked" })] }), jsxRuntime.jsxs("div", { className: "text-sm text-gray-700 font-mono bg-white px-2 py-1 rounded border border-gray-200", children: ["<", action.data.elementTag || 'unknown', action.data.elementId && ` id="${action.data.elementId}"`, action.data.elementClass && ` class="${action.data.elementClass}"`, ">"] }), action.data.elementText && (jsxRuntime.jsxs("div", { className: "mt-1 text-sm text-gray-600", children: ["Text: ", jsxRuntime.jsxs("span", { className: "italic", children: ["\"", action.data.elementText.substring(0, 100), action.data.elementText.length > 100 ? '...' : '', "\""] })] }))] })), action.type === 'navigation' && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsxRuntime.jsx("span", { className: "inline-block w-2 h-2 bg-purple-500 rounded-full" }), jsxRuntime.jsx("span", { className: "font-medium text-gray-900", children: "Navigated" })] }), jsxRuntime.jsx("div", { className: "text-sm text-gray-700 break-all", children: action.data.url })] })), action.type === 'scroll' && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsxRuntime.jsx("span", { className: "inline-block w-2 h-2 bg-green-500 rounded-full" }), jsxRuntime.jsx("span", { className: "font-medium text-gray-900", children: "Scrolled" })] }), jsxRuntime.jsxs("div", { className: "text-sm text-gray-700", children: ["Position: ", action.data.scrollY, "px"] })] })), action.type === 'input' && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsxRuntime.jsx("span", { className: "inline-block w-2 h-2 bg-orange-500 rounded-full" }), jsxRuntime.jsx("span", { className: "font-medium text-gray-900", children: "Input" })] }), jsxRuntime.jsxs("div", { className: "text-sm text-gray-700", children: [action.data.inputType, " field"] })] }))] })] }, idx));
37637
+ }) }) })] }) }), document.body), showOverlay && feedback.designMockup && reactDom.createPortal(jsxRuntime.jsxs("div", { className: "fixed inset-0 z-[10000] pointer-events-none", children: [jsxRuntime.jsx("img", { src: feedback.designMockup, style: { opacity: overlayOpacity / 100 }, className: "w-full h-full object-contain object-top", alt: "Design Mockup Overlay" }), jsxRuntime.jsxs("div", { className: "fixed bottom-10 left-1/2 -translate-x-1/2 bg-white/90 backdrop-blur border border-gray-200 shadow-xl rounded-full p-2 px-6 flex items-center gap-4 pointer-events-auto", children: [jsxRuntime.jsx("span", { className: "text-xs font-bold text-gray-500 uppercase whitespace-nowrap", children: "Overlay Opacity" }), jsxRuntime.jsx("input", { type: "range", min: "0", max: "100", value: overlayOpacity, onChange: (e) => setOverlayOpacity(Number(e.target.value)), className: "w-32 accent-brand-blue" }), jsxRuntime.jsx("button", { onClick: () => setShowOverlay(false), className: "ml-2 hover:bg-gray-200 p-1.5 rounded-full border-none bg-transparent", children: jsxRuntime.jsx(CloseIcon, { className: "w-4 h-4 text-gray-500" }) })] })] }), document.body)] }));
37359
37638
  };
37360
37639
 
37361
37640
  const signUp = async (email, password) => {
@@ -37407,18 +37686,82 @@ const AuthForm = ({ onSuccess }) => {
37407
37686
  };
37408
37687
  return (jsxRuntime.jsx("div", { className: "flex flex-col items-center justify-center h-full p-5", children: jsxRuntime.jsxs("div", { className: "w-full max-w-md", children: [jsxRuntime.jsxs("div", { className: "bg-white rounded-2xl shadow-2xl p-8", children: [jsxRuntime.jsx("h2", { className: "text-2xl font-bold text-gray-900 mb-2 text-center", children: mode === "login" ? "Sign In" : "Create Account" }), jsxRuntime.jsx("p", { className: "text-gray-600 text-sm text-center mb-6", children: mode === "login"
37409
37688
  ? "Sign in to submit and manage feedback"
37410
- : "Create an account to get started" }), jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { htmlFor: "email", className: "block text-sm font-medium text-gray-700 mb-2", children: "Email Address" }), jsxRuntime.jsx("input", { id: "email", type: "email", value: email, onChange: (e) => setEmail(e.target.value), required: true, className: "w-full px-4 py-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#C2D1D9] focus:border-transparent transition-all", placeholder: "you@example.com" })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { htmlFor: "password", className: "block text-sm font-medium text-gray-700 mb-2", children: "Password" }), jsxRuntime.jsx("input", { id: "password", type: "password", value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 6, className: "w-full px-4 py-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#C2D1D9] focus:border-transparent transition-all", placeholder: "Minimum 6 characters" })] }), error && (jsxRuntime.jsx("div", { className: "bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg text-sm", children: error })), jsxRuntime.jsx("div", { onClick: handleSubmit, className: "w-full bg-indigo-600 text-white py-2.5 px-4 rounded-lg font-medium hover:bg-indigo-700 focus:ring-4 focus:ring-indigo-200 transition-all cursor-pointer text-center", children: loading
37689
+ : "Create an account to get started" }), jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { htmlFor: "email", className: "block text-sm font-medium text-gray-700 mb-2", children: "Email Address" }), jsxRuntime.jsx("input", { id: "email", type: "email", value: email, onChange: (e) => setEmail(e.target.value), required: true, className: "w-full px-4 py-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#C2D1D9] focus:border-transparent transition-all", placeholder: "you@example.com" })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { htmlFor: "password", className: "block text-sm font-medium text-gray-700 mb-2", children: "Password" }), jsxRuntime.jsx("input", { id: "password", type: "password", value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 6, className: "w-full px-4 py-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#C2D1D9] focus:border-transparent transition-all", placeholder: "Minimum 6 characters" })] }), error && (jsxRuntime.jsx("div", { className: "bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg text-sm", children: error })), jsxRuntime.jsx("div", { onClick: handleSubmit, className: "w-full bg-[#c2d1d9] text-black py-2.5 px-4 rounded-lg font-medium hover:bg-[#c2d1d9]/80 focus:ring-4 focus:ring-blue transition-all cursor-pointer text-center", children: loading
37411
37690
  ? "Please wait..."
37412
37691
  : mode === "login"
37413
37692
  ? "Sign In"
37414
37693
  : "Create Account" })] }), jsxRuntime.jsx("div", { className: "mt-6 text-center", children: jsxRuntime.jsx("div", { onClick: () => {
37415
37694
  setMode(mode === "login" ? "signup" : "login");
37416
37695
  setError(null);
37417
- }, className: "text-sm text-white w-full font-medium cursor-pointer", children: mode === "login"
37696
+ }, className: "bg-pink text-black w-full font-medium cursor-pointer hover:underline", children: mode === "login"
37418
37697
  ? "Don't have an account? Sign up"
37419
37698
  : "Already have an account? Sign in" }) })] }), jsxRuntime.jsx("p", { className: "text-center text-xs text-gray-500 mt-6", children: "Your feedback will be associated with your account" })] }) }));
37420
37699
  };
37421
37700
 
37701
+ const VIEWPORT_PRESETS = [
37702
+ { name: "iPhone SE", width: 375, height: 667, deviceType: "mobile" },
37703
+ { name: "iPhone 12 Pro", width: 390, height: 844, deviceType: "mobile" },
37704
+ { name: "iPhone 14 Pro Max", width: 430, height: 932, deviceType: "mobile" },
37705
+ { name: "iPad Mini", width: 768, height: 1024, deviceType: "tablet" },
37706
+ { name: "iPad Pro", width: 1024, height: 1366, deviceType: "tablet" },
37707
+ { name: "Desktop", width: 1920, height: 1080, deviceType: "desktop" },
37708
+ ];
37709
+ const ViewportControls = () => {
37710
+ const { viewportMode, setViewportMode, isOpen: isWidgetOpen } = useMarkupStore();
37711
+ const [isExpanded, setIsExpanded] = require$$0.useState(false);
37712
+ const dropdownRef = require$$0.useRef(null);
37713
+ const handlePresetClick = (preset) => {
37714
+ setViewportMode({ width: preset.width, height: preset.height });
37715
+ setIsExpanded(false);
37716
+ };
37717
+ const handleReset = () => {
37718
+ setViewportMode(null);
37719
+ setIsExpanded(false);
37720
+ };
37721
+ const isActivePreset = (preset) => {
37722
+ return (viewportMode === null || viewportMode === void 0 ? void 0 : viewportMode.width) === preset.width && (viewportMode === null || viewportMode === void 0 ? void 0 : viewportMode.height) === preset.height;
37723
+ };
37724
+ // Close dropdown on outside click
37725
+ require$$0.useEffect(() => {
37726
+ if (!isExpanded)
37727
+ return;
37728
+ const handleClickOutside = (event) => {
37729
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
37730
+ setIsExpanded(false);
37731
+ }
37732
+ };
37733
+ document.addEventListener('mousedown', handleClickOutside);
37734
+ return () => document.removeEventListener('mousedown', handleClickOutside);
37735
+ }, [isExpanded]);
37736
+ // Handle ESC key to close dropdown or reset viewport
37737
+ require$$0.useEffect(() => {
37738
+ const handleKeyDown = (event) => {
37739
+ if (event.key === 'Escape') {
37740
+ if (isExpanded) {
37741
+ setIsExpanded(false);
37742
+ event.preventDefault();
37743
+ }
37744
+ else if (viewportMode) {
37745
+ handleReset();
37746
+ event.preventDefault();
37747
+ }
37748
+ }
37749
+ };
37750
+ document.addEventListener('keydown', handleKeyDown);
37751
+ return () => document.removeEventListener('keydown', handleKeyDown);
37752
+ }, [isExpanded, viewportMode]);
37753
+ // Don't show controls when widget is not open
37754
+ if (!isWidgetOpen)
37755
+ return null;
37756
+ return (jsxRuntime.jsxs("div", { ref: dropdownRef, className: "fixed top-4 left-1/2 -translate-x-1/2 z-[999998] flex items-center gap-2", children: [!viewportMode ? (jsxRuntime.jsxs("button", { onClick: () => setIsExpanded(!isExpanded), className: "bg-white border-2 border-gray-300 rounded-xl px-4 py-2 shadow-lg hover:shadow-xl transition-all flex items-center gap-2 text-sm font-medium text-gray-700 hover:text-gray-900 hover:border-gray-400", children: [jsxRuntime.jsx(DesktopIcon, { className: "w-4 h-4" }), "Responsive Mode"] })) : (jsxRuntime.jsxs("div", { className: "bg-white border-2 border-gray-300 rounded-xl px-4 py-2 shadow-lg flex items-center gap-3", children: [jsxRuntime.jsxs("span", { className: "text-sm font-medium text-gray-700", children: [viewportMode.width, " \u00D7 ", viewportMode.height] }), jsxRuntime.jsx("button", { onClick: () => setIsExpanded(!isExpanded), className: "text-gray-600 hover:text-gray-900 transition-colors", children: jsxRuntime.jsx(DesktopIcon, { className: "w-4 h-4" }) }), jsxRuntime.jsx("button", { onClick: handleReset, className: "px-2 py-1 text-xs font-medium text-red-600 hover:text-white hover:bg-red-600 border border-red-600 rounded transition-colors", children: "Reset" })] })), isExpanded && (jsxRuntime.jsx("div", { className: "absolute top-full left-1/2 -translate-x-1/2 mt-2 bg-white border-2 border-gray-200 rounded-xl shadow-2xl p-3 min-w-[240px]", children: jsxRuntime.jsxs("div", { className: "space-y-2", children: [jsxRuntime.jsx("div", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide px-2 mb-2", children: "Mobile" }), VIEWPORT_PRESETS.filter((p) => p.deviceType === "mobile").map((preset) => (jsxRuntime.jsxs("button", { onClick: () => handlePresetClick(preset), className: cn("w-full flex items-center gap-3 px-3 py-2 rounded-lg transition-all text-left group", isActivePreset(preset)
37757
+ ? "bg-blue-50 border border-blue-200"
37758
+ : "hover:bg-gray-100"), children: [jsxRuntime.jsx(MobileIcon, { className: cn("w-4 h-4 transition-colors", isActivePreset(preset) ? "text-blue-600" : "text-gray-400 group-hover:text-gray-600") }), jsxRuntime.jsxs("div", { className: "flex-1", children: [jsxRuntime.jsx("div", { className: "text-sm font-medium text-gray-700 group-hover:text-gray-900", children: preset.name }), jsxRuntime.jsxs("div", { className: "text-xs text-gray-500", children: [preset.width, " \u00D7 ", preset.height] })] })] }, preset.name))), jsxRuntime.jsx("div", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide px-2 mt-4 mb-2", children: "Tablet" }), VIEWPORT_PRESETS.filter((p) => p.deviceType === "tablet").map((preset) => (jsxRuntime.jsxs("button", { onClick: () => handlePresetClick(preset), className: cn("w-full flex items-center gap-3 px-3 py-2 rounded-lg transition-all text-left group", isActivePreset(preset)
37759
+ ? "bg-blue-50 border border-blue-200"
37760
+ : "hover:bg-gray-100"), children: [jsxRuntime.jsx(TabletIcon, { className: cn("w-4 h-4 transition-colors", isActivePreset(preset) ? "text-blue-600" : "text-gray-400 group-hover:text-gray-600") }), jsxRuntime.jsxs("div", { className: "flex-1", children: [jsxRuntime.jsx("div", { className: "text-sm font-medium text-gray-700 group-hover:text-gray-900", children: preset.name }), jsxRuntime.jsxs("div", { className: "text-xs text-gray-500", children: [preset.width, " \u00D7 ", preset.height] })] })] }, preset.name))), jsxRuntime.jsx("div", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide px-2 mt-4 mb-2", children: "Desktop" }), VIEWPORT_PRESETS.filter((p) => p.deviceType === "desktop").map((preset) => (jsxRuntime.jsxs("button", { onClick: () => handlePresetClick(preset), className: cn("w-full flex items-center gap-3 px-3 py-2 rounded-lg transition-all text-left group", isActivePreset(preset)
37761
+ ? "bg-blue-50 border border-blue-200"
37762
+ : "hover:bg-gray-100"), children: [jsxRuntime.jsx(DesktopIcon, { className: cn("w-4 h-4 transition-colors", isActivePreset(preset) ? "text-blue-600" : "text-gray-400 group-hover:text-gray-600") }), jsxRuntime.jsxs("div", { className: "flex-1", children: [jsxRuntime.jsx("div", { className: "text-sm font-medium text-gray-700 group-hover:text-gray-900", children: preset.name }), jsxRuntime.jsxs("div", { className: "text-xs text-gray-500", children: [preset.width, " \u00D7 ", preset.height] })] })] }, preset.name)))] }) }))] }));
37763
+ };
37764
+
37422
37765
  const useFirebaseSync = () => {
37423
37766
  const config = useMarkupStore((state) => state.config);
37424
37767
  const setCurrentUser = useMarkupStore((state) => state.setCurrentUser);
@@ -37513,6 +37856,109 @@ const useFirebaseSync = () => {
37513
37856
  }, [config.projectId, setFeedbackItems, isAuthenticated]);
37514
37857
  };
37515
37858
 
37859
+ const useSessionRecording = () => {
37860
+ const actionsRef = require$$0.useRef([]);
37861
+ const maxActions = 50; // Keep last 50 actions
37862
+ require$$0.useEffect(() => {
37863
+ if (typeof window === 'undefined')
37864
+ return;
37865
+ const recordAction = (action) => {
37866
+ if (actionsRef.current.length >= maxActions) {
37867
+ actionsRef.current.shift();
37868
+ }
37869
+ actionsRef.current.push(action);
37870
+ };
37871
+ // Record clicks
37872
+ const handleClick = (e) => {
37873
+ var _a;
37874
+ const target = e.target;
37875
+ if (target.closest('[data-markup-widget]'))
37876
+ return;
37877
+ recordAction({
37878
+ type: 'click',
37879
+ timestamp: Date.now(),
37880
+ data: {
37881
+ elementTag: target.tagName.toLowerCase(),
37882
+ elementText: ((_a = target.textContent) === null || _a === void 0 ? void 0 : _a.slice(0, 50).trim()) || undefined,
37883
+ elementId: target.id || undefined,
37884
+ elementClass: target.className && typeof target.className === 'string'
37885
+ ? target.className.split(' ').slice(0, 3).join(' ')
37886
+ : undefined,
37887
+ }
37888
+ });
37889
+ };
37890
+ // Record navigation
37891
+ const handleNavigation = () => {
37892
+ recordAction({
37893
+ type: 'navigation',
37894
+ timestamp: Date.now(),
37895
+ data: {
37896
+ url: window.location.href
37897
+ }
37898
+ });
37899
+ };
37900
+ // Record scroll (throttled)
37901
+ let scrollTimeout;
37902
+ const handleScroll = () => {
37903
+ clearTimeout(scrollTimeout);
37904
+ scrollTimeout = setTimeout(() => {
37905
+ recordAction({
37906
+ type: 'scroll',
37907
+ timestamp: Date.now(),
37908
+ data: {
37909
+ scrollY: window.scrollY
37910
+ }
37911
+ });
37912
+ }, 500);
37913
+ };
37914
+ // Record input events
37915
+ const handleInput = (e) => {
37916
+ const target = e.target;
37917
+ if (target.closest('[data-markup-widget]'))
37918
+ return;
37919
+ recordAction({
37920
+ type: 'input',
37921
+ timestamp: Date.now(),
37922
+ data: {
37923
+ elementTag: target.tagName.toLowerCase(),
37924
+ elementId: target.id || undefined,
37925
+ inputType: target.type || undefined,
37926
+ }
37927
+ });
37928
+ };
37929
+ // Record initial page load
37930
+ recordAction({
37931
+ type: 'navigation',
37932
+ timestamp: Date.now(),
37933
+ data: { url: window.location.href }
37934
+ });
37935
+ document.addEventListener('click', handleClick, true);
37936
+ window.addEventListener('popstate', handleNavigation);
37937
+ window.addEventListener('scroll', handleScroll, { passive: true });
37938
+ document.addEventListener('input', handleInput, true);
37939
+ return () => {
37940
+ document.removeEventListener('click', handleClick, true);
37941
+ window.removeEventListener('popstate', handleNavigation);
37942
+ window.removeEventListener('scroll', handleScroll);
37943
+ document.removeEventListener('input', handleInput, true);
37944
+ clearTimeout(scrollTimeout);
37945
+ };
37946
+ }, []);
37947
+ const getSessionEvents = require$$0.useCallback(() => {
37948
+ if (actionsRef.current.length === 0) {
37949
+ return undefined;
37950
+ }
37951
+ return JSON.stringify(actionsRef.current);
37952
+ }, []);
37953
+ const clearSession = require$$0.useCallback(() => {
37954
+ actionsRef.current = [];
37955
+ }, []);
37956
+ return {
37957
+ getSessionEvents,
37958
+ clearSession
37959
+ };
37960
+ };
37961
+
37516
37962
  const MarkupWidget = ({ config: userConfig, }) => {
37517
37963
  var _a;
37518
37964
  // Initialize Firebase synchronously on first render only
@@ -37527,9 +37973,76 @@ const MarkupWidget = ({ config: userConfig, }) => {
37527
37973
  console.error('Failed to initialize Firebase:', error);
37528
37974
  }
37529
37975
  }
37530
- const { isOpen, setIsOpen, activeTab, setActiveTab, selectedFeedback, setSelectedFeedback, feedbackItems, addFeedbackItem, config, setConfig, reset, isAuthenticated, currentUser, } = useMarkupStore();
37976
+ const { isOpen, setIsOpen, activeTab, setActiveTab, selectedFeedback, setSelectedFeedback, feedbackItems, addFeedbackItem, removeFeedbackItem, updateFeedback, config, setConfig, reset, isAuthenticated, currentUser, viewportMode, setViewportMode, } = useMarkupStore();
37531
37977
  // Initialize Firebase sync
37532
37978
  useFirebaseSync();
37979
+ // Initialize Session Recording (Feature 2)
37980
+ const { getSessionEvents } = useSessionRecording();
37981
+ // Track last clicked element for component detection (Feature 4)
37982
+ const lastClickedElementRef = require$$0.useRef(null);
37983
+ const [lastClickedText, setLastClickedText] = require$$0.useState('');
37984
+ require$$0.useEffect(() => {
37985
+ const handleClick = (e) => {
37986
+ var _a;
37987
+ // Store the clicked element (but ignore clicks on the widget itself)
37988
+ const target = e.target;
37989
+ if (!target.closest('[data-markup-widget]')) {
37990
+ lastClickedElementRef.current = target;
37991
+ // If user clicked on text content, capture it for copy amendment
37992
+ // Get the immediate text content (not children)
37993
+ let textContent = '';
37994
+ if (target.childNodes.length > 0) {
37995
+ // Try to get direct text nodes only
37996
+ for (const node of Array.from(target.childNodes)) {
37997
+ if (node.nodeType === Node.TEXT_NODE) {
37998
+ textContent += node.textContent || '';
37999
+ }
38000
+ }
38001
+ textContent = textContent.trim();
38002
+ }
38003
+ // If no direct text, fall back to full textContent
38004
+ if (!textContent) {
38005
+ textContent = ((_a = target.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || '';
38006
+ }
38007
+ if (textContent && textContent.length > 0 && textContent.length < 500) {
38008
+ setLastClickedText(textContent);
38009
+ }
38010
+ else {
38011
+ setLastClickedText('');
38012
+ }
38013
+ }
38014
+ };
38015
+ document.addEventListener('click', handleClick, true);
38016
+ return () => document.removeEventListener('click', handleClick, true);
38017
+ }, []);
38018
+ // Apply viewport mode styling to document (like browser dev tools)
38019
+ require$$0.useEffect(() => {
38020
+ if (viewportMode) {
38021
+ const root = document.documentElement;
38022
+ const body = document.body;
38023
+ // Apply dark background to body
38024
+ body.style.background = 'rgba(0, 0, 0, 0.5)';
38025
+ body.style.overflow = 'visible';
38026
+ // Apply viewport constraints with smooth transition
38027
+ root.style.transition = 'max-width 0.3s ease-in-out, margin 0.3s ease-in-out, background 0.2s ease-in-out';
38028
+ root.style.maxWidth = `${viewportMode.width}px`;
38029
+ root.style.margin = '0 auto';
38030
+ root.style.border = '2px solid #999';
38031
+ root.style.background = '#ffffff'; // Ensure content area has white background
38032
+ root.style.boxShadow = '0 0 50px rgba(0, 0, 0, 0.3)';
38033
+ return () => {
38034
+ // Reset to full width
38035
+ root.style.transition = '';
38036
+ root.style.maxWidth = '';
38037
+ root.style.margin = '';
38038
+ root.style.border = '';
38039
+ root.style.background = '';
38040
+ root.style.boxShadow = '';
38041
+ body.style.overflow = '';
38042
+ body.style.background = '';
38043
+ };
38044
+ }
38045
+ }, [viewportMode]);
37533
38046
  require$$0.useEffect(() => {
37534
38047
  if (userConfig) {
37535
38048
  setConfig(userConfig);
@@ -37601,7 +38114,8 @@ const MarkupWidget = ({ config: userConfig, }) => {
37601
38114
  }, [setSelectedFeedback]);
37602
38115
  const handleBackFromDetail = require$$0.useCallback(() => {
37603
38116
  setSelectedFeedback(null);
37604
- }, [setSelectedFeedback]);
38117
+ setViewportMode(null);
38118
+ }, [setSelectedFeedback, setViewportMode]);
37605
38119
  const handleLogout = require$$0.useCallback(async () => {
37606
38120
  try {
37607
38121
  await logOut();
@@ -37614,6 +38128,15 @@ const MarkupWidget = ({ config: userConfig, }) => {
37614
38128
  const handleAuthSuccess = require$$0.useCallback(() => {
37615
38129
  setActiveTab("create");
37616
38130
  }, [setActiveTab]);
38131
+ const handleDeleteFeedback = require$$0.useCallback((id) => {
38132
+ removeFeedbackItem(id);
38133
+ setSelectedFeedback(null);
38134
+ }, [removeFeedbackItem, setSelectedFeedback]);
38135
+ const handleUpdateFeedback = require$$0.useCallback((updatedFeedback) => {
38136
+ updateFeedback(updatedFeedback);
38137
+ // Also update selected feedback if it's the same one (it should be)
38138
+ setSelectedFeedback(updatedFeedback);
38139
+ }, [updateFeedback, setSelectedFeedback]);
37617
38140
  const openFeedbackCount = feedbackItems.filter((f) => f.status === "open").length;
37618
38141
  ({
37619
38142
  ["--markup-primary"]: config.primaryColor || "#6366f1",
@@ -37621,15 +38144,15 @@ const MarkupWidget = ({ config: userConfig, }) => {
37621
38144
  ? adjustColor(config.primaryColor, -20)
37622
38145
  : "#4f46e5",
37623
38146
  });
37624
- return (jsxRuntime.jsxs("div", { className: cn("markup-widget fixed z-[999999] right-0 top-1/2 flex items-center transition-transform duration-300 ease-in-out", isOpen ? "" : "hover:translate-x-[-8px]"), style: {
37625
- transform: isOpen
37626
- ? "translateY(-50%) translateX(0)"
37627
- : "translateY(-50%) translateX(calc(100% - 40px))",
37628
- }, "data-markup-widget": true, children: [jsxRuntime.jsxs("div", { onClick: handleToggle, className: "relative bg-white h-fit flex items-center gap-2 px-2 pr-5 text-black border-none rounded-l-2xl cursor-pointer text-sm font-semibold transition-all py-5 shadow-lg", children: [isOpen && jsxRuntime.jsx(CloseIcon, { className: "w-5 h-5" }), jsxRuntime.jsx("span", { className: "text-black", style: { writingMode: "sideways-lr" }, children: "Siren" }), openFeedbackCount > 0 && (jsxRuntime.jsx("span", { className: "absolute -top-3 -left-1 min-w-[24px] h-[24px] px-1 bg-[#E6B6CF] text-black rounded-full text-xs font-semibold flex items-center justify-center", children: openFeedbackCount }))] }), jsxRuntime.jsxs("div", { className: "bg-white w-[500px] h-[750px] rounded-l-xl shadow-2xl overflow-hidden flex flex-col text-black", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-5 py-4 text-black", style: { backgroundColor: "var(--markup-primary)" }, children: [jsxRuntime.jsx("h2", { className: "text-base font-semibold m-0", children: ((_a = config.labels) === null || _a === void 0 ? void 0 : _a.feedbackTitle) || "Feedback" }), isAuthenticated && currentUser && (jsxRuntime.jsx("div", { onClick: handleLogout, className: "text-xs p-2 border-black border text-black rounded-xl ", children: jsxRuntime.jsx("h2", { children: "Sign Out" }) }))] }), !isAuthenticated ? (jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto", children: jsxRuntime.jsx(AuthForm, { onSuccess: handleAuthSuccess }) })) : selectedFeedback ? (jsxRuntime.jsx(FeedbackDetail, { feedback: selectedFeedback, onBack: handleBackFromDetail })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "flex border-b border-gray-200 px-5", children: [jsxRuntime.jsxs("div", { className: cn("flex-1 py-3 px-4 border border-b-0 border-gray-200 rounded-t-xl hover:bg-gray-100 cursor-pointer text-sm font-medium transition-all flex items-center justify-center gap-1", activeTab === "create"
37629
- ? "bg-gray-200"
37630
- : "border-white"), onClick: () => setActiveTab("create"), children: [jsxRuntime.jsx(PlusIcon, { className: "w-3.5 h-3.5" }), "New"] }), jsxRuntime.jsxs("div", { className: cn("flex-1 py-3 px-4 border border-b-0 border-gray-200 rounded-t-xl hover:bg-gray-100 cursor-pointer text-sm font-medium transition-all flex items-center justify-center gap-1", activeTab === "list"
37631
- ? "bg-gray-200"
37632
- : "border-white"), onClick: () => setActiveTab("list"), children: ["View All (", feedbackItems.length, ")"] })] }), jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-5", children: [activeTab === "create" && (jsxRuntime.jsx(FeedbackForm, { onSubmit: handleSubmitFeedback, onCancel: handleCancel })), activeTab === "list" && (jsxRuntime.jsx(FeedbackList, { feedbackItems: feedbackItems, onSelectFeedback: handleSelectFeedback }))] })] }))] })] }));
38147
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ViewportControls, {}), jsxRuntime.jsxs("div", { className: cn("markup-widget fixed z-[999999] right-0 top-1/2 flex items-center transition-transform duration-300 ease-in-out", isOpen ? "" : "hover:translate-x-[-8px]"), style: {
38148
+ transform: isOpen
38149
+ ? "translateY(-50%) translateX(0)"
38150
+ : "translateY(-50%) translateX(calc(100% - 40px))",
38151
+ }, "data-markup-widget": true, children: [jsxRuntime.jsxs("div", { onClick: handleToggle, className: "relative bg-white h-fit flex items-center gap-2 px-2 pr-5 text-black border-none rounded-l-2xl cursor-pointer text-sm font-semibold transition-all py-5 shadow-lg", children: [isOpen && jsxRuntime.jsx(CloseIcon, { className: "w-5 h-5" }), jsxRuntime.jsx("span", { className: "text-black", style: { writingMode: "sideways-lr" }, children: "Siren" }), openFeedbackCount > 0 && (jsxRuntime.jsx("span", { className: "absolute -top-3 -left-1 min-w-[24px] h-[24px] px-1 bg-[#E6B6CF] text-black rounded-full text-xs font-semibold flex items-center justify-center", children: openFeedbackCount }))] }), jsxRuntime.jsxs("div", { className: "bg-white w-[500px] h-[750px] rounded-l-xl shadow-2xl overflow-hidden flex flex-col text-black", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-5 py-4 text-black", style: { backgroundColor: "var(--markup-primary)" }, children: [jsxRuntime.jsx("h2", { className: "text-base font-semibold m-0", children: ((_a = config.labels) === null || _a === void 0 ? void 0 : _a.feedbackTitle) || "Feedback" }), isAuthenticated && currentUser && (jsxRuntime.jsx("div", { onClick: handleLogout, className: "text-xs py-2 px-4 bg-gray-50 border border-gray-200 text-black rounded-xl hover:bg-gray-200 cursor-pointer transition-all flex items-center gap-2", children: jsxRuntime.jsx("h2", { children: "Sign Out" }) }))] }), !isAuthenticated ? (jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto", children: jsxRuntime.jsx(AuthForm, { onSuccess: handleAuthSuccess }) })) : selectedFeedback ? (jsxRuntime.jsx(FeedbackDetail, { feedback: selectedFeedback, onBack: handleBackFromDetail, onDelete: handleDeleteFeedback, onUpdate: handleUpdateFeedback })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "flex border-b border-gray-200 px-5", children: [jsxRuntime.jsxs("div", { className: cn("flex-1 py-3 px-4 border border-b-0 border-gray-200 rounded-t-xl hover:bg-gray-100 cursor-pointer text-sm font-medium transition-all flex items-center justify-center gap-1", activeTab === "create"
38152
+ ? "bg-gray-200"
38153
+ : "border-white"), onClick: () => setActiveTab("create"), children: [jsxRuntime.jsx(PlusIcon, { className: "w-3.5 h-3.5" }), "New"] }), jsxRuntime.jsxs("div", { className: cn("flex-1 py-3 px-4 border border-b-0 border-gray-200 rounded-t-xl hover:bg-gray-100 cursor-pointer text-sm font-medium transition-all flex items-center justify-center gap-1", activeTab === "list"
38154
+ ? "bg-gray-200"
38155
+ : "border-white"), onClick: () => setActiveTab("list"), children: ["View All (", feedbackItems.length, ")"] })] }), jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-5", children: [activeTab === "create" && (jsxRuntime.jsx(FeedbackForm, { onSubmit: handleSubmitFeedback, onCancel: handleCancel, getSessionEvents: getSessionEvents, lastClickedElement: lastClickedElementRef.current, lastClickedText: lastClickedText })), activeTab === "list" && (jsxRuntime.jsx(FeedbackList, { feedbackItems: feedbackItems, onSelectFeedback: handleSelectFeedback }))] })] }))] })] })] }));
37633
38156
  };
37634
38157
  function adjustColor(color, amount) {
37635
38158
  const clamp = (val) => Math.min(255, Math.max(0, val));