react-visual-feedback 1.4.9 → 2.2.0
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/README.md +89 -3
- package/dist/index.esm.js +2 -2
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/integrations/config.js +664 -0
- package/dist/integrations/config.js.map +1 -0
- package/dist/integrations/index.js +4 -0
- package/dist/integrations/index.js.map +1 -0
- package/dist/server/index.js +2907 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/jira.js +1565 -0
- package/dist/server/jira.js.map +1 -0
- package/dist/server/sheets.js +1448 -0
- package/dist/server/sheets.js.map +1 -0
- package/package.json +30 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sources":["../../src/integrations/config.js"],"sourcesContent":["/**\n * Integration Configuration & Default Mappings\n * Users can customize these by passing their own config\n */\n\n// ============================================\n// ATLASSIAN DOCUMENT FORMAT (ADF) HELPER\n// ============================================\n\n/**\n * Convert plain text to Atlassian Document Format\n * Jira Cloud requires descriptions in ADF format\n */\nexport function textToADF(text) {\n const lines = text.split('\\n');\n const content = [];\n let currentParagraph = [];\n\n const flushParagraph = () => {\n if (currentParagraph.length > 0) {\n content.push({\n type: 'paragraph',\n content: currentParagraph\n });\n currentParagraph = [];\n }\n };\n\n lines.forEach((line, index) => {\n // Check if it's a section header (ALL CAPS)\n if (line.match(/^[A-Z][A-Z\\s]+$/) && line.trim().length > 0) {\n flushParagraph();\n content.push({\n type: 'heading',\n attrs: { level: 3 },\n content: [{ type: 'text', text: line }]\n });\n } else if (line === '---') {\n // Horizontal rule\n flushParagraph();\n content.push({ type: 'rule' });\n } else if (line.trim() === '') {\n // Empty line - flush paragraph\n flushParagraph();\n } else {\n // Regular line\n if (currentParagraph.length > 0) {\n currentParagraph.push({ type: 'hardBreak' });\n }\n currentParagraph.push({ type: 'text', text: line });\n }\n });\n\n flushParagraph();\n\n return {\n type: 'doc',\n version: 1,\n content: content.length > 0 ? content : [{ type: 'paragraph', content: [{ type: 'text', text: ' ' }] }]\n };\n}\n\n// ============================================\n// GOOGLE SHEETS COLUMN MAPPING\n// ============================================\n\nexport const DEFAULT_SHEET_COLUMNS = {\n timestamp: {\n key: 'timestamp',\n header: 'Timestamp',\n field: 'timestamp',\n transform: (value) => value || new Date().toISOString()\n },\n id: {\n key: 'id',\n header: 'Feedback ID',\n field: 'id'\n },\n feedback: {\n key: 'feedback',\n header: 'Feedback',\n field: 'feedback'\n },\n type: {\n key: 'type',\n header: 'Type',\n field: 'type',\n transform: (value) => value || 'bug'\n },\n status: {\n key: 'status',\n header: 'Status',\n field: 'status',\n transform: (value) => value || 'new'\n },\n userName: {\n key: 'userName',\n header: 'User Name',\n field: 'userName',\n transform: (value) => value || 'Anonymous'\n },\n userEmail: {\n key: 'userEmail',\n header: 'User Email',\n field: 'userEmail',\n transform: (value) => value || ''\n },\n url: {\n key: 'url',\n header: 'Page URL',\n field: 'url'\n },\n viewport: {\n key: 'viewport',\n header: 'Viewport',\n field: 'viewport',\n transform: (value) => value ? `${value.width}x${value.height}` : ''\n },\n userAgent: {\n key: 'userAgent',\n header: 'Browser',\n field: 'userAgent',\n transform: (value) => {\n if (!value) return '';\n // Simplify user agent\n if (value.includes('Chrome')) return 'Chrome';\n if (value.includes('Firefox')) return 'Firefox';\n if (value.includes('Safari')) return 'Safari';\n if (value.includes('Edge')) return 'Edge';\n return value.substring(0, 50);\n }\n },\n screenshot: {\n key: 'screenshot',\n header: 'Screenshot',\n field: 'screenshot',\n transform: (value) => value ? 'Yes' : 'No' // Don't store base64 in sheets\n },\n video: {\n key: 'video',\n header: 'Video',\n field: 'video',\n transform: (value) => value ? 'Yes' : 'No'\n },\n elementSelector: {\n key: 'elementSelector',\n header: 'Element',\n field: 'elementInfo',\n transform: (value) => value?.selector || ''\n },\n componentName: {\n key: 'componentName',\n header: 'Component',\n field: 'elementInfo',\n transform: (value) => value?.componentStack?.[0] || ''\n },\n sourceFile: {\n key: 'sourceFile',\n header: 'Source File',\n field: 'elementInfo',\n transform: (value) => value?.sourceFile || ''\n },\n jiraKey: {\n key: 'jiraKey',\n header: 'Jira Issue',\n field: 'jiraKey',\n transform: (value) => value || ''\n }\n};\n\n// Default columns to include (order matters)\nexport const DEFAULT_SHEET_COLUMN_ORDER = [\n 'timestamp',\n 'id',\n 'feedback',\n 'type',\n 'status',\n 'userName',\n 'userEmail',\n 'url',\n 'viewport',\n 'screenshot',\n 'video',\n 'jiraKey'\n];\n\n// ============================================\n// JIRA FIELD MAPPING\n// ============================================\n\nexport const DEFAULT_JIRA_FIELDS = {\n summary: {\n key: 'summary',\n source: 'feedback',\n maxLength: 255,\n prefix: '[Feedback] ',\n transform: (data) => {\n const prefix = '[Feedback] ';\n const text = data.feedback || 'User Feedback';\n const maxLen = 255 - prefix.length;\n return prefix + (text.length > maxLen ? text.substring(0, maxLen - 3) + '...' : text);\n }\n },\n description: {\n key: 'description',\n // Build description directly - no wiki markup, clean plain text for ADF\n transform: (data) => {\n const lines = [];\n\n // Feedback Details\n lines.push('FEEDBACK DETAILS');\n lines.push(`Feedback: ${data.feedback || 'No feedback provided'}`);\n lines.push(`Type: ${data.type || 'bug'}`);\n lines.push(`Status: ${data.status || 'new'}`);\n lines.push('');\n\n // User Information\n lines.push('USER INFORMATION');\n lines.push(`Name: ${data.userName || 'Anonymous'}`);\n lines.push(`Email: ${data.userEmail || 'Not provided'}`);\n lines.push('');\n\n // Technical Details\n lines.push('TECHNICAL DETAILS');\n lines.push(`Page URL: ${data.url || 'N/A'}`);\n if (data.viewport) {\n lines.push(`Viewport: ${data.viewport.width}x${data.viewport.height}`);\n }\n if (data.userAgent) {\n // Simplify user agent\n let browser = data.userAgent;\n if (browser.includes('Chrome')) browser = 'Chrome';\n else if (browser.includes('Firefox')) browser = 'Firefox';\n else if (browser.includes('Safari')) browser = 'Safari';\n else if (browser.includes('Edge')) browser = 'Edge';\n lines.push(`Browser: ${browser}`);\n }\n\n // Element info\n if (data.elementInfo) {\n if (data.elementInfo.selector) {\n lines.push(`Element: ${data.elementInfo.selector}`);\n }\n if (data.elementInfo.componentStack?.length) {\n lines.push(`Component: ${data.elementInfo.componentStack.join(' > ')}`);\n }\n if (data.elementInfo.sourceFile) {\n lines.push(`Source: ${data.elementInfo.sourceFile}:${data.elementInfo.lineNumber || ''}`);\n }\n }\n lines.push('');\n\n // Attachments\n const attachments = [];\n if (data.screenshot) attachments.push('Screenshot');\n if (data.video) attachments.push('Screen Recording');\n if (attachments.length > 0) {\n lines.push('ATTACHMENTS');\n lines.push(attachments.join(', ') + ' attached');\n lines.push('');\n }\n\n lines.push('---');\n lines.push('Submitted via React Visual Feedback');\n\n return lines.join('\\n');\n }\n },\n issuetype: {\n key: 'issuetype',\n // Default to 'Task' which exists in most Jira projects\n // Can be overridden via JIRA_ISSUE_TYPE env var or config\n value: 'Task',\n // Map feedback types to Jira issue types (all default to Task for compatibility)\n typeMapping: {\n bug: 'Task',\n feature: 'Task',\n improvement: 'Task',\n question: 'Task',\n other: 'Task'\n },\n transform: (data, config) => {\n // Priority: env var > config value > type mapping > default\n const envIssueType = typeof process !== 'undefined' ? process.env?.JIRA_ISSUE_TYPE : null;\n if (envIssueType) return envIssueType;\n if (config?.value && config.value !== 'Task') return config.value;\n const mapping = config?.typeMapping || DEFAULT_JIRA_FIELDS.issuetype.typeMapping;\n return mapping[data.type] || config?.value || 'Task';\n }\n },\n labels: {\n key: 'labels',\n value: ['user-feedback'],\n transform: (data, config) => {\n const labels = [...(config?.value || ['user-feedback'])];\n if (data.type) labels.push(`type-${data.type}`);\n return labels;\n }\n },\n priority: {\n key: 'priority',\n // Map to Jira priority IDs (user can customize)\n priorityMapping: {\n bug: 'High',\n feature: 'Medium',\n improvement: 'Medium',\n question: 'Low',\n other: 'Low'\n },\n transform: (data, config) => {\n const mapping = config?.priorityMapping || DEFAULT_JIRA_FIELDS.priority.priorityMapping;\n return mapping[data.type] || 'Medium';\n }\n }\n};\n\n// ============================================\n// JIRA STATUS MAPPING (Bidirectional sync)\n// ============================================\n\nexport const DEFAULT_JIRA_STATUS_MAPPING = {\n // Our status -> Jira status\n toJira: {\n new: 'To Do',\n open: 'To Do',\n inProgress: 'In Progress',\n underReview: 'In Review',\n onHold: 'On Hold',\n resolved: 'Done',\n closed: 'Done',\n wontFix: 'Won\\'t Do'\n },\n // Jira status -> Our status\n fromJira: {\n 'To Do': 'open',\n 'Open': 'open',\n 'In Progress': 'inProgress',\n 'In Review': 'underReview',\n 'On Hold': 'onHold',\n 'Done': 'resolved',\n 'Closed': 'closed',\n 'Won\\'t Do': 'wontFix',\n 'Resolved': 'resolved'\n }\n};\n\n// ============================================\n// INTEGRATION TYPES\n// ============================================\n\nexport const INTEGRATION_TYPES = {\n JIRA: {\n SERVER: 'server', // Our server handler\n AUTOMATION: 'jira-automation', // Jira's built-in webhooks\n ZAPIER: 'zapier' // Zapier webhook\n },\n SHEETS: {\n SERVER: 'server', // Our server handler (Service Account)\n OAUTH: 'oauth', // OAuth with refresh\n APPS_SCRIPT: 'google-apps-script', // Google Apps Script\n ZAPIER: 'zapier' // Zapier webhook\n }\n};\n\n// ============================================\n// HELPER FUNCTIONS\n// ============================================\n\n/**\n * Merge user config with defaults\n */\nexport function mergeSheetColumns(userColumns = {}, columnOrder = null) {\n const merged = { ...DEFAULT_SHEET_COLUMNS };\n\n // Apply user overrides\n Object.entries(userColumns).forEach(([key, value]) => {\n if (value === null || value === false) {\n // Remove column\n delete merged[key];\n } else if (typeof value === 'object') {\n // Merge with default\n merged[key] = { ...merged[key], ...value };\n }\n });\n\n // Determine column order\n const order = columnOrder || Object.keys(merged).filter(k =>\n DEFAULT_SHEET_COLUMN_ORDER.includes(k) || userColumns[k]\n );\n\n return { columns: merged, order };\n}\n\n/**\n * Merge user Jira config with defaults\n */\nexport function mergeJiraFields(userFields = {}) {\n const merged = { ...DEFAULT_JIRA_FIELDS };\n\n Object.entries(userFields).forEach(([key, value]) => {\n if (value === null || value === false) {\n delete merged[key];\n } else if (typeof value === 'object') {\n merged[key] = { ...merged[key], ...value };\n }\n });\n\n return merged;\n}\n\n/**\n * Transform feedback data to sheet row\n */\nexport function feedbackToSheetRow(feedbackData, config = {}) {\n const { columns, order } = mergeSheetColumns(config.columns, config.columnOrder);\n\n const row = order.map(key => {\n const col = columns[key];\n if (!col) return '';\n\n const rawValue = feedbackData[col.field];\n if (col.transform) {\n return col.transform(rawValue) || '';\n }\n return rawValue || '';\n });\n\n return row;\n}\n\n/**\n * Get sheet headers\n */\nexport function getSheetHeaders(config = {}) {\n const { columns, order } = mergeSheetColumns(config.columns, config.columnOrder);\n return order.map(key => columns[key]?.header || key);\n}\n\n/**\n * Transform feedback data to Jira issue\n */\nexport function feedbackToJiraIssue(feedbackData, config = {}) {\n const fields = mergeJiraFields(config.fields);\n\n // Get plain text description and convert to ADF\n const plainDescription = fields.description.transform(feedbackData, fields.description);\n const adfDescription = textToADF(plainDescription);\n\n const issue = {\n fields: {\n project: { key: config.projectKey },\n summary: fields.summary.transform(feedbackData, fields.summary),\n description: adfDescription,\n issuetype: { name: fields.issuetype.transform(feedbackData, fields.issuetype) }\n }\n };\n\n // Add labels if configured\n if (fields.labels) {\n issue.fields.labels = fields.labels.transform(feedbackData, fields.labels);\n }\n\n // Add priority if configured and user wants it\n if (config.includePriority && fields.priority) {\n issue.fields.priority = { name: fields.priority.transform(feedbackData, fields.priority) };\n }\n\n // Add custom fields\n if (config.customFields) {\n Object.entries(config.customFields).forEach(([fieldId, fieldConfig]) => {\n if (typeof fieldConfig === 'string') {\n issue.fields[fieldId] = feedbackData[fieldConfig];\n } else if (fieldConfig.transform) {\n issue.fields[fieldId] = fieldConfig.transform(feedbackData);\n } else if (fieldConfig.value) {\n issue.fields[fieldId] = fieldConfig.value;\n }\n });\n }\n\n return issue;\n}\n\n/**\n * Map Jira status to our status\n */\nexport function mapJiraStatusToLocal(jiraStatus, customMapping = {}) {\n const mapping = { ...DEFAULT_JIRA_STATUS_MAPPING.fromJira, ...customMapping };\n return mapping[jiraStatus] || 'open';\n}\n\n/**\n * Map our status to Jira status\n */\nexport function mapLocalStatusToJira(localStatus, customMapping = {}) {\n const mapping = { ...DEFAULT_JIRA_STATUS_MAPPING.toJira, ...customMapping };\n return mapping[localStatus] || 'To Do';\n}\n"],"names":["textToADF","text","lines","split","content","currentParagraph","flushParagraph","length","push","type","forEach","line","index","match","trim","attrs","level","version","DEFAULT_SHEET_COLUMNS","timestamp","key","header","field","transform","value","Date","toISOString","id","feedback","status","userName","userEmail","url","viewport","concat","width","height","userAgent","includes","substring","screenshot","video","elementSelector","selector","componentName","_value$componentStack","componentStack","sourceFile","jiraKey","DEFAULT_SHEET_COLUMN_ORDER","DEFAULT_JIRA_FIELDS","summary","source","maxLength","prefix","data","maxLen","description","browser","elementInfo","_data$elementInfo$com","join","lineNumber","attachments","issuetype","typeMapping","bug","feature","improvement","question","other","config","_process$env","envIssueType","process","env","JIRA_ISSUE_TYPE","mapping","labels","_toConsumableArray","priority","priorityMapping","DEFAULT_JIRA_STATUS_MAPPING","toJira","open","inProgress","underReview","onHold","resolved","closed","wontFix","fromJira","INTEGRATION_TYPES","JIRA","SERVER","AUTOMATION","ZAPIER","SHEETS","OAUTH","APPS_SCRIPT","mergeSheetColumns","userColumns","arguments","undefined","columnOrder","merged","_objectSpread","Object","entries","_ref","_ref2","_slicedToArray","_typeof","order","keys","filter","k","columns","mergeJiraFields","userFields","_ref3","_ref4","feedbackToSheetRow","feedbackData","_mergeSheetColumns","row","map","col","rawValue","getSheetHeaders","_mergeSheetColumns2","_columns$key","feedbackToJiraIssue","fields","plainDescription","adfDescription","issue","project","projectKey","name","includePriority","customFields","_ref5","_ref6","fieldId","fieldConfig","mapJiraStatusToLocal","jiraStatus","customMapping","mapLocalStatusToJira","localStatus"],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{useRef as e,useState as n,useEffect as t,useCallback as r}from"react";function o(e,n){(null==n||n>e.length)&&(n=e.length);for(var t=0,r=Array(n);t<n;t++)r[t]=e[t];return r}function a(e,n,t,r,o,a,i){try{var s=e[a](i),u=s.value}catch(e){return void t(e)}s.done?n(u):Promise.resolve(u).then(r,o)}function i(e){return function(){var n=this,t=arguments;return new Promise(function(r,o){var i=e.apply(n,t);function s(e){a(i,r,o,s,u,"next",e)}function u(e){a(i,r,o,s,u,"throw",e)}s(void 0)})}}function s(e,n,t){return n&&function(e,n){for(var t=0;t<n.length;t++){var r=n[t];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,m(r.key),r)}}(e.prototype,n),Object.defineProperty(e,"prototype",{writable:!1}),e}function u(e,n,t){return(n=m(n))in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function c(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter(function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable})),t.push.apply(t,r)}return t}function l(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?c(Object(t),!0).forEach(function(n){u(e,n,t[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):c(Object(t)).forEach(function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))})}return e}function d(e,n){if(null==e)return{};var t,r,o=function(e,n){if(null==e)return{};var t={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(-1!==n.indexOf(r))continue;t[r]=e[r]}return t}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)t=a[r],-1===n.indexOf(t)&&{}.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}function f(){
|
|
2
|
+
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
|
|
3
|
+
var e,n,t="function"==typeof Symbol?Symbol:{},r=t.iterator||"@@iterator",o=t.toStringTag||"@@toStringTag";function a(t,r,o,a){var u=r&&r.prototype instanceof s?r:s,c=Object.create(u.prototype);return p(c,"_invoke",function(t,r,o){var a,s,u,c=0,l=o||[],d=!1,f={p:0,n:0,v:e,a:p,f:p.bind(e,4),d:function(n,t){return a=n,s=0,u=e,f.n=t,i}};function p(t,r){for(s=t,u=r,n=0;!d&&c&&!o&&n<l.length;n++){var o,a=l[n],p=f.p,h=a[2];t>3?(o=h===r)&&(u=a[(s=a[4])?5:(s=3,3)],a[4]=a[5]=e):a[0]<=p&&((o=t<2&&p<a[1])?(s=0,f.v=r,f.n=a[1]):p<h&&(o=t<3||a[0]>r||r>h)&&(a[4]=t,a[5]=r,f.n=h,s=0))}if(o||t>1)return i;throw d=!0,r}return function(o,l,h){if(c>1)throw TypeError("Generator is already running");for(d&&1===l&&p(l,h),s=l,u=h;(n=s<2?e:u)||!d;){a||(s?s<3?(s>1&&(f.n=-1),p(s,u)):f.n=u:f.v=u);try{if(c=2,a){if(s||(o="next"),n=a[o]){if(!(n=n.call(a,u)))throw TypeError("iterator result is not an object");if(!n.done)return n;u=n.value,s<2&&(s=0)}else 1===s&&(n=a.return)&&n.call(a),s<2&&(u=TypeError("The iterator does not provide a '"+o+"' method"),s=1);a=e}else if((n=(d=f.n<0)?u:t.call(r,f))!==i)break}catch(n){a=e,s=1,u=n}finally{c=1}}return{value:n,done:d}}}(t,o,a),!0),c}var i={};function s(){}function u(){}function c(){}n=Object.getPrototypeOf;var l=[][r]?n(n([][r]())):(p(n={},r,function(){return this}),n),d=c.prototype=s.prototype=Object.create(l);function h(e){return Object.setPrototypeOf?Object.setPrototypeOf(e,c):(e.__proto__=c,p(e,o,"GeneratorFunction")),e.prototype=Object.create(d),e}return u.prototype=c,p(d,"constructor",c),p(c,"constructor",u),u.displayName="GeneratorFunction",p(c,o,"GeneratorFunction"),p(d),p(d,o,"Generator"),p(d,r,function(){return this}),p(d,"toString",function(){return"[object Generator]"}),(f=function(){return{w:a,m:h}})()}function p(e,n,t,r){var o=Object.defineProperty;try{o({},"",{})}catch(e){o=0}p=function(e,n,t,r){function a(n,t){p(e,n,function(e){return this._invoke(n,t,e)})}n?o?o(e,n,{value:t,enumerable:!r,configurable:!r,writable:!r}):e[n]=t:(a("next",0),a("throw",1),a("return",2))},p(e,n,t,r)}function h(e,n){return function(e){if(Array.isArray(e))return e}(e)||function(e,n){var t=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=t){var r,o,a,i,s=[],u=!0,c=!1;try{if(a=(t=t.call(e)).next,0===n);else for(;!(u=(r=a.call(t)).done)&&(s.push(r.value),s.length!==n);u=!0);}catch(e){c=!0,o=e}finally{try{if(!u&&null!=t.return&&(i=t.return(),Object(i)!==i))return}finally{if(c)throw o}}return s}}(e,n)||b(e,n)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function y(e){return function(e){if(Array.isArray(e))return o(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||b(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function m(e){var n=function(e,n){if("object"!=typeof e||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var r=t.call(e,n);if("object"!=typeof r)return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===n?String:Number)(e)}(e,"string");return"symbol"==typeof n?n:n+""}function v(e){return v="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},v(e)}function b(e,n){if(e){if("string"==typeof e)return o(e,n);var t={}.toString.call(e).slice(8,-1);return"Object"===t&&e.constructor&&(t=e.constructor.name),"Map"===t||"Set"===t?Array.from(e):"Arguments"===t||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?o(e,n):void 0}}var g={timestamp:{key:"timestamp",header:"Timestamp",field:"timestamp",transform:function(e){return e||(new Date).toISOString()}},id:{key:"id",header:"Feedback ID",field:"id"},feedback:{key:"feedback",header:"Feedback",field:"feedback"},type:{key:"type",header:"Type",field:"type",transform:function(e){return e||"bug"}},status:{key:"status",header:"Status",field:"status",transform:function(e){return e||"new"}},userName:{key:"userName",header:"User Name",field:"userName",transform:function(e){return e||"Anonymous"}},userEmail:{key:"userEmail",header:"User Email",field:"userEmail",transform:function(e){return e||""}},url:{key:"url",header:"Page URL",field:"url"},viewport:{key:"viewport",header:"Viewport",field:"viewport",transform:function(e){return e?"".concat(e.width,"x").concat(e.height):""}},userAgent:{key:"userAgent",header:"Browser",field:"userAgent",transform:function(e){return e?e.includes("Chrome")?"Chrome":e.includes("Firefox")?"Firefox":e.includes("Safari")?"Safari":e.includes("Edge")?"Edge":e.substring(0,50):""}},screenshot:{key:"screenshot",header:"Screenshot",field:"screenshot",transform:function(e){return e?"Yes":"No"}},video:{key:"video",header:"Video",field:"video",transform:function(e){return e?"Yes":"No"}},elementSelector:{key:"elementSelector",header:"Element",field:"elementInfo",transform:function(e){return(null==e?void 0:e.selector)||""}},componentName:{key:"componentName",header:"Component",field:"elementInfo",transform:function(e){var n;return(null==e||null===(n=e.componentStack)||void 0===n?void 0:n[0])||""}},sourceFile:{key:"sourceFile",header:"Source File",field:"elementInfo",transform:function(e){return(null==e?void 0:e.sourceFile)||""}},jiraKey:{key:"jiraKey",header:"Jira Issue",field:"jiraKey",transform:function(e){return e||""}}},S=["timestamp","id","feedback","type","status","userName","userEmail","url","viewport","screenshot","video","jiraKey"],w={summary:{key:"summary",source:"feedback",maxLength:255,prefix:"[Feedback] ",transform:function(e){var n="[Feedback] ",t=e.feedback||"User Feedback";return n+(t.length>244?t.substring(0,241)+"...":t)}},description:{key:"description",transform:function(e){var n,t=[];if(t.push("FEEDBACK DETAILS"),t.push("Feedback: ".concat(e.feedback||"No feedback provided")),t.push("Type: ".concat(e.type||"bug")),t.push("Status: ".concat(e.status||"new")),t.push(""),t.push("USER INFORMATION"),t.push("Name: ".concat(e.userName||"Anonymous")),t.push("Email: ".concat(e.userEmail||"Not provided")),t.push(""),t.push("TECHNICAL DETAILS"),t.push("Page URL: ".concat(e.url||"N/A")),e.viewport&&t.push("Viewport: ".concat(e.viewport.width,"x").concat(e.viewport.height)),e.userAgent){var r=e.userAgent;r.includes("Chrome")?r="Chrome":r.includes("Firefox")?r="Firefox":r.includes("Safari")?r="Safari":r.includes("Edge")&&(r="Edge"),t.push("Browser: ".concat(r))}e.elementInfo&&(e.elementInfo.selector&&t.push("Element: ".concat(e.elementInfo.selector)),null!==(n=e.elementInfo.componentStack)&&void 0!==n&&n.length&&t.push("Component: ".concat(e.elementInfo.componentStack.join(" > "))),e.elementInfo.sourceFile&&t.push("Source: ".concat(e.elementInfo.sourceFile,":").concat(e.elementInfo.lineNumber||"")));t.push("");var o=[];return e.screenshot&&o.push("Screenshot"),e.video&&o.push("Screen Recording"),o.length>0&&(t.push("ATTACHMENTS"),t.push(o.join(", ")+" attached"),t.push("")),t.push("---"),t.push("Submitted via React Visual Feedback"),t.join("\n")}},issuetype:{key:"issuetype",value:"Task",typeMapping:{bug:"Task",feature:"Task",improvement:"Task",question:"Task",other:"Task"},transform:function(e,n){var t,r="undefined"!=typeof process?null===(t=process.env)||void 0===t?void 0:t.JIRA_ISSUE_TYPE:null;return r||(null!=n&&n.value&&"Task"!==n.value?n.value:((null==n?void 0:n.typeMapping)||w.issuetype.typeMapping)[e.type]||(null==n?void 0:n.value)||"Task")}},labels:{key:"labels",value:["user-feedback"],transform:function(e,n){var t=y((null==n?void 0:n.value)||["user-feedback"]);return e.type&&t.push("type-".concat(e.type)),t}},priority:{key:"priority",priorityMapping:{bug:"High",feature:"Medium",improvement:"Medium",question:"Low",other:"Low"},transform:function(e,n){return((null==n?void 0:n.priorityMapping)||w.priority.priorityMapping)[e.type]||"Medium"}}},k={toJira:{new:"To Do",open:"To Do",inProgress:"In Progress",underReview:"In Review",onHold:"On Hold",resolved:"Done",closed:"Done",wontFix:"Won't Do"},fromJira:{"To Do":"open",Open:"open","In Progress":"inProgress","In Review":"underReview","On Hold":"onHold",Done:"resolved",Closed:"closed","Won't Do":"wontFix",Resolved:"resolved"}},E={JIRA:{SERVER:"server",AUTOMATION:"jira-automation",ZAPIER:"zapier"},SHEETS:{SERVER:"server",OAUTH:"oauth",APPS_SCRIPT:"google-apps-script",ZAPIER:"zapier"}};function j(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,t=l({},g);Object.entries(e).forEach(function(e){var n=h(e,2),r=n[0],o=n[1];null===o||!1===o?delete t[r]:"object"===v(o)&&(t[r]=l(l({},t[r]),o))});var r=n||Object.keys(t).filter(function(n){return S.includes(n)||e[n]});return{columns:t,order:r}}function T(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},t=j(n.columns,n.columnOrder),r=t.columns;return t.order.map(function(n){var t=r[n];if(!t)return"";var o=e[t.field];return t.transform?t.transform(o)||"":o||""})}function O(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=j(e.columns,e.columnOrder),t=n.columns;return n.order.map(function(e){var n;return(null===(n=t[e])||void 0===n?void 0:n.header)||e})}function A(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=O(e);return"\n/**\n * React Visual Feedback - Google Apps Script Handler\n *\n * Setup:\n * 1. Open your Google Sheet\n * 2. Extensions > Apps Script\n * 3. Paste this code\n * 4. Deploy > New deployment > Web app\n * 5. Execute as: Me, Who has access: Anyone\n * 6. Copy the URL and use in your React app\n */\n\n// Sheet configuration\nconst SHEET_NAME = '".concat(e.sheetName||"Feedback","';\nconst HEADERS = ").concat(JSON.stringify(n),";\n\n/**\n * Handle POST requests\n */\nfunction doPost(e) {\n try {\n const data = JSON.parse(e.postData.contents);\n const action = data.action || 'append';\n\n let result;\n\n switch (action) {\n case 'append':\n result = appendFeedback(data.feedbackData);\n break;\n case 'updateStatus':\n result = updateStatus(data.feedbackId, data.status);\n break;\n case 'getRows':\n result = getRows(data.limit || 100);\n break;\n default:\n throw new Error('Unknown action: ' + action);\n }\n\n return ContentService\n .createTextOutput(JSON.stringify(result))\n .setMimeType(ContentService.MimeType.JSON);\n\n } catch (error) {\n return ContentService\n .createTextOutput(JSON.stringify({ success: false, error: error.message }))\n .setMimeType(ContentService.MimeType.JSON);\n }\n}\n\n/**\n * Handle GET requests (for testing)\n */\nfunction doGet(e) {\n return ContentService\n .createTextOutput(JSON.stringify({ status: 'ok', message: 'Feedback API ready' }))\n .setMimeType(ContentService.MimeType.JSON);\n}\n\n/**\n * Append feedback to sheet\n */\nfunction appendFeedback(feedbackData) {\n const sheet = getOrCreateSheet();\n\n const row = [\n new Date().toISOString(), // Timestamp\n feedbackData.id || '', // ID\n feedbackData.feedback || '', // Feedback\n feedbackData.type || 'bug', // Type\n feedbackData.status || 'new', // Status\n feedbackData.userName || 'Anonymous', // User Name\n feedbackData.userEmail || '', // User Email\n feedbackData.url || '', // Page URL\n feedbackData.viewport ? feedbackData.viewport.width + 'x' + feedbackData.viewport.height : '', // Viewport\n feedbackData.screenshot ? 'Yes' : 'No', // Screenshot\n feedbackData.video ? 'Yes' : 'No', // Video\n feedbackData.jiraKey || '' // Jira Key\n ];\n\n sheet.appendRow(row);\n\n return {\n success: true,\n row: sheet.getLastRow()\n };\n}\n\n/**\n * Update feedback status\n */\nfunction updateStatus(feedbackId, newStatus) {\n const sheet = getOrCreateSheet();\n const data = sheet.getDataRange().getValues();\n\n // Find row with matching ID (column B, index 1)\n for (let i = 1; i < data.length; i++) {\n if (data[i][1] === feedbackId) {\n // Update status (column E, index 4)\n sheet.getRange(i + 1, 5).setValue(newStatus);\n return { success: true, row: i + 1 };\n }\n }\n\n return { success: false, error: 'Feedback not found' };\n}\n\n/**\n * Get rows from sheet\n */\nfunction getRows(limit) {\n const sheet = getOrCreateSheet();\n const data = sheet.getDataRange().getValues();\n\n const rows = data.slice(1, limit + 1).map((row, index) => ({\n rowNumber: index + 2,\n timestamp: row[0],\n id: row[1],\n feedback: row[2],\n type: row[3],\n status: row[4],\n userName: row[5],\n userEmail: row[6],\n url: row[7],\n viewport: row[8],\n hasScreenshot: row[9] === 'Yes',\n hasVideo: row[10] === 'Yes',\n jiraKey: row[11]\n }));\n\n return { success: true, rows };\n}\n\n/**\n * Get or create the feedback sheet\n */\nfunction getOrCreateSheet() {\n const ss = SpreadsheetApp.getActiveSpreadsheet();\n let sheet = ss.getSheetByName(SHEET_NAME);\n\n if (!sheet) {\n sheet = ss.insertSheet(SHEET_NAME);\n sheet.appendRow(HEADERS);\n\n // Format headers\n const headerRange = sheet.getRange(1, 1, 1, HEADERS.length);\n headerRange.setFontWeight('bold');\n headerRange.setBackground('#4285f4');\n headerRange.setFontColor('#ffffff');\n }\n\n return sheet;\n}\n\n/**\n * Update Jira key for a feedback item\n */\nfunction updateJiraKey(feedbackId, jiraKey) {\n const sheet = getOrCreateSheet();\n const data = sheet.getDataRange().getValues();\n\n for (let i = 1; i < data.length; i++) {\n if (data[i][1] === feedbackId) {\n // Update Jira key (column L, index 11)\n sheet.getRange(i + 1, 12).setValue(jiraKey);\n return { success: true, row: i + 1 };\n }\n }\n\n return { success: false, error: 'Feedback not found' };\n}\n").trim()}var R=["video","videoBlob","screenshot","eventLogs"],I=function(){return s(function e(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,e),this.jiraConfig=n.jira||null,this.sheetsConfig=n.sheets||null,this.onError=n.onError||function(){},this.onSuccess=n.onSuccess||function(){}},[{key:"sendFeedback",value:(y=i(f().m(function e(n){var t,r,o,a,i,s,u,c,l,d=arguments;return f().w(function(e){for(;;)switch(e.n){case 0:return s={jira:null,sheets:null},u=void 0!==(i=d.length>1&&void 0!==d[1]?d[1]:{}).jira?i.jira:null===(t=this.jiraConfig)||void 0===t?void 0:t.enabled,c=void 0!==i.sheets?i.sheets:null===(r=this.sheetsConfig)||void 0===r?void 0:r.enabled,l=[],u&&null!==(o=this.jiraConfig)&&void 0!==o&&o.enabled&&l.push(this.sendToJira(n).then(function(e){s.jira=e}).catch(function(e){s.jira={success:!1,error:e.message}})),c&&null!==(a=this.sheetsConfig)&&void 0!==a&&a.enabled&&l.push(this.sendToSheets(n).then(function(e){s.sheets=e}).catch(function(e){s.sheets={success:!1,error:e.message}})),e.n=1,Promise.all(l);case 1:return e.a(2,s)}},e,this)})),function(e){return y.apply(this,arguments)})},{key:"sendToJira",value:(h=i(f().m(function e(n){var t,r,o;return f().w(function(e){for(;;)switch(e.n){case 0:if(null!=(t=this.jiraConfig)&&t.enabled){e.n=1;break}return e.a(2,{success:!1,error:"Jira integration not enabled"});case 1:r=t.type||E.JIRA.SERVER,o=r,e.n=o===E.JIRA.SERVER?2:o===E.JIRA.AUTOMATION?3:o===E.JIRA.ZAPIER?4:5;break;case 2:return e.a(2,this.sendToJiraServer(n,t));case 3:return e.a(2,this.sendToJiraAutomation(n,t));case 4:return e.a(2,this.sendToZapier(n,t.webhookUrl,"jira"));case 5:throw new Error("Unknown Jira integration type: ".concat(r));case 6:return e.a(2)}},e,this)})),function(e){return h.apply(this,arguments)})},{key:"sendToJiraServer",value:(p=i(f().m(function e(n,t){var r,o,a,i,s,u,c,l,p,h,y,m,v,b,g;return f().w(function(e){for(;;)switch(e.n){case 0:if(r=t.endpoint||"/api/feedback/jira",(o=new FormData).append("action","create"),a=n.video,i=n.videoBlob,s=n.screenshot,u=n.eventLogs,c=d(n,R),o.append("metadata",JSON.stringify(c)),!s){e.n=3;break}if(!(s instanceof Blob)){e.n=1;break}o.append("screenshot",s,"screenshot.png"),e.n=3;break;case 1:if("string"!=typeof s||!s.startsWith("data:")){e.n=3;break}return e.n=2,this.dataURLToBlob(s);case 2:(l=e.v)&&o.append("screenshot",l,"screenshot.png");case 3:if(!(i&&i instanceof Blob)){e.n=4;break}p=i.type.includes("mp4")?"mp4":"webm",o.append("video",i,"recording.".concat(p)),e.n=6;break;case 4:if(!a){e.n=6;break}if("string"!=typeof a||!a.startsWith("data:")){e.n=6;break}return e.n=5,this.dataURLToBlob(a);case 5:(h=e.v)&&(y=a.includes("video/mp4")?"mp4":"webm",o.append("video",h,"recording.".concat(y)));case 6:return u&&u.length>0&&(m=new Blob([JSON.stringify(u,null,2)],{type:"application/json"}),o.append("eventLogs",m,"session-logs.json")),e.n=7,fetch(r,{method:"POST",body:o});case 7:if((v=e.v).ok){e.n=9;break}return e.n=8,v.text();case 8:throw b=e.v,new Error(b);case 9:return e.n=10,v.json();case 10:return g=e.v,this.onSuccess("jira",g),e.a(2,g)}},e,this)})),function(e,n){return p.apply(this,arguments)})},{key:"dataURLToBlob",value:(l=i(f().m(function e(n){var t;return f().w(function(e){for(;;)switch(e.p=e.n){case 0:return e.p=0,e.n=1,fetch(n);case 1:return t=e.v,e.n=2,t.blob();case 2:return e.a(2,e.v);case 3:return e.p=3,e.v,e.a(2,null)}},e,null,[[0,3]])})),function(e){return l.apply(this,arguments)})},{key:"sendToJiraAutomation",value:(c=i(f().m(function e(n,t){var r,o,a;return f().w(function(e){for(;;)switch(e.n){case 0:if(t.webhookUrl){e.n=1;break}throw new Error("Jira Automation webhook URL not configured");case 1:return r={summary:"[Feedback] ".concat((n.feedback||"").substring(0,200)),description:n.feedback,type:n.type||"bug",userName:n.userName||"Anonymous",userEmail:n.userEmail||"",url:n.url||"",viewport:n.viewport?"".concat(n.viewport.width,"x").concat(n.viewport.height):"",hasScreenshot:!!n.screenshot,hasVideo:!!n.video,timestamp:n.timestamp||(new Date).toISOString(),feedbackId:n.id},e.n=2,fetch(t.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});case 2:if((o=e.v).ok){e.n=3;break}throw new Error("Jira Automation webhook failed: ".concat(o.status));case 3:return a={success:!0,type:"jira-automation"},this.onSuccess("jira",a),e.a(2,a)}},e,this)})),function(e,n){return c.apply(this,arguments)})},{key:"sendToSheets",value:(u=i(f().m(function e(n){var t,r,o;return f().w(function(e){for(;;)switch(e.n){case 0:if(null!=(t=this.sheetsConfig)&&t.enabled){e.n=1;break}return e.a(2,{success:!1,error:"Sheets integration not enabled"});case 1:r=t.type||E.SHEETS.SERVER,o=r,e.n=o===E.SHEETS.SERVER||o===E.SHEETS.OAUTH?2:o===E.SHEETS.APPS_SCRIPT?3:o===E.SHEETS.ZAPIER?4:5;break;case 2:return e.a(2,this.sendToSheetsServer(n,t));case 3:return e.a(2,this.sendToAppsScript(n,t));case 4:return e.a(2,this.sendToZapier(n,t.webhookUrl,"sheets"));case 5:throw new Error("Unknown Sheets integration type: ".concat(r));case 6:return e.a(2)}},e,this)})),function(e){return u.apply(this,arguments)})},{key:"sendToSheetsServer",value:(a=i(f().m(function e(n,t){var r,o,a,i;return f().w(function(e){for(;;)switch(e.n){case 0:return r=t.endpoint||"/api/feedback/sheets",e.n=1,fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"append",feedbackData:n})});case 1:if((o=e.v).ok){e.n=3;break}return e.n=2,o.text();case 2:throw a=e.v,new Error(a);case 3:return e.n=4,o.json();case 4:return i=e.v,this.onSuccess("sheets",i),e.a(2,i)}},e,this)})),function(e,n){return a.apply(this,arguments)})},{key:"sendToAppsScript",value:(o=i(f().m(function e(n,t){var r,o;return f().w(function(e){for(;;)switch(e.n){case 0:if(t.deploymentUrl){e.n=1;break}throw new Error("Google Apps Script deployment URL not configured");case 1:return e.n=2,fetch(t.deploymentUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"append",feedbackData:n})});case 2:if((r=e.v).ok){e.n=3;break}throw new Error("Apps Script request failed: ".concat(r.status));case 3:return e.n=4,r.json();case 4:if((o=e.v).success){e.n=5;break}throw new Error(o.error||"Apps Script returned error");case 5:return this.onSuccess("sheets",o),e.a(2,o)}},e,this)})),function(e,n){return o.apply(this,arguments)})},{key:"sendToZapier",value:(r=i(f().m(function e(n,t,r){var o,a,i,s,u;return f().w(function(e){for(;;)switch(e.n){case 0:if(t){e.n=1;break}throw new Error("Zapier webhook URL not configured for ".concat(r));case 1:return i={timestamp:(new Date).toISOString(),id:n.id,feedback:n.feedback,type:n.type||"bug",status:n.status||"new",user_name:n.userName||"Anonymous",user_email:n.userEmail||"",page_url:n.url||"",viewport:n.viewport?"".concat(n.viewport.width,"x").concat(n.viewport.height):"",has_screenshot:!!n.screenshot,has_video:!!n.video,element_selector:(null===(o=n.elementInfo)||void 0===o?void 0:o.selector)||"",component_name:((null===(a=n.elementInfo)||void 0===a?void 0:a.componentStack)||[])[0]||""},e.n=2,fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});case 2:if((s=e.v).ok){e.n=3;break}throw new Error("Zapier webhook failed: ".concat(s.status));case 3:return u={success:!0,type:"zapier"},this.onSuccess(r,u),e.a(2,u)}},e,this)})),function(e,n,t){return r.apply(this,arguments)})},{key:"updateJiraStatus",value:(t=i(f().m(function e(n,t){var r,o,a,i;return f().w(function(e){for(;;)switch(e.n){case 0:if(null!==(r=this.jiraConfig)&&void 0!==r&&r.enabled&&null!==(o=this.jiraConfig)&&void 0!==o&&o.syncStatus){e.n=1;break}return e.a(2,null);case 1:return a=this.jiraConfig.endpoint||"/api/feedback/jira",e.n=2,fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"updateStatus",issueKey:n,status:t})});case 2:if((i=e.v).ok){e.n=3;break}throw new Error("Failed to update Jira status");case 3:return e.a(2,i.json())}},e,this)})),function(e,n){return t.apply(this,arguments)})},{key:"updateSheetsStatus",value:(n=i(f().m(function e(n,t){var r,o,a,i;return f().w(function(e){for(;;)switch(e.n){case 0:if(null!==(r=this.sheetsConfig)&&void 0!==r&&r.enabled){e.n=1;break}return e.a(2,null);case 1:if((this.sheetsConfig.type||E.SHEETS.SERVER)!==E.SHEETS.APPS_SCRIPT){e.n=3;break}return e.n=2,fetch(this.sheetsConfig.deploymentUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"updateStatus",feedbackId:n,status:t})});case 2:return o=e.v,e.a(2,o.json());case 3:return a=this.sheetsConfig.endpoint||"/api/feedback/sheets",e.n=4,fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"updateStatus",feedbackId:n,status:t})});case 4:return i=e.v,e.a(2,i.json())}},e,this)})),function(e,t){return n.apply(this,arguments)})},{key:"getJiraStatus",value:(e=i(f().m(function e(n){var t,r,o;return f().w(function(e){for(;;)switch(e.n){case 0:if(null!==(t=this.jiraConfig)&&void 0!==t&&t.enabled){e.n=1;break}return e.a(2,null);case 1:return r=this.jiraConfig.endpoint||"/api/feedback/jira",e.n=2,fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"getStatus",issueKey:n})});case 2:return o=e.v,e.a(2,o.json())}},e,this)})),function(n){return e.apply(this,arguments)})}]);var e,n,t,r,o,a,u,c,l,p,h,y}();function P(){var o,a,s,c,d,p,y=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},m=e(null),v=h(n({jira:{loading:!1,error:null,result:null},sheets:{loading:!1,error:null,result:null}}),2),b=v[0],g=v[1];t(function(){m.current=new I(l(l({},y),{},{onSuccess:function(e,n){g(function(t){return l(l({},t),{},u({},e,{loading:!1,error:null,result:n}))})},onError:function(e,n){g(function(t){return l(l({},t),{},u({},e,{loading:!1,error:n.message,result:null}))})}}))},[null===(o=y.jira)||void 0===o?void 0:o.enabled,null===(a=y.sheets)||void 0===a?void 0:a.enabled]);var S=r(function(){var e=i(f().m(function e(n){var t,r;return f().w(function(e){for(;;)switch(e.p=e.n){case 0:if(m.current){e.n=1;break}return e.a(2,null);case 1:return g(function(e){var n,t;return{jira:null!==(n=y.jira)&&void 0!==n&&n.enabled?l(l({},e.jira),{},{loading:!0}):e.jira,sheets:null!==(t=y.sheets)&&void 0!==t&&t.enabled?l(l({},e.sheets),{},{loading:!0}):e.sheets}}),e.p=2,e.n=3,m.current.sendFeedback(n);case 3:return t=e.v,g({jira:t.jira?{loading:!1,error:t.jira.error||null,result:t.jira}:{loading:!1,error:null,result:null},sheets:t.sheets?{loading:!1,error:t.sheets.error||null,result:t.sheets}:{loading:!1,error:null,result:null}}),e.a(2,t);case 4:throw e.p=4,r=e.v,g(function(e){return{jira:l(l({},e.jira),{},{loading:!1,error:r.message}),sheets:l(l({},e.sheets),{},{loading:!1,error:r.message})}}),r;case 5:return e.a(2)}},e,null,[[2,4]])}));return function(n){return e.apply(this,arguments)}}(),[null===(s=y.jira)||void 0===s?void 0:s.enabled,null===(c=y.sheets)||void 0===c?void 0:c.enabled]),w=r(function(){var e=i(f().m(function e(n,t){var r,o,a;return f().w(function(e){for(;;)switch(e.n){case 0:if(m.current){e.n=1;break}return e.a(2,null);case 1:if(a={},!n.jiraKey||null===(r=y.jira)||void 0===r||!r.syncStatus){e.n=3;break}return e.n=2,m.current.updateJiraStatus(n.jiraKey,t);case 2:a.jira=e.v;case 3:if(null===(o=y.sheets)||void 0===o||!o.enabled){e.n=5;break}return e.n=4,m.current.updateSheetsStatus(n.id,t);case 4:a.sheets=e.v;case 5:return e.a(2,a)}},e)}));return function(n,t){return e.apply(this,arguments)}}(),[null===(d=y.jira)||void 0===d?void 0:d.syncStatus,null===(p=y.sheets)||void 0===p?void 0:p.enabled]);return{status:b,sendFeedback:S,updateStatus:w,client:m.current}}export{w as DEFAULT_JIRA_FIELDS,k as DEFAULT_JIRA_STATUS_MAPPING,g as DEFAULT_SHEET_COLUMNS,E as INTEGRATION_TYPES,I as IntegrationClient,T as feedbackToSheetRow,A as getAppsScriptTemplate,O as getSheetHeaders,P as useIntegrations};
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/integrations/config.js","../../src/integrations/sheets.js","../../src/integrations/index.js"],"sourcesContent":["/**\n * Integration Configuration & Default Mappings\n * Users can customize these by passing their own config\n */\n\n// ============================================\n// ATLASSIAN DOCUMENT FORMAT (ADF) HELPER\n// ============================================\n\n/**\n * Convert plain text to Atlassian Document Format\n * Jira Cloud requires descriptions in ADF format\n */\nexport function textToADF(text) {\n const lines = text.split('\\n');\n const content = [];\n let currentParagraph = [];\n\n const flushParagraph = () => {\n if (currentParagraph.length > 0) {\n content.push({\n type: 'paragraph',\n content: currentParagraph\n });\n currentParagraph = [];\n }\n };\n\n lines.forEach((line, index) => {\n // Check if it's a section header (ALL CAPS)\n if (line.match(/^[A-Z][A-Z\\s]+$/) && line.trim().length > 0) {\n flushParagraph();\n content.push({\n type: 'heading',\n attrs: { level: 3 },\n content: [{ type: 'text', text: line }]\n });\n } else if (line === '---') {\n // Horizontal rule\n flushParagraph();\n content.push({ type: 'rule' });\n } else if (line.trim() === '') {\n // Empty line - flush paragraph\n flushParagraph();\n } else {\n // Regular line\n if (currentParagraph.length > 0) {\n currentParagraph.push({ type: 'hardBreak' });\n }\n currentParagraph.push({ type: 'text', text: line });\n }\n });\n\n flushParagraph();\n\n return {\n type: 'doc',\n version: 1,\n content: content.length > 0 ? content : [{ type: 'paragraph', content: [{ type: 'text', text: ' ' }] }]\n };\n}\n\n// ============================================\n// GOOGLE SHEETS COLUMN MAPPING\n// ============================================\n\nexport const DEFAULT_SHEET_COLUMNS = {\n timestamp: {\n key: 'timestamp',\n header: 'Timestamp',\n field: 'timestamp',\n transform: (value) => value || new Date().toISOString()\n },\n id: {\n key: 'id',\n header: 'Feedback ID',\n field: 'id'\n },\n feedback: {\n key: 'feedback',\n header: 'Feedback',\n field: 'feedback'\n },\n type: {\n key: 'type',\n header: 'Type',\n field: 'type',\n transform: (value) => value || 'bug'\n },\n status: {\n key: 'status',\n header: 'Status',\n field: 'status',\n transform: (value) => value || 'new'\n },\n userName: {\n key: 'userName',\n header: 'User Name',\n field: 'userName',\n transform: (value) => value || 'Anonymous'\n },\n userEmail: {\n key: 'userEmail',\n header: 'User Email',\n field: 'userEmail',\n transform: (value) => value || ''\n },\n url: {\n key: 'url',\n header: 'Page URL',\n field: 'url'\n },\n viewport: {\n key: 'viewport',\n header: 'Viewport',\n field: 'viewport',\n transform: (value) => value ? `${value.width}x${value.height}` : ''\n },\n userAgent: {\n key: 'userAgent',\n header: 'Browser',\n field: 'userAgent',\n transform: (value) => {\n if (!value) return '';\n // Simplify user agent\n if (value.includes('Chrome')) return 'Chrome';\n if (value.includes('Firefox')) return 'Firefox';\n if (value.includes('Safari')) return 'Safari';\n if (value.includes('Edge')) return 'Edge';\n return value.substring(0, 50);\n }\n },\n screenshot: {\n key: 'screenshot',\n header: 'Screenshot',\n field: 'screenshot',\n transform: (value) => value ? 'Yes' : 'No' // Don't store base64 in sheets\n },\n video: {\n key: 'video',\n header: 'Video',\n field: 'video',\n transform: (value) => value ? 'Yes' : 'No'\n },\n elementSelector: {\n key: 'elementSelector',\n header: 'Element',\n field: 'elementInfo',\n transform: (value) => value?.selector || ''\n },\n componentName: {\n key: 'componentName',\n header: 'Component',\n field: 'elementInfo',\n transform: (value) => value?.componentStack?.[0] || ''\n },\n sourceFile: {\n key: 'sourceFile',\n header: 'Source File',\n field: 'elementInfo',\n transform: (value) => value?.sourceFile || ''\n },\n jiraKey: {\n key: 'jiraKey',\n header: 'Jira Issue',\n field: 'jiraKey',\n transform: (value) => value || ''\n }\n};\n\n// Default columns to include (order matters)\nexport const DEFAULT_SHEET_COLUMN_ORDER = [\n 'timestamp',\n 'id',\n 'feedback',\n 'type',\n 'status',\n 'userName',\n 'userEmail',\n 'url',\n 'viewport',\n 'screenshot',\n 'video',\n 'jiraKey'\n];\n\n// ============================================\n// JIRA FIELD MAPPING\n// ============================================\n\nexport const DEFAULT_JIRA_FIELDS = {\n summary: {\n key: 'summary',\n source: 'feedback',\n maxLength: 255,\n prefix: '[Feedback] ',\n transform: (data) => {\n const prefix = '[Feedback] ';\n const text = data.feedback || 'User Feedback';\n const maxLen = 255 - prefix.length;\n return prefix + (text.length > maxLen ? text.substring(0, maxLen - 3) + '...' : text);\n }\n },\n description: {\n key: 'description',\n // Build description directly - no wiki markup, clean plain text for ADF\n transform: (data) => {\n const lines = [];\n\n // Feedback Details\n lines.push('FEEDBACK DETAILS');\n lines.push(`Feedback: ${data.feedback || 'No feedback provided'}`);\n lines.push(`Type: ${data.type || 'bug'}`);\n lines.push(`Status: ${data.status || 'new'}`);\n lines.push('');\n\n // User Information\n lines.push('USER INFORMATION');\n lines.push(`Name: ${data.userName || 'Anonymous'}`);\n lines.push(`Email: ${data.userEmail || 'Not provided'}`);\n lines.push('');\n\n // Technical Details\n lines.push('TECHNICAL DETAILS');\n lines.push(`Page URL: ${data.url || 'N/A'}`);\n if (data.viewport) {\n lines.push(`Viewport: ${data.viewport.width}x${data.viewport.height}`);\n }\n if (data.userAgent) {\n // Simplify user agent\n let browser = data.userAgent;\n if (browser.includes('Chrome')) browser = 'Chrome';\n else if (browser.includes('Firefox')) browser = 'Firefox';\n else if (browser.includes('Safari')) browser = 'Safari';\n else if (browser.includes('Edge')) browser = 'Edge';\n lines.push(`Browser: ${browser}`);\n }\n\n // Element info\n if (data.elementInfo) {\n if (data.elementInfo.selector) {\n lines.push(`Element: ${data.elementInfo.selector}`);\n }\n if (data.elementInfo.componentStack?.length) {\n lines.push(`Component: ${data.elementInfo.componentStack.join(' > ')}`);\n }\n if (data.elementInfo.sourceFile) {\n lines.push(`Source: ${data.elementInfo.sourceFile}:${data.elementInfo.lineNumber || ''}`);\n }\n }\n lines.push('');\n\n // Attachments\n const attachments = [];\n if (data.screenshot) attachments.push('Screenshot');\n if (data.video) attachments.push('Screen Recording');\n if (attachments.length > 0) {\n lines.push('ATTACHMENTS');\n lines.push(attachments.join(', ') + ' attached');\n lines.push('');\n }\n\n lines.push('---');\n lines.push('Submitted via React Visual Feedback');\n\n return lines.join('\\n');\n }\n },\n issuetype: {\n key: 'issuetype',\n // Default to 'Task' which exists in most Jira projects\n // Can be overridden via JIRA_ISSUE_TYPE env var or config\n value: 'Task',\n // Map feedback types to Jira issue types (all default to Task for compatibility)\n typeMapping: {\n bug: 'Task',\n feature: 'Task',\n improvement: 'Task',\n question: 'Task',\n other: 'Task'\n },\n transform: (data, config) => {\n // Priority: env var > config value > type mapping > default\n const envIssueType = typeof process !== 'undefined' ? process.env?.JIRA_ISSUE_TYPE : null;\n if (envIssueType) return envIssueType;\n if (config?.value && config.value !== 'Task') return config.value;\n const mapping = config?.typeMapping || DEFAULT_JIRA_FIELDS.issuetype.typeMapping;\n return mapping[data.type] || config?.value || 'Task';\n }\n },\n labels: {\n key: 'labels',\n value: ['user-feedback'],\n transform: (data, config) => {\n const labels = [...(config?.value || ['user-feedback'])];\n if (data.type) labels.push(`type-${data.type}`);\n return labels;\n }\n },\n priority: {\n key: 'priority',\n // Map to Jira priority IDs (user can customize)\n priorityMapping: {\n bug: 'High',\n feature: 'Medium',\n improvement: 'Medium',\n question: 'Low',\n other: 'Low'\n },\n transform: (data, config) => {\n const mapping = config?.priorityMapping || DEFAULT_JIRA_FIELDS.priority.priorityMapping;\n return mapping[data.type] || 'Medium';\n }\n }\n};\n\n// ============================================\n// JIRA STATUS MAPPING (Bidirectional sync)\n// ============================================\n\nexport const DEFAULT_JIRA_STATUS_MAPPING = {\n // Our status -> Jira status\n toJira: {\n new: 'To Do',\n open: 'To Do',\n inProgress: 'In Progress',\n underReview: 'In Review',\n onHold: 'On Hold',\n resolved: 'Done',\n closed: 'Done',\n wontFix: 'Won\\'t Do'\n },\n // Jira status -> Our status\n fromJira: {\n 'To Do': 'open',\n 'Open': 'open',\n 'In Progress': 'inProgress',\n 'In Review': 'underReview',\n 'On Hold': 'onHold',\n 'Done': 'resolved',\n 'Closed': 'closed',\n 'Won\\'t Do': 'wontFix',\n 'Resolved': 'resolved'\n }\n};\n\n// ============================================\n// INTEGRATION TYPES\n// ============================================\n\nexport const INTEGRATION_TYPES = {\n JIRA: {\n SERVER: 'server', // Our server handler\n AUTOMATION: 'jira-automation', // Jira's built-in webhooks\n ZAPIER: 'zapier' // Zapier webhook\n },\n SHEETS: {\n SERVER: 'server', // Our server handler (Service Account)\n OAUTH: 'oauth', // OAuth with refresh\n APPS_SCRIPT: 'google-apps-script', // Google Apps Script\n ZAPIER: 'zapier' // Zapier webhook\n }\n};\n\n// ============================================\n// HELPER FUNCTIONS\n// ============================================\n\n/**\n * Merge user config with defaults\n */\nexport function mergeSheetColumns(userColumns = {}, columnOrder = null) {\n const merged = { ...DEFAULT_SHEET_COLUMNS };\n\n // Apply user overrides\n Object.entries(userColumns).forEach(([key, value]) => {\n if (value === null || value === false) {\n // Remove column\n delete merged[key];\n } else if (typeof value === 'object') {\n // Merge with default\n merged[key] = { ...merged[key], ...value };\n }\n });\n\n // Determine column order\n const order = columnOrder || Object.keys(merged).filter(k =>\n DEFAULT_SHEET_COLUMN_ORDER.includes(k) || userColumns[k]\n );\n\n return { columns: merged, order };\n}\n\n/**\n * Merge user Jira config with defaults\n */\nexport function mergeJiraFields(userFields = {}) {\n const merged = { ...DEFAULT_JIRA_FIELDS };\n\n Object.entries(userFields).forEach(([key, value]) => {\n if (value === null || value === false) {\n delete merged[key];\n } else if (typeof value === 'object') {\n merged[key] = { ...merged[key], ...value };\n }\n });\n\n return merged;\n}\n\n/**\n * Transform feedback data to sheet row\n */\nexport function feedbackToSheetRow(feedbackData, config = {}) {\n const { columns, order } = mergeSheetColumns(config.columns, config.columnOrder);\n\n const row = order.map(key => {\n const col = columns[key];\n if (!col) return '';\n\n const rawValue = feedbackData[col.field];\n if (col.transform) {\n return col.transform(rawValue) || '';\n }\n return rawValue || '';\n });\n\n return row;\n}\n\n/**\n * Get sheet headers\n */\nexport function getSheetHeaders(config = {}) {\n const { columns, order } = mergeSheetColumns(config.columns, config.columnOrder);\n return order.map(key => columns[key]?.header || key);\n}\n\n/**\n * Transform feedback data to Jira issue\n */\nexport function feedbackToJiraIssue(feedbackData, config = {}) {\n const fields = mergeJiraFields(config.fields);\n\n // Get plain text description and convert to ADF\n const plainDescription = fields.description.transform(feedbackData, fields.description);\n const adfDescription = textToADF(plainDescription);\n\n const issue = {\n fields: {\n project: { key: config.projectKey },\n summary: fields.summary.transform(feedbackData, fields.summary),\n description: adfDescription,\n issuetype: { name: fields.issuetype.transform(feedbackData, fields.issuetype) }\n }\n };\n\n // Add labels if configured\n if (fields.labels) {\n issue.fields.labels = fields.labels.transform(feedbackData, fields.labels);\n }\n\n // Add priority if configured and user wants it\n if (config.includePriority && fields.priority) {\n issue.fields.priority = { name: fields.priority.transform(feedbackData, fields.priority) };\n }\n\n // Add custom fields\n if (config.customFields) {\n Object.entries(config.customFields).forEach(([fieldId, fieldConfig]) => {\n if (typeof fieldConfig === 'string') {\n issue.fields[fieldId] = feedbackData[fieldConfig];\n } else if (fieldConfig.transform) {\n issue.fields[fieldId] = fieldConfig.transform(feedbackData);\n } else if (fieldConfig.value) {\n issue.fields[fieldId] = fieldConfig.value;\n }\n });\n }\n\n return issue;\n}\n\n/**\n * Map Jira status to our status\n */\nexport function mapJiraStatusToLocal(jiraStatus, customMapping = {}) {\n const mapping = { ...DEFAULT_JIRA_STATUS_MAPPING.fromJira, ...customMapping };\n return mapping[jiraStatus] || 'open';\n}\n\n/**\n * Map our status to Jira status\n */\nexport function mapLocalStatusToJira(localStatus, customMapping = {}) {\n const mapping = { ...DEFAULT_JIRA_STATUS_MAPPING.toJira, ...customMapping };\n return mapping[localStatus] || 'To Do';\n}\n","/**\n * Google Sheets Integration Server Handler\n *\n * Supports:\n * - Service Account authentication (recommended for servers)\n * - OAuth 2.0 with automatic token refresh\n * - Google Apps Script (no server needed)\n *\n * Usage (Next.js App Router):\n * export { POST } from 'react-visual-feedback/server/sheets';\n *\n * Usage (Express):\n * app.post('/api/sheets', sheetsHandler({ spreadsheetId: '...' }));\n */\n\nimport {\n feedbackToSheetRow,\n getSheetHeaders,\n mergeSheetColumns,\n DEFAULT_SHEET_COLUMN_ORDER\n} from './config.js';\n\n// ============================================\n// GOOGLE SHEETS CLIENT (Service Account)\n// ============================================\n\nclass SheetsClient {\n constructor(config) {\n this.spreadsheetId = config.spreadsheetId || process.env.GOOGLE_SPREADSHEET_ID;\n this.sheetName = config.sheetName || 'Feedback';\n\n // Service Account credentials\n const credentials = config.credentials || process.env.GOOGLE_SERVICE_ACCOUNT;\n\n if (!credentials) {\n throw new Error(\n 'Google credentials missing. Set GOOGLE_SERVICE_ACCOUNT environment variable.'\n );\n }\n\n this.credentials = typeof credentials === 'string'\n ? JSON.parse(credentials)\n : credentials;\n\n if (!this.spreadsheetId) {\n throw new Error(\n 'Spreadsheet ID missing. Set GOOGLE_SPREADSHEET_ID environment variable.'\n );\n }\n\n this.accessToken = null;\n this.tokenExpiry = null;\n }\n\n /**\n * Get access token using Service Account JWT\n */\n async getAccessToken() {\n // Return cached token if still valid\n if (this.accessToken && this.tokenExpiry && Date.now() < this.tokenExpiry) {\n return this.accessToken;\n }\n\n const { client_email, private_key } = this.credentials;\n\n // Create JWT\n const header = {\n alg: 'RS256',\n typ: 'JWT'\n };\n\n const now = Math.floor(Date.now() / 1000);\n const payload = {\n iss: client_email,\n scope: 'https://www.googleapis.com/auth/spreadsheets',\n aud: 'https://oauth2.googleapis.com/token',\n exp: now + 3600,\n iat: now\n };\n\n const jwt = await this.createJWT(header, payload, private_key);\n\n // Exchange JWT for access token\n const response = await fetch('https://oauth2.googleapis.com/token', {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',\n assertion: jwt\n })\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to get access token: ${error}`);\n }\n\n const data = await response.json();\n this.accessToken = data.access_token;\n this.tokenExpiry = Date.now() + (data.expires_in - 60) * 1000; // Refresh 1 min early\n\n return this.accessToken;\n }\n\n /**\n * Create JWT for Service Account auth\n */\n async createJWT(header, payload, privateKey) {\n const encoder = new TextEncoder();\n\n const headerB64 = this.base64UrlEncode(JSON.stringify(header));\n const payloadB64 = this.base64UrlEncode(JSON.stringify(payload));\n const signatureInput = `${headerB64}.${payloadB64}`;\n\n // Import private key\n const pemHeader = '-----BEGIN PRIVATE KEY-----';\n const pemFooter = '-----END PRIVATE KEY-----';\n const pemContents = privateKey\n .replace(pemHeader, '')\n .replace(pemFooter, '')\n .replace(/\\s/g, '');\n\n const binaryKey = Buffer.from(pemContents, 'base64');\n\n // Use Node.js crypto for signing\n const crypto = await import('crypto');\n const sign = crypto.createSign('RSA-SHA256');\n sign.update(signatureInput);\n sign.end();\n\n const signature = sign.sign({\n key: privateKey,\n padding: crypto.constants.RSA_PKCS1_PADDING\n });\n\n const signatureB64 = this.base64UrlEncode(signature);\n\n return `${signatureInput}.${signatureB64}`;\n }\n\n base64UrlEncode(data) {\n const str = typeof data === 'string' ? data : Buffer.from(data).toString('base64');\n return Buffer.from(data)\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n }\n\n /**\n * Make authenticated request to Sheets API\n */\n async request(endpoint, options = {}) {\n const token = await this.getAccessToken();\n const baseUrl = 'https://sheets.googleapis.com/v4/spreadsheets';\n\n const response = await fetch(`${baseUrl}/${this.spreadsheetId}${endpoint}`, {\n ...options,\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n ...options.headers\n }\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Sheets API error (${response.status}): ${error}`);\n }\n\n const text = await response.text();\n return text ? JSON.parse(text) : null;\n }\n\n /**\n * Append row to sheet\n */\n async appendRow(values, sheetName = null) {\n const range = `${sheetName || this.sheetName}!A:Z`;\n\n return this.request(`/values/${encodeURIComponent(range)}:append`, {\n method: 'POST',\n body: JSON.stringify({\n values: [values],\n majorDimension: 'ROWS'\n }) + '?valueInputOption=RAW&insertDataOption=INSERT_ROWS'\n });\n }\n\n /**\n * Get sheet values\n */\n async getValues(range) {\n return this.request(`/values/${encodeURIComponent(range)}`);\n }\n\n /**\n * Update specific cell/range\n */\n async updateValues(range, values) {\n return this.request(`/values/${encodeURIComponent(range)}?valueInputOption=RAW`, {\n method: 'PUT',\n body: JSON.stringify({\n values,\n majorDimension: 'ROWS'\n })\n });\n }\n\n /**\n * Check if headers exist, create if not\n */\n async ensureHeaders(headers) {\n try {\n const existing = await this.getValues(`${this.sheetName}!1:1`);\n\n if (!existing.values || existing.values.length === 0) {\n // No headers, add them\n await this.updateValues(`${this.sheetName}!A1`, [headers]);\n return { created: true };\n }\n\n return { created: false, existing: existing.values[0] };\n } catch (error) {\n // Sheet might not exist, try to create headers anyway\n try {\n await this.updateValues(`${this.sheetName}!A1`, [headers]);\n return { created: true };\n } catch (e) {\n throw new Error(`Failed to set up headers: ${e.message}`);\n }\n }\n }\n\n /**\n * Find row by feedback ID\n */\n async findRowByFeedbackId(feedbackId, idColumn = 'B') {\n const values = await this.getValues(`${this.sheetName}!${idColumn}:${idColumn}`);\n\n if (!values.values) return null;\n\n const rowIndex = values.values.findIndex(row => row[0] === feedbackId);\n return rowIndex >= 0 ? rowIndex + 1 : null; // 1-indexed\n }\n\n /**\n * Update feedback status in sheet\n */\n async updateStatus(feedbackId, newStatus, statusColumn = 'E') {\n const rowNumber = await this.findRowByFeedbackId(feedbackId);\n\n if (!rowNumber) {\n throw new Error(`Feedback ${feedbackId} not found in sheet`);\n }\n\n await this.updateValues(\n `${this.sheetName}!${statusColumn}${rowNumber}`,\n [[newStatus]]\n );\n\n return { success: true, row: rowNumber };\n }\n}\n\n// ============================================\n// OAUTH CLIENT (User Authentication)\n// ============================================\n\nclass SheetsOAuthClient extends SheetsClient {\n constructor(config) {\n super({ spreadsheetId: config.spreadsheetId, sheetName: config.sheetName, credentials: { client_email: '', private_key: '' } });\n\n this.clientId = config.clientId || process.env.GOOGLE_CLIENT_ID;\n this.clientSecret = config.clientSecret || process.env.GOOGLE_CLIENT_SECRET;\n this.redirectUri = config.redirectUri || process.env.GOOGLE_REDIRECT_URI;\n\n // Token storage (user must provide storage mechanism)\n this.getStoredTokens = config.getStoredTokens;\n this.saveTokens = config.saveTokens;\n\n if (!this.clientId || !this.clientSecret) {\n throw new Error('OAuth configuration missing. Required: GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET');\n }\n }\n\n /**\n * Get OAuth authorization URL\n */\n getAuthUrl(state = '') {\n const params = new URLSearchParams({\n client_id: this.clientId,\n redirect_uri: this.redirectUri,\n response_type: 'code',\n scope: 'https://www.googleapis.com/auth/spreadsheets',\n access_type: 'offline',\n prompt: 'consent',\n state\n });\n\n return `https://accounts.google.com/o/oauth2/v2/auth?${params}`;\n }\n\n /**\n * Exchange authorization code for tokens\n */\n async exchangeCode(code) {\n const response = await fetch('https://oauth2.googleapis.com/token', {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n client_id: this.clientId,\n client_secret: this.clientSecret,\n code,\n grant_type: 'authorization_code',\n redirect_uri: this.redirectUri\n })\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to exchange code: ${error}`);\n }\n\n const tokens = await response.json();\n\n // Save tokens\n if (this.saveTokens) {\n await this.saveTokens({\n access_token: tokens.access_token,\n refresh_token: tokens.refresh_token,\n expiry: Date.now() + tokens.expires_in * 1000\n });\n }\n\n return tokens;\n }\n\n /**\n * Refresh access token using refresh token\n */\n async refreshAccessToken(refreshToken) {\n const response = await fetch('https://oauth2.googleapis.com/token', {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n client_id: this.clientId,\n client_secret: this.clientSecret,\n refresh_token: refreshToken,\n grant_type: 'refresh_token'\n })\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to refresh token: ${error}`);\n }\n\n const data = await response.json();\n\n // Save new access token\n if (this.saveTokens) {\n const stored = await this.getStoredTokens();\n await this.saveTokens({\n access_token: data.access_token,\n refresh_token: stored.refresh_token, // Keep existing refresh token\n expiry: Date.now() + data.expires_in * 1000\n });\n }\n\n return data.access_token;\n }\n\n /**\n * Override getAccessToken to use OAuth\n */\n async getAccessToken() {\n if (!this.getStoredTokens) {\n throw new Error('Token storage not configured. Provide getStoredTokens and saveTokens functions.');\n }\n\n const stored = await this.getStoredTokens();\n\n if (!stored || !stored.refresh_token) {\n throw new Error('Not authenticated. User needs to complete OAuth flow.');\n }\n\n // Check if access token is still valid\n if (stored.access_token && stored.expiry && Date.now() < stored.expiry - 60000) {\n return stored.access_token;\n }\n\n // Refresh the token\n return this.refreshAccessToken(stored.refresh_token);\n }\n}\n\n// ============================================\n// REQUEST HANDLERS\n// ============================================\n\n/**\n * Create Sheets handler with configuration\n */\nexport function createSheetsHandler(config = {}) {\n const handler = async (req, res) => {\n try {\n const body = typeof req.body === 'string' ? JSON.parse(req.body) : req.body;\n const { action = 'append', feedbackData, feedbackId, status, row } = body;\n\n // Choose client type based on config\n const ClientClass = config.oauth ? SheetsOAuthClient : SheetsClient;\n const client = new ClientClass(config);\n\n let result;\n\n switch (action) {\n case 'append':\n result = await handleAppend(client, feedbackData, config);\n break;\n\n case 'updateStatus':\n result = await handleUpdateStatus(client, feedbackId, status, config);\n break;\n\n case 'updateRow':\n result = await handleUpdateRow(client, row, feedbackData, config);\n break;\n\n case 'getHeaders':\n result = { headers: getSheetHeaders(config) };\n break;\n\n case 'ensureHeaders':\n const headers = getSheetHeaders(config);\n result = await client.ensureHeaders(headers);\n break;\n\n // OAuth specific actions\n case 'getAuthUrl':\n if (!(client instanceof SheetsOAuthClient)) {\n throw new Error('OAuth not configured');\n }\n result = { url: client.getAuthUrl(body.state) };\n break;\n\n case 'exchangeCode':\n if (!(client instanceof SheetsOAuthClient)) {\n throw new Error('OAuth not configured');\n }\n result = await client.exchangeCode(body.code);\n break;\n\n default:\n throw new Error(`Unknown action: ${action}`);\n }\n\n // Send response\n if (res?.json) {\n res.status(200).json(result);\n } else {\n return new Response(JSON.stringify(result), {\n status: 200,\n headers: { 'Content-Type': 'application/json' }\n });\n }\n } catch (error) {\n const errorResponse = {\n success: false,\n error: error.message\n };\n\n if (res?.json) {\n res.status(500).json(errorResponse);\n } else {\n return new Response(JSON.stringify(errorResponse), {\n status: 500,\n headers: { 'Content-Type': 'application/json' }\n });\n }\n }\n };\n\n return handler;\n}\n\n/**\n * Handle append row\n */\nasync function handleAppend(client, feedbackData, config) {\n // Ensure headers exist\n const headers = getSheetHeaders(config);\n await client.ensureHeaders(headers);\n\n // Transform feedback to row\n const row = feedbackToSheetRow(feedbackData, config);\n\n // Append row\n const result = await client.appendRow(row);\n\n return {\n success: true,\n updatedRange: result?.updates?.updatedRange,\n rowNumber: result?.updates?.updatedRange?.match(/:(\\d+)$/)?.[1]\n };\n}\n\n/**\n * Handle status update\n */\nasync function handleUpdateStatus(client, feedbackId, status, config) {\n // Find status column\n const { columns, order } = mergeSheetColumns(config.columns, config.columnOrder);\n const statusIndex = order.indexOf('status');\n const statusColumn = String.fromCharCode(65 + statusIndex); // A, B, C...\n\n const result = await client.updateStatus(feedbackId, status, statusColumn);\n\n return result;\n}\n\n/**\n * Handle row update\n */\nasync function handleUpdateRow(client, rowNumber, feedbackData, config) {\n const row = feedbackToSheetRow(feedbackData, config);\n const range = `${config.sheetName || 'Feedback'}!A${rowNumber}`;\n\n await client.updateValues(range, [row]);\n\n return { success: true, row: rowNumber };\n}\n\n// ============================================\n// FRAMEWORK-SPECIFIC EXPORTS\n// ============================================\n\n/**\n * Next.js App Router handler\n * Returns a function that can be directly exported as POST\n */\nexport function createNextAppHandler(config = {}) {\n const handler = createSheetsHandler(config);\n\n return async (request) => {\n const body = await request.json();\n return handler({ body }, null);\n };\n}\n\n/**\n * Next.js Pages Router handler\n */\nexport function createNextPagesHandler(config = {}) {\n return createSheetsHandler(config);\n}\n\n/**\n * Express middleware\n */\nexport function createExpressMiddleware(config = {}) {\n const handler = createSheetsHandler(config);\n\n return async (req, res, next) => {\n try {\n await handler(req, res);\n } catch (error) {\n next(error);\n }\n };\n}\n\n// ============================================\n// GOOGLE APPS SCRIPT TEMPLATE\n// ============================================\n\n/**\n * Returns the Google Apps Script code that users paste into their sheet\n */\nexport function getAppsScriptTemplate(config = {}) {\n const headers = getSheetHeaders(config);\n\n return `\n/**\n * React Visual Feedback - Google Apps Script Handler\n *\n * Setup:\n * 1. Open your Google Sheet\n * 2. Extensions > Apps Script\n * 3. Paste this code\n * 4. Deploy > New deployment > Web app\n * 5. Execute as: Me, Who has access: Anyone\n * 6. Copy the URL and use in your React app\n */\n\n// Sheet configuration\nconst SHEET_NAME = '${config.sheetName || 'Feedback'}';\nconst HEADERS = ${JSON.stringify(headers)};\n\n/**\n * Handle POST requests\n */\nfunction doPost(e) {\n try {\n const data = JSON.parse(e.postData.contents);\n const action = data.action || 'append';\n\n let result;\n\n switch (action) {\n case 'append':\n result = appendFeedback(data.feedbackData);\n break;\n case 'updateStatus':\n result = updateStatus(data.feedbackId, data.status);\n break;\n case 'getRows':\n result = getRows(data.limit || 100);\n break;\n default:\n throw new Error('Unknown action: ' + action);\n }\n\n return ContentService\n .createTextOutput(JSON.stringify(result))\n .setMimeType(ContentService.MimeType.JSON);\n\n } catch (error) {\n return ContentService\n .createTextOutput(JSON.stringify({ success: false, error: error.message }))\n .setMimeType(ContentService.MimeType.JSON);\n }\n}\n\n/**\n * Handle GET requests (for testing)\n */\nfunction doGet(e) {\n return ContentService\n .createTextOutput(JSON.stringify({ status: 'ok', message: 'Feedback API ready' }))\n .setMimeType(ContentService.MimeType.JSON);\n}\n\n/**\n * Append feedback to sheet\n */\nfunction appendFeedback(feedbackData) {\n const sheet = getOrCreateSheet();\n\n const row = [\n new Date().toISOString(), // Timestamp\n feedbackData.id || '', // ID\n feedbackData.feedback || '', // Feedback\n feedbackData.type || 'bug', // Type\n feedbackData.status || 'new', // Status\n feedbackData.userName || 'Anonymous', // User Name\n feedbackData.userEmail || '', // User Email\n feedbackData.url || '', // Page URL\n feedbackData.viewport ? feedbackData.viewport.width + 'x' + feedbackData.viewport.height : '', // Viewport\n feedbackData.screenshot ? 'Yes' : 'No', // Screenshot\n feedbackData.video ? 'Yes' : 'No', // Video\n feedbackData.jiraKey || '' // Jira Key\n ];\n\n sheet.appendRow(row);\n\n return {\n success: true,\n row: sheet.getLastRow()\n };\n}\n\n/**\n * Update feedback status\n */\nfunction updateStatus(feedbackId, newStatus) {\n const sheet = getOrCreateSheet();\n const data = sheet.getDataRange().getValues();\n\n // Find row with matching ID (column B, index 1)\n for (let i = 1; i < data.length; i++) {\n if (data[i][1] === feedbackId) {\n // Update status (column E, index 4)\n sheet.getRange(i + 1, 5).setValue(newStatus);\n return { success: true, row: i + 1 };\n }\n }\n\n return { success: false, error: 'Feedback not found' };\n}\n\n/**\n * Get rows from sheet\n */\nfunction getRows(limit) {\n const sheet = getOrCreateSheet();\n const data = sheet.getDataRange().getValues();\n\n const rows = data.slice(1, limit + 1).map((row, index) => ({\n rowNumber: index + 2,\n timestamp: row[0],\n id: row[1],\n feedback: row[2],\n type: row[3],\n status: row[4],\n userName: row[5],\n userEmail: row[6],\n url: row[7],\n viewport: row[8],\n hasScreenshot: row[9] === 'Yes',\n hasVideo: row[10] === 'Yes',\n jiraKey: row[11]\n }));\n\n return { success: true, rows };\n}\n\n/**\n * Get or create the feedback sheet\n */\nfunction getOrCreateSheet() {\n const ss = SpreadsheetApp.getActiveSpreadsheet();\n let sheet = ss.getSheetByName(SHEET_NAME);\n\n if (!sheet) {\n sheet = ss.insertSheet(SHEET_NAME);\n sheet.appendRow(HEADERS);\n\n // Format headers\n const headerRange = sheet.getRange(1, 1, 1, HEADERS.length);\n headerRange.setFontWeight('bold');\n headerRange.setBackground('#4285f4');\n headerRange.setFontColor('#ffffff');\n }\n\n return sheet;\n}\n\n/**\n * Update Jira key for a feedback item\n */\nfunction updateJiraKey(feedbackId, jiraKey) {\n const sheet = getOrCreateSheet();\n const data = sheet.getDataRange().getValues();\n\n for (let i = 1; i < data.length; i++) {\n if (data[i][1] === feedbackId) {\n // Update Jira key (column L, index 11)\n sheet.getRange(i + 1, 12).setValue(jiraKey);\n return { success: true, row: i + 1 };\n }\n }\n\n return { success: false, error: 'Feedback not found' };\n}\n`.trim();\n}\n\n// ============================================\n// ZAPIER / WEBHOOK FORMATTERS\n// ============================================\n\n/**\n * Format feedback for Zapier webhook\n */\nexport function formatForZapier(feedbackData) {\n return {\n timestamp: new Date().toISOString(),\n id: feedbackData.id,\n feedback: feedbackData.feedback,\n type: feedbackData.type || 'bug',\n status: feedbackData.status || 'new',\n user_name: feedbackData.userName || 'Anonymous',\n user_email: feedbackData.userEmail || '',\n page_url: feedbackData.url || '',\n viewport: feedbackData.viewport ? `${feedbackData.viewport.width}x${feedbackData.viewport.height}` : '',\n has_screenshot: !!feedbackData.screenshot,\n has_video: !!feedbackData.video,\n element_selector: feedbackData.elementInfo?.selector || '',\n component_name: (feedbackData.elementInfo?.componentStack || [])[0] || ''\n };\n}\n\n// Default export\nexport default createSheetsHandler;\n","/**\n * React Visual Feedback - Client-Side Integration Manager\n *\n * Handles communication with integration endpoints and webhooks.\n * Used internally by FeedbackProvider and FeedbackDashboard.\n */\n\nimport {\n DEFAULT_SHEET_COLUMNS,\n DEFAULT_JIRA_FIELDS,\n DEFAULT_JIRA_STATUS_MAPPING,\n INTEGRATION_TYPES,\n feedbackToSheetRow,\n getSheetHeaders\n} from './config.js';\n\n// ============================================\n// INTEGRATION CLIENT\n// ============================================\n\nexport class IntegrationClient {\n constructor(config = {}) {\n this.jiraConfig = config.jira || null;\n this.sheetsConfig = config.sheets || null;\n this.onError = config.onError || (() => {});\n this.onSuccess = config.onSuccess || (() => {});\n }\n\n /**\n * Send feedback to selected integrations\n * @param {Object} feedbackData - The feedback data to send\n * @param {Object} options - Optional. Specify which integrations to send to\n * @param {boolean} options.jira - Send to Jira (defaults to jiraConfig.enabled)\n * @param {boolean} options.sheets - Send to Sheets (defaults to sheetsConfig.enabled)\n */\n async sendFeedback(feedbackData, options = {}) {\n const results = {\n jira: null,\n sheets: null\n };\n\n // Determine which integrations to use\n // If options are provided, use them; otherwise fall back to config\n const sendToJira = options.jira !== undefined ? options.jira : this.jiraConfig?.enabled;\n const sendToSheets = options.sheets !== undefined ? options.sheets : this.sheetsConfig?.enabled;\n\n const promises = [];\n\n if (sendToJira && this.jiraConfig?.enabled) {\n promises.push(\n this.sendToJira(feedbackData)\n .then(r => { results.jira = r; })\n .catch(e => { results.jira = { success: false, error: e.message }; })\n );\n }\n\n if (sendToSheets && this.sheetsConfig?.enabled) {\n promises.push(\n this.sendToSheets(feedbackData)\n .then(r => { results.sheets = r; })\n .catch(e => { results.sheets = { success: false, error: e.message }; })\n );\n }\n\n await Promise.all(promises);\n\n return results;\n }\n\n /**\n * Send feedback to Jira\n */\n async sendToJira(feedbackData) {\n const config = this.jiraConfig;\n\n if (!config?.enabled) {\n return { success: false, error: 'Jira integration not enabled' };\n }\n\n const type = config.type || INTEGRATION_TYPES.JIRA.SERVER;\n\n switch (type) {\n case INTEGRATION_TYPES.JIRA.SERVER:\n return this.sendToJiraServer(feedbackData, config);\n\n case INTEGRATION_TYPES.JIRA.AUTOMATION:\n return this.sendToJiraAutomation(feedbackData, config);\n\n case INTEGRATION_TYPES.JIRA.ZAPIER:\n return this.sendToZapier(feedbackData, config.webhookUrl, 'jira');\n\n default:\n throw new Error(`Unknown Jira integration type: ${type}`);\n }\n }\n\n /**\n * Send to our server handler using FormData for large file support\n */\n async sendToJiraServer(feedbackData, config) {\n const endpoint = config.endpoint || '/api/feedback/jira';\n\n // Use FormData for efficient binary data transfer\n const formData = new FormData();\n formData.append('action', 'create');\n\n // Separate binary data from metadata\n const { video, videoBlob, screenshot, eventLogs, ...metadata } = feedbackData;\n\n // Add metadata as JSON\n formData.append('metadata', JSON.stringify(metadata));\n\n // Add screenshot if present (as base64 string or blob)\n if (screenshot) {\n if (screenshot instanceof Blob) {\n formData.append('screenshot', screenshot, 'screenshot.png');\n } else if (typeof screenshot === 'string' && screenshot.startsWith('data:')) {\n // Convert base64 to blob for efficient transfer\n const screenshotBlob = await this.dataURLToBlob(screenshot);\n if (screenshotBlob) {\n formData.append('screenshot', screenshotBlob, 'screenshot.png');\n }\n }\n }\n\n // Add video if present (as blob - much more efficient than base64)\n if (videoBlob && videoBlob instanceof Blob) {\n const extension = videoBlob.type.includes('mp4') ? 'mp4' : 'webm';\n formData.append('video', videoBlob, `recording.${extension}`);\n } else if (video) {\n // Video is already base64 string - convert to blob\n if (typeof video === 'string' && video.startsWith('data:')) {\n const videoAsBlob = await this.dataURLToBlob(video);\n if (videoAsBlob) {\n const extension = video.includes('video/mp4') ? 'mp4' : 'webm';\n formData.append('video', videoAsBlob, `recording.${extension}`);\n }\n }\n }\n\n // Add event logs as JSON file\n if (eventLogs && eventLogs.length > 0) {\n const logsBlob = new Blob([JSON.stringify(eventLogs, null, 2)], { type: 'application/json' });\n formData.append('eventLogs', logsBlob, 'session-logs.json');\n }\n\n const response = await fetch(endpoint, {\n method: 'POST',\n body: formData\n // Note: Don't set Content-Type header - browser will set it with boundary\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(error);\n }\n\n const result = await response.json();\n this.onSuccess('jira', result);\n return result;\n }\n\n /**\n * Convert data URL to Blob\n */\n async dataURLToBlob(dataURL) {\n try {\n const response = await fetch(dataURL);\n return await response.blob();\n } catch (e) {\n return null;\n }\n }\n\n /**\n * Send to Jira Automation webhook\n */\n async sendToJiraAutomation(feedbackData, config) {\n if (!config.webhookUrl) {\n throw new Error('Jira Automation webhook URL not configured');\n }\n\n const payload = {\n summary: `[Feedback] ${(feedbackData.feedback || '').substring(0, 200)}`,\n description: feedbackData.feedback,\n type: feedbackData.type || 'bug',\n userName: feedbackData.userName || 'Anonymous',\n userEmail: feedbackData.userEmail || '',\n url: feedbackData.url || '',\n viewport: feedbackData.viewport ? `${feedbackData.viewport.width}x${feedbackData.viewport.height}` : '',\n hasScreenshot: !!feedbackData.screenshot,\n hasVideo: !!feedbackData.video,\n timestamp: feedbackData.timestamp || new Date().toISOString(),\n feedbackId: feedbackData.id\n };\n\n const response = await fetch(config.webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload)\n });\n\n if (!response.ok) {\n throw new Error(`Jira Automation webhook failed: ${response.status}`);\n }\n\n const result = { success: true, type: 'jira-automation' };\n this.onSuccess('jira', result);\n return result;\n }\n\n /**\n * Send feedback to Google Sheets\n */\n async sendToSheets(feedbackData) {\n const config = this.sheetsConfig;\n\n if (!config?.enabled) {\n return { success: false, error: 'Sheets integration not enabled' };\n }\n\n const type = config.type || INTEGRATION_TYPES.SHEETS.SERVER;\n\n switch (type) {\n case INTEGRATION_TYPES.SHEETS.SERVER:\n case INTEGRATION_TYPES.SHEETS.OAUTH:\n return this.sendToSheetsServer(feedbackData, config);\n\n case INTEGRATION_TYPES.SHEETS.APPS_SCRIPT:\n return this.sendToAppsScript(feedbackData, config);\n\n case INTEGRATION_TYPES.SHEETS.ZAPIER:\n return this.sendToZapier(feedbackData, config.webhookUrl, 'sheets');\n\n default:\n throw new Error(`Unknown Sheets integration type: ${type}`);\n }\n }\n\n /**\n * Send to our server handler\n */\n async sendToSheetsServer(feedbackData, config) {\n const endpoint = config.endpoint || '/api/feedback/sheets';\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'append',\n feedbackData\n })\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(error);\n }\n\n const result = await response.json();\n this.onSuccess('sheets', result);\n return result;\n }\n\n /**\n * Send to Google Apps Script deployment\n */\n async sendToAppsScript(feedbackData, config) {\n if (!config.deploymentUrl) {\n throw new Error('Google Apps Script deployment URL not configured');\n }\n\n const response = await fetch(config.deploymentUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'append',\n feedbackData\n })\n });\n\n if (!response.ok) {\n throw new Error(`Apps Script request failed: ${response.status}`);\n }\n\n const result = await response.json();\n\n if (!result.success) {\n throw new Error(result.error || 'Apps Script returned error');\n }\n\n this.onSuccess('sheets', result);\n return result;\n }\n\n /**\n * Send to Zapier webhook\n */\n async sendToZapier(feedbackData, webhookUrl, type) {\n if (!webhookUrl) {\n throw new Error(`Zapier webhook URL not configured for ${type}`);\n }\n\n const payload = {\n timestamp: new Date().toISOString(),\n id: feedbackData.id,\n feedback: feedbackData.feedback,\n type: feedbackData.type || 'bug',\n status: feedbackData.status || 'new',\n user_name: feedbackData.userName || 'Anonymous',\n user_email: feedbackData.userEmail || '',\n page_url: feedbackData.url || '',\n viewport: feedbackData.viewport ? `${feedbackData.viewport.width}x${feedbackData.viewport.height}` : '',\n has_screenshot: !!feedbackData.screenshot,\n has_video: !!feedbackData.video,\n element_selector: feedbackData.elementInfo?.selector || '',\n component_name: (feedbackData.elementInfo?.componentStack || [])[0] || ''\n };\n\n const response = await fetch(webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload)\n });\n\n if (!response.ok) {\n throw new Error(`Zapier webhook failed: ${response.status}`);\n }\n\n const result = { success: true, type: 'zapier' };\n this.onSuccess(type, result);\n return result;\n }\n\n /**\n * Update status in Jira\n */\n async updateJiraStatus(issueKey, status) {\n if (!this.jiraConfig?.enabled || !this.jiraConfig?.syncStatus) {\n return null;\n }\n\n const endpoint = this.jiraConfig.endpoint || '/api/feedback/jira';\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'updateStatus',\n issueKey,\n status\n })\n });\n\n if (!response.ok) {\n throw new Error('Failed to update Jira status');\n }\n\n return response.json();\n }\n\n /**\n * Update status in Sheets\n */\n async updateSheetsStatus(feedbackId, status) {\n if (!this.sheetsConfig?.enabled) {\n return null;\n }\n\n const type = this.sheetsConfig.type || INTEGRATION_TYPES.SHEETS.SERVER;\n\n if (type === INTEGRATION_TYPES.SHEETS.APPS_SCRIPT) {\n const response = await fetch(this.sheetsConfig.deploymentUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'updateStatus',\n feedbackId,\n status\n })\n });\n return response.json();\n }\n\n const endpoint = this.sheetsConfig.endpoint || '/api/feedback/sheets';\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'updateStatus',\n feedbackId,\n status\n })\n });\n\n return response.json();\n }\n\n /**\n * Get Jira issue status\n */\n async getJiraStatus(issueKey) {\n if (!this.jiraConfig?.enabled) {\n return null;\n }\n\n const endpoint = this.jiraConfig.endpoint || '/api/feedback/jira';\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'getStatus',\n issueKey\n })\n });\n\n return response.json();\n }\n}\n\n// ============================================\n// REACT HOOK\n// ============================================\n\nimport { useState, useCallback, useRef, useEffect } from 'react';\n\n/**\n * React hook for managing integrations\n */\nexport function useIntegrations(config = {}) {\n const clientRef = useRef(null);\n const [status, setStatus] = useState({\n jira: { loading: false, error: null, result: null },\n sheets: { loading: false, error: null, result: null }\n });\n\n // Initialize client\n useEffect(() => {\n clientRef.current = new IntegrationClient({\n ...config,\n onSuccess: (type, result) => {\n setStatus(prev => ({\n ...prev,\n [type]: { loading: false, error: null, result }\n }));\n },\n onError: (type, error) => {\n setStatus(prev => ({\n ...prev,\n [type]: { loading: false, error: error.message, result: null }\n }));\n }\n });\n }, [config.jira?.enabled, config.sheets?.enabled]);\n\n /**\n * Send feedback to integrations\n */\n const sendFeedback = useCallback(async (feedbackData) => {\n if (!clientRef.current) return null;\n\n // Set loading state\n setStatus(prev => ({\n jira: config.jira?.enabled ? { ...prev.jira, loading: true } : prev.jira,\n sheets: config.sheets?.enabled ? { ...prev.sheets, loading: true } : prev.sheets\n }));\n\n try {\n const results = await clientRef.current.sendFeedback(feedbackData);\n\n // Update status based on results\n setStatus({\n jira: results.jira\n ? { loading: false, error: results.jira.error || null, result: results.jira }\n : { loading: false, error: null, result: null },\n sheets: results.sheets\n ? { loading: false, error: results.sheets.error || null, result: results.sheets }\n : { loading: false, error: null, result: null }\n });\n\n return results;\n } catch (error) {\n setStatus(prev => ({\n jira: { ...prev.jira, loading: false, error: error.message },\n sheets: { ...prev.sheets, loading: false, error: error.message }\n }));\n throw error;\n }\n }, [config.jira?.enabled, config.sheets?.enabled]);\n\n /**\n * Update status in integrations\n */\n const updateStatus = useCallback(async (feedbackItem, newStatus) => {\n if (!clientRef.current) return null;\n\n const results = {};\n\n if (feedbackItem.jiraKey && config.jira?.syncStatus) {\n results.jira = await clientRef.current.updateJiraStatus(feedbackItem.jiraKey, newStatus);\n }\n\n if (config.sheets?.enabled) {\n results.sheets = await clientRef.current.updateSheetsStatus(feedbackItem.id, newStatus);\n }\n\n return results;\n }, [config.jira?.syncStatus, config.sheets?.enabled]);\n\n return {\n status,\n sendFeedback,\n updateStatus,\n client: clientRef.current\n };\n}\n\n// ============================================\n// EXPORTS\n// ============================================\n\nexport {\n DEFAULT_SHEET_COLUMNS,\n DEFAULT_JIRA_FIELDS,\n DEFAULT_JIRA_STATUS_MAPPING,\n INTEGRATION_TYPES,\n feedbackToSheetRow,\n getSheetHeaders\n} from './config.js';\n\n// Export Apps Script template getter for documentation\nexport { getAppsScriptTemplate } from './sheets.js';\n"],"names":["DEFAULT_SHEET_COLUMNS","timestamp","key","header","field","transform","value","Date","toISOString","id","feedback","type","status","userName","userEmail","url","viewport","concat","width","height","userAgent","includes","substring","screenshot","video","elementSelector","selector","componentName","_value$componentStack","componentStack","sourceFile","jiraKey","DEFAULT_SHEET_COLUMN_ORDER","DEFAULT_JIRA_FIELDS","summary","source","maxLength","prefix","data","text","length","maxLen","description","_data$elementInfo$com","lines","push","browser","elementInfo","join","lineNumber","attachments","issuetype","typeMapping","bug","feature","improvement","question","other","config","_process$env","envIssueType","process","env","JIRA_ISSUE_TYPE","labels","_toConsumableArray","priority","priorityMapping","DEFAULT_JIRA_STATUS_MAPPING","toJira","new","open","inProgress","underReview","onHold","resolved","closed","wontFix","fromJira","Open","Done","Closed","Resolved","INTEGRATION_TYPES","JIRA","SERVER","AUTOMATION","ZAPIER","SHEETS","OAUTH","APPS_SCRIPT","mergeSheetColumns","userColumns","arguments","undefined","columnOrder","merged","_objectSpread","Object","entries","forEach","_ref","_ref2","_slicedToArray","_typeof","order","keys","filter","k","columns","feedbackToSheetRow","feedbackData","_mergeSheetColumns","map","col","rawValue","getSheetHeaders","_mergeSheetColumns2","_columns$key","getAppsScriptTemplate","headers","sheetName","JSON","stringify","trim","IntegrationClient","_createClass","_classCallCheck","this","jiraConfig","jira","sheetsConfig","sheets","onError","onSuccess","_sendFeedback","_asyncToGenerator","_regenerator","m","_callee","_this$jiraConfig","_this$sheetsConfig","_this$jiraConfig2","_this$sheetsConfig2","options","results","sendToJira","sendToSheets","promises","_args","w","_context","n","enabled","then","r","e","success","error","message","Promise","all","a","_x","apply","_sendToJira","_callee2","_t","_context2","sendToJiraServer","sendToJiraAutomation","sendToZapier","webhookUrl","Error","_x2","_sendToJiraServer","_callee3","endpoint","formData","videoBlob","eventLogs","metadata","screenshotBlob","extension","videoAsBlob","_extension","logsBlob","response","result","_context3","FormData","append","_objectWithoutProperties","_excluded","Blob","startsWith","dataURLToBlob","v","fetch","method","body","ok","json","_x3","_x4","_dataURLToBlob","_callee4","dataURL","_context4","p","blob","_x5","_sendToJiraAutomation","_callee5","payload","_context5","hasScreenshot","hasVideo","feedbackId","_x6","_x7","_sendToSheets","_callee6","_t3","_context6","sendToSheetsServer","sendToAppsScript","_x8","_sendToSheetsServer","_callee7","_context7","action","_x9","_x0","_sendToAppsScript","_callee8","_context8","deploymentUrl","_x1","_x10","_sendToZapier","_callee9","_feedbackData$element","_feedbackData$element2","_context9","user_name","user_email","page_url","has_screenshot","has_video","element_selector","component_name","_x11","_x12","_x13","_updateJiraStatus","_callee0","issueKey","_this$jiraConfig3","_this$jiraConfig4","_context0","syncStatus","_x14","_x15","_updateSheetsStatus","_callee1","_this$sheetsConfig3","_response","_context1","_x16","_x17","_getJiraStatus","_callee10","_this$jiraConfig5","_context10","_x18","useIntegrations","_config$jira","_config$sheets","_config$jira3","_config$sheets3","_config$jira5","_config$sheets5","clientRef","useRef","_useState2","useState","loading","setStatus","useEffect","current","prev","_defineProperty","sendFeedback","useCallback","_callee11","_t4","_context11","_config$jira2","_config$sheets2","_x19","updateStatus","_callee12","feedbackItem","newStatus","_config$jira4","_config$sheets4","_context12","updateJiraStatus","updateSheetsStatus","_x20","_x21","client"],"mappings":"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"}
|