@webority/mobile-support 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -76,6 +76,8 @@ const SupportTicketScreen = ({ route }) => <SupportTicketDetail ticketId={route.
76
76
  const NewSupportTicketScreen = ({ navigation, route }) => (
77
77
  <NewSupportTicket
78
78
  initialDraft={route.params?.draft}
79
+ defaultCategory="Bug report"
80
+ appVersion={AppSettings.VERSION_DISPLAY}
79
81
  onCancel={() => navigation.goBack()}
80
82
  onCreated={(t) => navigation.replace('SupportTicket', { id: t.id })}
81
83
  />
@@ -88,11 +90,17 @@ const NewSupportTicketScreen = ({ navigation, route }) => (
88
90
  does pull to refresh. Empty state, retry on failure, and a Load more retry when a later page
89
91
  fails without losing the rows already shown.
90
92
  - **SupportTicketDetail**: the thread as bubbles, status events as small centred lines, image
91
- thumbnails that open full screen, a reply box with photos, Reopen when `canReopen`, and a
92
- satisfied or not satisfied rating with an optional comment when `canRate`. Replying to a
93
- resolved or closed ticket reopens it.
93
+ thumbnails that open full screen, a reply box with photos, and Reopen when `canReopen`. When
94
+ `canRate`, it asks "Did this solve your problem?" with an optional comment; once answered, it
95
+ shows the answer and the comment instead. A message with no author name reads "You" or
96
+ "Support team". Replying to a resolved or closed ticket reopens it.
94
97
  - **NewSupportTicket**: category, subject, message and photos, checked against the limits the
95
- product sends in `GET /settings` before anything is uploaded.
98
+ product sends in `GET /settings` before anything is uploaded. `defaultCategory` preselects a
99
+ category the product lists (a draft's own category wins; one the product does not list starts
100
+ unselected). `appVersion` is recorded when the draft carries none, and the device line
101
+ (`describeDevice()`) is recorded on every ticket.
102
+ - Both forms keep the focused field above the keyboard (mobile-ui's `KeyboardAwareScrollView`,
103
+ which needs the app's `KeyboardProvider` at the root).
96
104
  - **SupportContact**: the support email with copy and compose, the phone number, and the hours.
97
105
 
98
106
  ## Report an issue
@@ -107,8 +115,10 @@ import { ReportIssueButton } from '@webority/mobile-support/report';
107
115
  />;
108
116
  ```
109
117
 
110
- The button captures the screen, then hands your app a draft with the image under
111
- `screenshots`, the screen name as the page, the device line and the app version.
118
+ The button captures the screen as soon as it is pressed, then hands your app a draft with the
119
+ image under `screenshots`, the screen name as the page, the device line and the app version. The
120
+ person can remove the screenshot on the form before sending. An app that wants no capture opens
121
+ `NewSupportTicket` directly; the person can still attach their own screenshots as photos.
112
122
  `captureAndReport(options)` does the same without the button. The device line reads the
113
123
  platform and OS version, plus the model when the app has called mobile-core's
114
124
  `setDeviceContext`.
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.NewSupportTicket=void 0;var _mobileUi=require("@webority/mobile-ui"),_react=require("react"),_reactNative=require("react-native"),_client=require("../client.js"),_SupportProvider=require("../SupportProvider.js"),_validation=require("../validation.js"),_PhotoTray=require("./PhotoTray.js"),_jsxRuntime=require("react/jsx-runtime");const TicketForm=({config:e,styles:t,onCreated:i,onCancel:r,initialDraft:a})=>{const o=(0,_SupportProvider.useCreateSupportTicket)(),[n,s]=(0,_react.useState)([]),[l,u]=(0,_react.useState)(a?.screenshots??[]),[c,d]=(0,_react.useState)(null),[m,p]=(0,_react.useState)(null),g=(0,_mobileUi.useForm)({initialValues:{category:a?.category??"",subject:a?.subject??"",body:a?.body??""},validate:{category:t=>(0,_validation.validateCategory)(t,e),subject:t=>(0,_validation.validateSubject)(t,e),body:t=>(0,_validation.validateBody)(t,e)},onSubmit:async t=>{const r=(0,_validation.validateFiles)([...l,...n],e);if(d(r??null),!r){p(null);try{const e=await o({category:t.category,subject:t.subject.trim(),body:t.body.trim(),pageUrl:a?.pageUrl,userAgent:a?.userAgent,appVersion:a?.appVersion,files:n,screenshots:l});i(e)}catch(e){p((0,_client.toSupportApiError)(e).message)}}}}),x=g.getFieldProps("category"),b=g.getFieldProps("subject"),_=g.getFieldProps("body"),h=l.length+n.length;return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{contentContainerStyle:t.content,keyboardShouldPersistTaps:"handled",children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",color:"secondary",children:"Tell us what you need. We reply by email and in this ticket."}),(0,_jsxRuntime.jsx)(_mobileUi.Select,{label:"Category",placeholder:"Choose a category",required:!0,options:e.categories.map(e=>({label:e,value:e})),value:x.value||void 0,onChange:e=>x.setValue(String(e),!0),error:x.error,testID:"support-new-category"}),(0,_jsxRuntime.jsx)(_mobileUi.Input,{label:"Subject",placeholder:"A short summary",required:!0,maxLength:e.subjectMaxLength,value:b.value,onChangeText:b.onChangeText,onBlur:b.onBlur,error:b.error,testID:"support-new-subject"}),(0,_jsxRuntime.jsx)(_mobileUi.Input,{label:"Message",placeholder:"What happened, and what did you expect?",required:!0,multiline:!0,maxLength:e.bodyMaxLength,value:_.value,onChangeText:_.onChangeText,onBlur:_.onBlur,error:_.error,testID:"support-new-body"}),l.length>0&&(0,_jsxRuntime.jsx)(_PhotoTray.PhotoTray,{label:"Screenshot",photos:l,onChange:u,remaining:0,allowAdd:!1,maxBytes:e.maxAttachmentBytes,disabled:g.isSubmitting}),(0,_jsxRuntime.jsx)(_PhotoTray.PhotoTray,{label:"Photos",photos:n,onChange:s,remaining:e.maxAttachmentsPerMessage-h,maxBytes:e.maxAttachmentBytes,disabled:g.isSubmitting}),(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"caption",color:"tertiary",children:`Attach up to ${e.maxAttachmentsPerMessage} files.`}),(c||m)&&(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",color:"error",accessibilityLiveRegion:"polite",children:c??m}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:t.actions,children:[r&&(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Cancel",variant:"ghost",tone:"neutral",onPress:r,disabled:g.isSubmitting}),(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Send ticket",loading:g.isSubmitting,disabled:g.isSubmitting,onPress:g.submit,testID:"support-new-submit"})]})]})},NewSupportTicket=e=>{const t=(0,_mobileUi.useTheme)(),i=(0,_react.useMemo)(()=>buildStyles(t),[t]),{config:r,loading:a,error:o,reload:n}=(0,_SupportProvider.useSupportConfig)(),s=e.testID??"support-new-ticket";return r?(0,_jsxRuntime.jsx)(_reactNative.View,{style:i.root,testID:s,children:(0,_jsxRuntime.jsx)(TicketForm,{...e,config:r,styles:i})}):(0,_jsxRuntime.jsx)(_reactNative.View,{style:i.center,testID:s,children:a?(0,_jsxRuntime.jsx)(_mobileUi.Spinner,{accessibilityLabel:"Loading"}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"body",color:"error",align:"center",children:o?.message??"Support is not available right now."}),(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Try again",variant:"ghost",onPress:()=>{n()}})]})})};exports.NewSupportTicket=NewSupportTicket;const buildStyles=e=>_reactNative.StyleSheet.create({root:{flex:1},content:{padding:e.spacing.md,gap:e.spacing.md},center:{flex:1,alignItems:"center",justifyContent:"center",padding:e.spacing.xl,gap:e.spacing.sm},actions:{flexDirection:"row",justifyContent:"flex-end",gap:e.spacing.sm}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.NewSupportTicket=void 0;var _mobileUi=require("@webority/mobile-ui"),_react=require("react"),_reactNative=require("react-native"),_client=require("../client.js"),_device=require("../device.js"),_SupportProvider=require("../SupportProvider.js"),_validation=require("../validation.js"),_PhotoTray=require("./PhotoTray.js"),_jsxRuntime=require("react/jsx-runtime");const TicketForm=({config:e,styles:t,onCreated:i,onCancel:r,initialDraft:o,defaultCategory:a,appVersion:s})=>{const n=(0,_SupportProvider.useCreateSupportTicket)(),listed=t=>t&&e.categories.includes(t)?t:void 0,[l,u]=(0,_react.useState)([]),[c,d]=(0,_react.useState)(o?.screenshots??[]),[m,p]=(0,_react.useState)(null),[g,x]=(0,_react.useState)(null),b=(0,_mobileUi.useForm)({initialValues:{category:listed(o?.category)??listed(a)??"",subject:o?.subject??"",body:o?.body??""},validate:{category:t=>(0,_validation.validateCategory)(t,e),subject:t=>(0,_validation.validateSubject)(t,e),body:t=>(0,_validation.validateBody)(t,e)},onSubmit:async t=>{const r=(0,_validation.validateFiles)([...c,...l],e);if(p(r??null),!r){x(null);try{const e=await n({category:t.category,subject:t.subject.trim(),body:t.body.trim(),pageUrl:o?.pageUrl,userAgent:o?.userAgent??(0,_device.describeDevice)(),appVersion:o?.appVersion??s,files:l,screenshots:c});i(e)}catch(e){x((0,_client.toSupportApiError)(e).message)}}}}),_=b.getFieldProps("category"),j=b.getFieldProps("subject"),y=b.getFieldProps("body"),h=c.length+l.length;return(0,_jsxRuntime.jsxs)(_mobileUi.KeyboardAwareScrollView,{contentContainerStyle:t.content,safeAreaEdges:[],children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",color:"secondary",children:"Tell us what you need. We reply by email and in this ticket."}),(0,_jsxRuntime.jsx)(_mobileUi.Select,{label:"Category",placeholder:"Choose a category",required:!0,options:e.categories.map(e=>({label:e,value:e})),value:_.value||void 0,onChange:e=>_.setValue(String(e),!0),error:_.error,testID:"support-new-category"}),(0,_jsxRuntime.jsx)(_mobileUi.Input,{label:"Subject",placeholder:"A short summary",required:!0,maxLength:e.subjectMaxLength,value:j.value,onChangeText:j.onChangeText,onBlur:j.onBlur,error:j.error,testID:"support-new-subject"}),(0,_jsxRuntime.jsx)(_mobileUi.Input,{label:"Message",placeholder:"What happened, and what did you expect?",required:!0,multiline:!0,maxLength:e.bodyMaxLength,value:y.value,onChangeText:y.onChangeText,onBlur:y.onBlur,error:y.error,testID:"support-new-body"}),c.length>0&&(0,_jsxRuntime.jsx)(_PhotoTray.PhotoTray,{label:"Screenshot",photos:c,onChange:d,remaining:0,allowAdd:!1,maxBytes:e.maxAttachmentBytes,disabled:b.isSubmitting}),(0,_jsxRuntime.jsx)(_PhotoTray.PhotoTray,{label:"Photos",photos:l,onChange:u,remaining:e.maxAttachmentsPerMessage-h,maxBytes:e.maxAttachmentBytes,disabled:b.isSubmitting}),(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"caption",color:"tertiary",children:`Attach up to ${e.maxAttachmentsPerMessage} files.`}),(m||g)&&(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",color:"error",accessibilityLiveRegion:"polite",children:m??g}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:t.actions,children:[r&&(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Cancel",variant:"ghost",tone:"neutral",onPress:r,disabled:b.isSubmitting}),(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Send ticket",loading:b.isSubmitting,disabled:b.isSubmitting,onPress:b.submit,testID:"support-new-submit"})]})]})},NewSupportTicket=e=>{const t=(0,_mobileUi.useTheme)(),i=(0,_react.useMemo)(()=>buildStyles(t),[t]),{config:r,loading:o,error:a,reload:s}=(0,_SupportProvider.useSupportConfig)(),n=e.testID??"support-new-ticket";return r?(0,_jsxRuntime.jsx)(_reactNative.View,{style:i.root,testID:n,children:(0,_jsxRuntime.jsx)(TicketForm,{...e,config:r,styles:i})}):(0,_jsxRuntime.jsx)(_reactNative.View,{style:i.center,testID:n,children:o?(0,_jsxRuntime.jsx)(_mobileUi.Spinner,{accessibilityLabel:"Loading"}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"body",color:"error",align:"center",children:a?.message??"Support is not available right now."}),(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Try again",variant:"ghost",onPress:()=>{s()}})]})})};exports.NewSupportTicket=NewSupportTicket;const buildStyles=e=>_reactNative.StyleSheet.create({root:{flex:1},content:{padding:e.spacing.md,gap:e.spacing.md},center:{flex:1,alignItems:"center",justifyContent:"center",padding:e.spacing.xl,gap:e.spacing.sm},actions:{flexDirection:"row",justifyContent:"flex-end",gap:e.spacing.sm}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.SupportTicketDetail=void 0;var _mobileCore=require("@webority/mobile-core"),_mobileUi=require("@webority/mobile-ui"),_react=require("react"),_reactNative=require("react-native"),_SupportProvider=require("../SupportProvider.js"),_validation=require("../validation.js"),_Attachments=require("./Attachments.js"),_PhotoTray=require("./PhotoTray.js"),_SupportTicketList=require("./SupportTicketList.js"),_jsxRuntime=require("react/jsx-runtime");const MessageBubble=({message:e,styles:t,timeZone:i,onOpenImage:s})=>{if("System"===e.authorKind)return(0,_jsxRuntime.jsx)(_reactNative.View,{style:t.system,testID:`support-message-${e.id}`,children:(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"caption",color:"tertiary",align:"center",children:`${e.body}, ${(0,_mobileCore.formatDateTime)(e.createdDateTimeUtc,{zone:i})}`})});const a="Customer"===e.authorKind;return(0,_jsxRuntime.jsx)(_reactNative.View,{style:[t.bubbleRow,a?t.mineRow:t.theirsRow],testID:`support-message-${e.id}`,children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[t.bubble,a?t.mine:t.theirs],children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"label",color:a?"primary":"secondary",children:e.authorName??"-"}),(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"body",selectable:!0,children:e.body}),(0,_jsxRuntime.jsx)(_Attachments.AttachmentList,{attachments:e.attachments,onOpenImage:s}),(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"caption",color:"tertiary",children:(0,_mobileCore.formatDateTime)(e.createdDateTimeUtc,{zone:i})})]})})},SATISFACTION_TEXT={Satisfied:"You said we handled this well.",Unsatisfied:"You said we did not handle this well."},SupportTicketDetail=({ticketId:e,testID:t="support-ticket-detail"})=>{const i=(0,_mobileUi.useTheme)(),s=(0,_react.useMemo)(()=>buildStyles(i),[i]),{config:a}=(0,_SupportProvider.useSupportConfig)(),n=(0,_SupportProvider.useSupportTimeZone)(),{ticket:r,loading:o,error:l,actionError:c,busy:m,reload:u,reply:d,reopen:x,rate:p}=(0,_SupportProvider.useSupportTicket)(e),[_,b]=(0,_react.useState)(null),[j,g]=(0,_react.useState)(""),[h,y]=(0,_react.useState)([]),[R,S]=(0,_react.useState)(null),[v,T]=(0,_react.useState)(null),[f,w]=(0,_react.useState)("");if(!r)return(0,_jsxRuntime.jsx)(_reactNative.View,{style:s.center,testID:t,children:o?(0,_jsxRuntime.jsx)(_mobileUi.Spinner,{accessibilityLabel:"Loading the ticket"}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"body",color:"error",align:"center",children:l?.message??"That ticket could not be found."}),(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Try again",variant:"ghost",onPress:()=>{u()}})]})});const U=r.messages.filter(e=>!e.isInternal);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:s.root,testID:t,children:[(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{contentContainerStyle:s.content,keyboardShouldPersistTaps:"handled",children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:s.head,children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"h3",accessibilityRole:"header",children:r.subject}),(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",color:"secondary",children:`${r.number}, ${r.category}`}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:s.headRow,children:[(0,_jsxRuntime.jsx)(_mobileUi.StatusBadge,{label:r.statusLabel,tone:_SupportTicketList.STATUS_TONES[r.status]??"neutral",accessibilityLabel:`Status: ${r.statusLabel}`}),(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"caption",color:"tertiary",children:`Opened ${(0,_mobileCore.formatDateTime)(r.createdDateTimeUtc,{zone:n})}`})]})]}),r.canReopen&&(0,_jsxRuntime.jsxs)(_mobileUi.Card,{variant:"outlined",bodyStyle:s.section,children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",children:`This ticket is ${r.statusLabel}. Reopen it if you still need help.`}),(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Reopen ticket",variant:"outline",size:"sm",loading:m,disabled:m,onPress:()=>{x()},testID:"support-reopen"})]}),r.canRate&&(0,_jsxRuntime.jsxs)(_mobileUi.Card,{variant:"outlined",bodyStyle:s.section,testID:"support-rating",children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"label",children:"How did we do?"}),r.satisfaction&&(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",color:"secondary",children:SATISFACTION_TEXT[r.satisfaction]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:s.ratingRow,children:[(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Satisfied",size:"sm",leftIcon:"like",variant:"Satisfied"===v?"solid":"outline",tone:"success",accessibilityState:{selected:"Satisfied"===v},onPress:()=>T("Satisfied"),testID:"support-rate-satisfied"}),(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Not satisfied",size:"sm",leftIcon:"dislike",variant:"Unsatisfied"===v?"solid":"outline",tone:"error",accessibilityState:{selected:"Unsatisfied"===v},onPress:()=>T("Unsatisfied"),testID:"support-rate-unsatisfied"})]}),v&&(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_mobileUi.Input,{label:"Anything to add? (optional)",value:f,onChangeText:w,multiline:!0,maxLength:a?.satisfactionCommentMaxLength,testID:"support-rating-comment"}),(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Send rating",size:"sm",loading:m,disabled:m,onPress:()=>{(async()=>{v&&await p({satisfaction:v,comment:f})&&(T(null),w(""))})()},testID:"support-rating-send"})]})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:s.thread,accessibilityLabel:"Conversation",children:U.map(e=>(0,_jsxRuntime.jsx)(MessageBubble,{message:e,styles:s,timeZone:n,onOpenImage:(e,t)=>b({uri:e,name:t})},e.id))}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:s.section,children:[(0,_jsxRuntime.jsx)(_mobileUi.Input,{label:"Your reply",placeholder:"Write a reply to the support team",value:j,onChangeText:g,multiline:!0,maxLength:a?.bodyMaxLength,error:R??void 0,testID:"support-reply-input"}),a&&(0,_jsxRuntime.jsx)(_PhotoTray.PhotoTray,{photos:h,onChange:y,remaining:a.maxAttachmentsPerMessage-h.length,maxBytes:a.maxAttachmentBytes,disabled:m}),r.canReopen&&(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"caption",color:"secondary",children:"Replying reopens this ticket."}),c&&(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",color:"error",accessibilityLiveRegion:"polite",children:c.message}),(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Send reply",leftIcon:"send",loading:m,disabled:m,onPress:()=>{(async()=>{const e=j.trim(),t=a?(0,_validation.validateBody)(e,a)??(0,_validation.validateFiles)(h,a):e?void 0:"Write a message.";t?S(t):(S(null),await d({body:e,files:h})&&(g(""),y([])))})()},testID:"support-reply-send"})]})]}),(0,_jsxRuntime.jsx)(_Attachments.ImageViewer,{image:_,onClose:()=>b(null)})]})};exports.SupportTicketDetail=SupportTicketDetail;const buildStyles=e=>_reactNative.StyleSheet.create({root:{flex:1},content:{padding:e.spacing.md,gap:e.spacing.md},center:{flex:1,alignItems:"center",justifyContent:"center",padding:e.spacing.xl,gap:e.spacing.sm},head:{gap:e.spacing.xxs},headRow:{flexDirection:"row",alignItems:"center",gap:e.spacing.sm,marginTop:e.spacing.xs},section:{gap:e.spacing.sm},ratingRow:{flexDirection:"row",gap:e.spacing.sm},thread:{gap:e.spacing.sm},system:{paddingHorizontal:e.spacing.lg,paddingVertical:e.spacing.xxs},bubbleRow:{flexDirection:"row"},mineRow:{justifyContent:"flex-end"},theirsRow:{justifyContent:"flex-start"},bubble:{maxWidth:"85%",borderRadius:e.radius.lg,padding:e.spacing.sm,gap:e.spacing.xxs},mine:{backgroundColor:e.colors.primaryMuted},theirs:{backgroundColor:e.colors.background.secondary}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.SupportTicketDetail=void 0;var _mobileCore=require("@webority/mobile-core"),_mobileUi=require("@webority/mobile-ui"),_react=require("react"),_reactNative=require("react-native"),_SupportProvider=require("../SupportProvider.js"),_validation=require("../validation.js"),_Attachments=require("./Attachments.js"),_PhotoTray=require("./PhotoTray.js"),_SupportTicketList=require("./SupportTicketList.js"),_jsxRuntime=require("react/jsx-runtime");const MessageBubble=({message:e,styles:t,timeZone:i,onOpenImage:s})=>{if("System"===e.authorKind)return(0,_jsxRuntime.jsx)(_reactNative.View,{style:t.system,testID:`support-message-${e.id}`,children:(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"caption",color:"tertiary",align:"center",children:`${e.body}, ${(0,_mobileCore.formatDateTime)(e.createdDateTimeUtc,{zone:i})}`})});const a="Customer"===e.authorKind;return(0,_jsxRuntime.jsx)(_reactNative.View,{style:[t.bubbleRow,a?t.mineRow:t.theirsRow],testID:`support-message-${e.id}`,children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[t.bubble,a?t.mine:t.theirs],children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"label",color:a?"primary":"secondary",children:e.authorName??(a?"You":"Support team")}),(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"body",selectable:!0,children:e.body}),(0,_jsxRuntime.jsx)(_Attachments.AttachmentList,{attachments:e.attachments,onOpenImage:s}),(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"caption",color:"tertiary",children:(0,_mobileCore.formatDateTime)(e.createdDateTimeUtc,{zone:i})})]})})},SATISFACTION_TEXT={Satisfied:"You told us this solved your problem.",Unsatisfied:"You told us this did not solve your problem."},SupportTicketDetail=({ticketId:e,testID:t="support-ticket-detail"})=>{const i=(0,_mobileUi.useTheme)(),s=(0,_react.useMemo)(()=>buildStyles(i),[i]),{config:a}=(0,_SupportProvider.useSupportConfig)(),n=(0,_SupportProvider.useSupportTimeZone)(),{ticket:o,loading:r,error:l,actionError:c,busy:m,reload:u,reply:d,reopen:x,rate:p}=(0,_SupportProvider.useSupportTicket)(e),[_,b]=(0,_react.useState)(null),[j,g]=(0,_react.useState)(""),[y,h]=(0,_react.useState)([]),[R,v]=(0,_react.useState)(null),[S,T]=(0,_react.useState)(null),[f,U]=(0,_react.useState)("");if(!o)return(0,_jsxRuntime.jsx)(_reactNative.View,{style:s.center,testID:t,children:r?(0,_jsxRuntime.jsx)(_mobileUi.Spinner,{accessibilityLabel:"Loading the ticket"}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"body",color:"error",align:"center",children:l?.message??"That ticket could not be found."}),(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Try again",variant:"ghost",onPress:()=>{u()}})]})});const w=o.messages.filter(e=>!e.isInternal);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:s.root,testID:t,children:[(0,_jsxRuntime.jsxs)(_mobileUi.KeyboardAwareScrollView,{contentContainerStyle:s.content,safeAreaEdges:[],children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:s.head,children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"h3",accessibilityRole:"header",children:o.subject}),(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",color:"secondary",children:`${o.number}, ${o.category}`}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:s.headRow,children:[(0,_jsxRuntime.jsx)(_mobileUi.StatusBadge,{label:o.statusLabel,tone:_SupportTicketList.STATUS_TONES[o.status]??"neutral",accessibilityLabel:`Status: ${o.statusLabel}`}),(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"caption",color:"tertiary",children:`Opened ${(0,_mobileCore.formatDateTime)(o.createdDateTimeUtc,{zone:n})}`})]})]}),o.canReopen&&(0,_jsxRuntime.jsxs)(_mobileUi.Card,{variant:"outlined",bodyStyle:s.section,children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",children:`This ticket is ${o.statusLabel}. Reopen it if you still need help.`}),(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Reopen ticket",variant:"outline",size:"sm",loading:m,disabled:m,onPress:()=>{x()},testID:"support-reopen"})]}),o.satisfaction?(0,_jsxRuntime.jsxs)(_mobileUi.Card,{variant:"outlined",bodyStyle:s.section,testID:"support-rating",children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",accessibilityLiveRegion:"polite",children:SATISFACTION_TEXT[o.satisfaction]}),o.satisfactionComment?(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",color:"secondary",children:`Your comment: ${o.satisfactionComment}`}):null]}):o.canRate?(0,_jsxRuntime.jsxs)(_mobileUi.Card,{variant:"outlined",bodyStyle:s.section,testID:"support-rating",children:[(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"label",children:"Did this solve your problem?"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:s.ratingRow,children:[(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Yes, it is solved",size:"sm",leftIcon:"like",variant:"Satisfied"===S?"solid":"outline",tone:"success",accessibilityState:{selected:"Satisfied"===S},onPress:()=>T("Satisfied"),testID:"support-rate-satisfied"}),(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"No, it is not",size:"sm",leftIcon:"dislike",variant:"Unsatisfied"===S?"solid":"outline",tone:"error",accessibilityState:{selected:"Unsatisfied"===S},onPress:()=>T("Unsatisfied"),testID:"support-rate-unsatisfied"})]}),S&&(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_mobileUi.Input,{label:"Anything to add? (optional)",helperText:"Your comment goes to the support team.",value:f,onChangeText:U,multiline:!0,maxLength:a?.satisfactionCommentMaxLength,testID:"support-rating-comment"}),(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Send answer",size:"sm",loading:m,disabled:m,onPress:()=>{(async()=>{S&&await p({satisfaction:S,comment:f})&&(T(null),U(""))})()},testID:"support-rating-send"})]})]}):null,(0,_jsxRuntime.jsx)(_reactNative.View,{style:s.thread,accessibilityLabel:"Conversation",children:w.map(e=>(0,_jsxRuntime.jsx)(MessageBubble,{message:e,styles:s,timeZone:n,onOpenImage:(e,t)=>b({uri:e,name:t})},e.id))}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:s.section,children:[(0,_jsxRuntime.jsx)(_mobileUi.Input,{label:"Your reply",placeholder:"Write a reply to the support team",value:j,onChangeText:g,multiline:!0,maxLength:a?.bodyMaxLength,error:R??void 0,testID:"support-reply-input"}),a&&(0,_jsxRuntime.jsx)(_PhotoTray.PhotoTray,{photos:y,onChange:h,remaining:a.maxAttachmentsPerMessage-y.length,maxBytes:a.maxAttachmentBytes,disabled:m}),o.canReopen&&(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"caption",color:"secondary",children:"Replying reopens this ticket."}),c&&(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",color:"error",accessibilityLiveRegion:"polite",children:c.message}),(0,_jsxRuntime.jsx)(_mobileUi.Button,{title:"Send reply",leftIcon:"send",loading:m,disabled:m,onPress:()=>{(async()=>{const e=j.trim(),t=a?(0,_validation.validateBody)(e,a)??(0,_validation.validateFiles)(y,a):e?void 0:"Write a message.";t?v(t):(v(null),await d({body:e,files:y})&&(g(""),h([])))})()},testID:"support-reply-send"})]})]}),(0,_jsxRuntime.jsx)(_Attachments.ImageViewer,{image:_,onClose:()=>b(null)})]})};exports.SupportTicketDetail=SupportTicketDetail;const buildStyles=e=>_reactNative.StyleSheet.create({root:{flex:1},content:{padding:e.spacing.md,gap:e.spacing.md},center:{flex:1,alignItems:"center",justifyContent:"center",padding:e.spacing.xl,gap:e.spacing.sm},head:{gap:e.spacing.xxs},headRow:{flexDirection:"row",alignItems:"center",gap:e.spacing.sm,marginTop:e.spacing.xs},section:{gap:e.spacing.sm},ratingRow:{flexDirection:"row",flexWrap:"wrap",gap:e.spacing.sm},thread:{gap:e.spacing.sm},system:{paddingHorizontal:e.spacing.lg,paddingVertical:e.spacing.xxs},bubbleRow:{flexDirection:"row"},mineRow:{justifyContent:"flex-end"},theirsRow:{justifyContent:"flex-start"},bubble:{maxWidth:"85%",borderRadius:e.radius.lg,padding:e.spacing.sm,gap:e.spacing.xxs},mine:{backgroundColor:e.colors.primaryMuted},theirs:{backgroundColor:e.colors.background.secondary}});
@@ -1 +1 @@
1
- "use strict";import{Button,Input,Select,Spinner,Text,useForm,useTheme}from"@webority/mobile-ui";import{useMemo,useState}from"react";import{ScrollView,StyleSheet,View}from"react-native";import{toSupportApiError}from"../client.js";import{useCreateSupportTicket,useSupportConfig}from"../SupportProvider.js";import{validateBody,validateCategory,validateFiles,validateSubject}from"../validation.js";import{PhotoTray}from"./PhotoTray.js";import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";const TicketForm=({config:e,styles:t,onCreated:o,onCancel:r,initialDraft:a})=>{const s=useCreateSupportTicket(),[n,i]=useState([]),[l,c]=useState(a?.screenshots??[]),[u,d]=useState(null),[p,g]=useState(null),m=useForm({initialValues:{category:a?.category??"",subject:a?.subject??"",body:a?.body??""},validate:{category:t=>validateCategory(t,e),subject:t=>validateSubject(t,e),body:t=>validateBody(t,e)},onSubmit:async t=>{const r=validateFiles([...l,...n],e);if(d(r??null),!r){g(null);try{const e=await s({category:t.category,subject:t.subject.trim(),body:t.body.trim(),pageUrl:a?.pageUrl,userAgent:a?.userAgent,appVersion:a?.appVersion,files:n,screenshots:l});o(e)}catch(e){g(toSupportApiError(e).message)}}}}),h=m.getFieldProps("category"),y=m.getFieldProps("subject"),b=m.getFieldProps("body"),x=l.length+n.length;return _jsxs(ScrollView,{contentContainerStyle:t.content,keyboardShouldPersistTaps:"handled",children:[_jsx(Text,{variant:"bodySmall",color:"secondary",children:"Tell us what you need. We reply by email and in this ticket."}),_jsx(Select,{label:"Category",placeholder:"Choose a category",required:!0,options:e.categories.map(e=>({label:e,value:e})),value:h.value||void 0,onChange:e=>h.setValue(String(e),!0),error:h.error,testID:"support-new-category"}),_jsx(Input,{label:"Subject",placeholder:"A short summary",required:!0,maxLength:e.subjectMaxLength,value:y.value,onChangeText:y.onChangeText,onBlur:y.onBlur,error:y.error,testID:"support-new-subject"}),_jsx(Input,{label:"Message",placeholder:"What happened, and what did you expect?",required:!0,multiline:!0,maxLength:e.bodyMaxLength,value:b.value,onChangeText:b.onChangeText,onBlur:b.onBlur,error:b.error,testID:"support-new-body"}),l.length>0&&_jsx(PhotoTray,{label:"Screenshot",photos:l,onChange:c,remaining:0,allowAdd:!1,maxBytes:e.maxAttachmentBytes,disabled:m.isSubmitting}),_jsx(PhotoTray,{label:"Photos",photos:n,onChange:i,remaining:e.maxAttachmentsPerMessage-x,maxBytes:e.maxAttachmentBytes,disabled:m.isSubmitting}),_jsx(Text,{variant:"caption",color:"tertiary",children:`Attach up to ${e.maxAttachmentsPerMessage} files.`}),(u||p)&&_jsx(Text,{variant:"bodySmall",color:"error",accessibilityLiveRegion:"polite",children:u??p}),_jsxs(View,{style:t.actions,children:[r&&_jsx(Button,{title:"Cancel",variant:"ghost",tone:"neutral",onPress:r,disabled:m.isSubmitting}),_jsx(Button,{title:"Send ticket",loading:m.isSubmitting,disabled:m.isSubmitting,onPress:m.submit,testID:"support-new-submit"})]})]})};export const NewSupportTicket=e=>{const t=useTheme(),o=useMemo(()=>buildStyles(t),[t]),{config:r,loading:a,error:s,reload:n}=useSupportConfig(),i=e.testID??"support-new-ticket";return _jsx(View,r?{style:o.root,testID:i,children:_jsx(TicketForm,{...e,config:r,styles:o})}:{style:o.center,testID:i,children:a?_jsx(Spinner,{accessibilityLabel:"Loading"}):_jsxs(_Fragment,{children:[_jsx(Text,{variant:"body",color:"error",align:"center",children:s?.message??"Support is not available right now."}),_jsx(Button,{title:"Try again",variant:"ghost",onPress:()=>{n()}})]})})};const buildStyles=e=>StyleSheet.create({root:{flex:1},content:{padding:e.spacing.md,gap:e.spacing.md},center:{flex:1,alignItems:"center",justifyContent:"center",padding:e.spacing.xl,gap:e.spacing.sm},actions:{flexDirection:"row",justifyContent:"flex-end",gap:e.spacing.sm}});
1
+ "use strict";import{Button,Input,KeyboardAwareScrollView,Select,Spinner,Text,useForm,useTheme}from"@webority/mobile-ui";import{useMemo,useState}from"react";import{StyleSheet,View}from"react-native";import{toSupportApiError}from"../client.js";import{describeDevice}from"../device.js";import{useCreateSupportTicket,useSupportConfig}from"../SupportProvider.js";import{validateBody,validateCategory,validateFiles,validateSubject}from"../validation.js";import{PhotoTray}from"./PhotoTray.js";import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";const TicketForm=({config:e,styles:t,onCreated:r,onCancel:o,initialDraft:a,defaultCategory:s,appVersion:i})=>{const n=useCreateSupportTicket(),listed=t=>t&&e.categories.includes(t)?t:void 0,[l,c]=useState([]),[u,d]=useState(a?.screenshots??[]),[p,g]=useState(null),[m,y]=useState(null),h=useForm({initialValues:{category:listed(a?.category)??listed(s)??"",subject:a?.subject??"",body:a?.body??""},validate:{category:t=>validateCategory(t,e),subject:t=>validateSubject(t,e),body:t=>validateBody(t,e)},onSubmit:async t=>{const o=validateFiles([...u,...l],e);if(g(o??null),!o){y(null);try{const e=await n({category:t.category,subject:t.subject.trim(),body:t.body.trim(),pageUrl:a?.pageUrl,userAgent:a?.userAgent??describeDevice(),appVersion:a?.appVersion??i,files:l,screenshots:u});r(e)}catch(e){y(toSupportApiError(e).message)}}}}),b=h.getFieldProps("category"),x=h.getFieldProps("subject"),j=h.getFieldProps("body"),S=u.length+l.length;return _jsxs(KeyboardAwareScrollView,{contentContainerStyle:t.content,safeAreaEdges:[],children:[_jsx(Text,{variant:"bodySmall",color:"secondary",children:"Tell us what you need. We reply by email and in this ticket."}),_jsx(Select,{label:"Category",placeholder:"Choose a category",required:!0,options:e.categories.map(e=>({label:e,value:e})),value:b.value||void 0,onChange:e=>b.setValue(String(e),!0),error:b.error,testID:"support-new-category"}),_jsx(Input,{label:"Subject",placeholder:"A short summary",required:!0,maxLength:e.subjectMaxLength,value:x.value,onChangeText:x.onChangeText,onBlur:x.onBlur,error:x.error,testID:"support-new-subject"}),_jsx(Input,{label:"Message",placeholder:"What happened, and what did you expect?",required:!0,multiline:!0,maxLength:e.bodyMaxLength,value:j.value,onChangeText:j.onChangeText,onBlur:j.onBlur,error:j.error,testID:"support-new-body"}),u.length>0&&_jsx(PhotoTray,{label:"Screenshot",photos:u,onChange:d,remaining:0,allowAdd:!1,maxBytes:e.maxAttachmentBytes,disabled:h.isSubmitting}),_jsx(PhotoTray,{label:"Photos",photos:l,onChange:c,remaining:e.maxAttachmentsPerMessage-S,maxBytes:e.maxAttachmentBytes,disabled:h.isSubmitting}),_jsx(Text,{variant:"caption",color:"tertiary",children:`Attach up to ${e.maxAttachmentsPerMessage} files.`}),(p||m)&&_jsx(Text,{variant:"bodySmall",color:"error",accessibilityLiveRegion:"polite",children:p??m}),_jsxs(View,{style:t.actions,children:[o&&_jsx(Button,{title:"Cancel",variant:"ghost",tone:"neutral",onPress:o,disabled:h.isSubmitting}),_jsx(Button,{title:"Send ticket",loading:h.isSubmitting,disabled:h.isSubmitting,onPress:h.submit,testID:"support-new-submit"})]})]})};export const NewSupportTicket=e=>{const t=useTheme(),r=useMemo(()=>buildStyles(t),[t]),{config:o,loading:a,error:s,reload:i}=useSupportConfig(),n=e.testID??"support-new-ticket";return _jsx(View,o?{style:r.root,testID:n,children:_jsx(TicketForm,{...e,config:o,styles:r})}:{style:r.center,testID:n,children:a?_jsx(Spinner,{accessibilityLabel:"Loading"}):_jsxs(_Fragment,{children:[_jsx(Text,{variant:"body",color:"error",align:"center",children:s?.message??"Support is not available right now."}),_jsx(Button,{title:"Try again",variant:"ghost",onPress:()=>{i()}})]})})};const buildStyles=e=>StyleSheet.create({root:{flex:1},content:{padding:e.spacing.md,gap:e.spacing.md},center:{flex:1,alignItems:"center",justifyContent:"center",padding:e.spacing.xl,gap:e.spacing.sm},actions:{flexDirection:"row",justifyContent:"flex-end",gap:e.spacing.sm}});
@@ -1 +1 @@
1
- "use strict";import{formatDateTime}from"@webority/mobile-core";import{Button,Card,Input,Spinner,StatusBadge,Text,useTheme}from"@webority/mobile-ui";import{useMemo,useState}from"react";import{ScrollView,StyleSheet,View}from"react-native";import{useSupportConfig,useSupportTicket,useSupportTimeZone}from"../SupportProvider.js";import{validateBody,validateFiles}from"../validation.js";import{AttachmentList,ImageViewer}from"./Attachments.js";import{PhotoTray}from"./PhotoTray.js";import{STATUS_TONES}from"./SupportTicketList.js";import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";const MessageBubble=({message:e,styles:t,timeZone:s,onOpenImage:i})=>{if("System"===e.authorKind)return _jsx(View,{style:t.system,testID:`support-message-${e.id}`,children:_jsx(Text,{variant:"caption",color:"tertiary",align:"center",children:`${e.body}, ${formatDateTime(e.createdDateTimeUtc,{zone:s})}`})});const a="Customer"===e.authorKind;return _jsx(View,{style:[t.bubbleRow,a?t.mineRow:t.theirsRow],testID:`support-message-${e.id}`,children:_jsxs(View,{style:[t.bubble,a?t.mine:t.theirs],children:[_jsx(Text,{variant:"label",color:a?"primary":"secondary",children:e.authorName??"-"}),_jsx(Text,{variant:"body",selectable:!0,children:e.body}),_jsx(AttachmentList,{attachments:e.attachments,onOpenImage:i}),_jsx(Text,{variant:"caption",color:"tertiary",children:formatDateTime(e.createdDateTimeUtc,{zone:s})})]})})},SATISFACTION_TEXT={Satisfied:"You said we handled this well.",Unsatisfied:"You said we did not handle this well."};export const SupportTicketDetail=({ticketId:e,testID:t="support-ticket-detail"})=>{const s=useTheme(),i=useMemo(()=>buildStyles(s),[s]),{config:a}=useSupportConfig(),n=useSupportTimeZone(),{ticket:o,loading:r,error:l,actionError:c,busy:d,reload:p,reply:m,reopen:u,rate:g}=useSupportTicket(e),[x,h]=useState(null),[y,b]=useState(""),[S,j]=useState([]),[T,f]=useState(null),[_,w]=useState(null),[v,I]=useState("");if(!o)return _jsx(View,{style:i.center,testID:t,children:r?_jsx(Spinner,{accessibilityLabel:"Loading the ticket"}):_jsxs(_Fragment,{children:[_jsx(Text,{variant:"body",color:"error",align:"center",children:l?.message??"That ticket could not be found."}),_jsx(Button,{title:"Try again",variant:"ghost",onPress:()=>{p()}})]})});const D=o.messages.filter(e=>!e.isInternal);return _jsxs(View,{style:i.root,testID:t,children:[_jsxs(ScrollView,{contentContainerStyle:i.content,keyboardShouldPersistTaps:"handled",children:[_jsxs(View,{style:i.head,children:[_jsx(Text,{variant:"h3",accessibilityRole:"header",children:o.subject}),_jsx(Text,{variant:"bodySmall",color:"secondary",children:`${o.number}, ${o.category}`}),_jsxs(View,{style:i.headRow,children:[_jsx(StatusBadge,{label:o.statusLabel,tone:STATUS_TONES[o.status]??"neutral",accessibilityLabel:`Status: ${o.statusLabel}`}),_jsx(Text,{variant:"caption",color:"tertiary",children:`Opened ${formatDateTime(o.createdDateTimeUtc,{zone:n})}`})]})]}),o.canReopen&&_jsxs(Card,{variant:"outlined",bodyStyle:i.section,children:[_jsx(Text,{variant:"bodySmall",children:`This ticket is ${o.statusLabel}. Reopen it if you still need help.`}),_jsx(Button,{title:"Reopen ticket",variant:"outline",size:"sm",loading:d,disabled:d,onPress:()=>{u()},testID:"support-reopen"})]}),o.canRate&&_jsxs(Card,{variant:"outlined",bodyStyle:i.section,testID:"support-rating",children:[_jsx(Text,{variant:"label",children:"How did we do?"}),o.satisfaction&&_jsx(Text,{variant:"bodySmall",color:"secondary",children:SATISFACTION_TEXT[o.satisfaction]}),_jsxs(View,{style:i.ratingRow,children:[_jsx(Button,{title:"Satisfied",size:"sm",leftIcon:"like",variant:"Satisfied"===_?"solid":"outline",tone:"success",accessibilityState:{selected:"Satisfied"===_},onPress:()=>w("Satisfied"),testID:"support-rate-satisfied"}),_jsx(Button,{title:"Not satisfied",size:"sm",leftIcon:"dislike",variant:"Unsatisfied"===_?"solid":"outline",tone:"error",accessibilityState:{selected:"Unsatisfied"===_},onPress:()=>w("Unsatisfied"),testID:"support-rate-unsatisfied"})]}),_&&_jsxs(_Fragment,{children:[_jsx(Input,{label:"Anything to add? (optional)",value:v,onChangeText:I,multiline:!0,maxLength:a?.satisfactionCommentMaxLength,testID:"support-rating-comment"}),_jsx(Button,{title:"Send rating",size:"sm",loading:d,disabled:d,onPress:()=>{(async()=>{_&&await g({satisfaction:_,comment:v})&&(w(null),I(""))})()},testID:"support-rating-send"})]})]}),_jsx(View,{style:i.thread,accessibilityLabel:"Conversation",children:D.map(e=>_jsx(MessageBubble,{message:e,styles:i,timeZone:n,onOpenImage:(e,t)=>h({uri:e,name:t})},e.id))}),_jsxs(View,{style:i.section,children:[_jsx(Input,{label:"Your reply",placeholder:"Write a reply to the support team",value:y,onChangeText:b,multiline:!0,maxLength:a?.bodyMaxLength,error:T??void 0,testID:"support-reply-input"}),a&&_jsx(PhotoTray,{photos:S,onChange:j,remaining:a.maxAttachmentsPerMessage-S.length,maxBytes:a.maxAttachmentBytes,disabled:d}),o.canReopen&&_jsx(Text,{variant:"caption",color:"secondary",children:"Replying reopens this ticket."}),c&&_jsx(Text,{variant:"bodySmall",color:"error",accessibilityLiveRegion:"polite",children:c.message}),_jsx(Button,{title:"Send reply",leftIcon:"send",loading:d,disabled:d,onPress:()=>{(async()=>{const e=y.trim(),t=a?validateBody(e,a)??validateFiles(S,a):e?void 0:"Write a message.";t?f(t):(f(null),await m({body:e,files:S})&&(b(""),j([])))})()},testID:"support-reply-send"})]})]}),_jsx(ImageViewer,{image:x,onClose:()=>h(null)})]})};const buildStyles=e=>StyleSheet.create({root:{flex:1},content:{padding:e.spacing.md,gap:e.spacing.md},center:{flex:1,alignItems:"center",justifyContent:"center",padding:e.spacing.xl,gap:e.spacing.sm},head:{gap:e.spacing.xxs},headRow:{flexDirection:"row",alignItems:"center",gap:e.spacing.sm,marginTop:e.spacing.xs},section:{gap:e.spacing.sm},ratingRow:{flexDirection:"row",gap:e.spacing.sm},thread:{gap:e.spacing.sm},system:{paddingHorizontal:e.spacing.lg,paddingVertical:e.spacing.xxs},bubbleRow:{flexDirection:"row"},mineRow:{justifyContent:"flex-end"},theirsRow:{justifyContent:"flex-start"},bubble:{maxWidth:"85%",borderRadius:e.radius.lg,padding:e.spacing.sm,gap:e.spacing.xxs},mine:{backgroundColor:e.colors.primaryMuted},theirs:{backgroundColor:e.colors.background.secondary}});
1
+ "use strict";import{formatDateTime}from"@webority/mobile-core";import{Button,Card,Input,KeyboardAwareScrollView,Spinner,StatusBadge,Text,useTheme}from"@webority/mobile-ui";import{useMemo,useState}from"react";import{StyleSheet,View}from"react-native";import{useSupportConfig,useSupportTicket,useSupportTimeZone}from"../SupportProvider.js";import{validateBody,validateFiles}from"../validation.js";import{AttachmentList,ImageViewer}from"./Attachments.js";import{PhotoTray}from"./PhotoTray.js";import{STATUS_TONES}from"./SupportTicketList.js";import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";const MessageBubble=({message:e,styles:t,timeZone:s,onOpenImage:i})=>{if("System"===e.authorKind)return _jsx(View,{style:t.system,testID:`support-message-${e.id}`,children:_jsx(Text,{variant:"caption",color:"tertiary",align:"center",children:`${e.body}, ${formatDateTime(e.createdDateTimeUtc,{zone:s})}`})});const a="Customer"===e.authorKind;return _jsx(View,{style:[t.bubbleRow,a?t.mineRow:t.theirsRow],testID:`support-message-${e.id}`,children:_jsxs(View,{style:[t.bubble,a?t.mine:t.theirs],children:[_jsx(Text,{variant:"label",color:a?"primary":"secondary",children:e.authorName??(a?"You":"Support team")}),_jsx(Text,{variant:"body",selectable:!0,children:e.body}),_jsx(AttachmentList,{attachments:e.attachments,onOpenImage:i}),_jsx(Text,{variant:"caption",color:"tertiary",children:formatDateTime(e.createdDateTimeUtc,{zone:s})})]})})},SATISFACTION_TEXT={Satisfied:"You told us this solved your problem.",Unsatisfied:"You told us this did not solve your problem."};export const SupportTicketDetail=({ticketId:e,testID:t="support-ticket-detail"})=>{const s=useTheme(),i=useMemo(()=>buildStyles(s),[s]),{config:a}=useSupportConfig(),o=useSupportTimeZone(),{ticket:n,loading:r,error:l,actionError:c,busy:d,reload:m,reply:p,reopen:u,rate:g}=useSupportTicket(e),[x,y]=useState(null),[h,b]=useState(""),[j,S]=useState([]),[f,T]=useState(null),[_,v]=useState(null),[w,I]=useState("");if(!n)return _jsx(View,{style:i.center,testID:t,children:r?_jsx(Spinner,{accessibilityLabel:"Loading the ticket"}):_jsxs(_Fragment,{children:[_jsx(Text,{variant:"body",color:"error",align:"center",children:l?.message??"That ticket could not be found."}),_jsx(Button,{title:"Try again",variant:"ghost",onPress:()=>{m()}})]})});const D=n.messages.filter(e=>!e.isInternal);return _jsxs(View,{style:i.root,testID:t,children:[_jsxs(KeyboardAwareScrollView,{contentContainerStyle:i.content,safeAreaEdges:[],children:[_jsxs(View,{style:i.head,children:[_jsx(Text,{variant:"h3",accessibilityRole:"header",children:n.subject}),_jsx(Text,{variant:"bodySmall",color:"secondary",children:`${n.number}, ${n.category}`}),_jsxs(View,{style:i.headRow,children:[_jsx(StatusBadge,{label:n.statusLabel,tone:STATUS_TONES[n.status]??"neutral",accessibilityLabel:`Status: ${n.statusLabel}`}),_jsx(Text,{variant:"caption",color:"tertiary",children:`Opened ${formatDateTime(n.createdDateTimeUtc,{zone:o})}`})]})]}),n.canReopen&&_jsxs(Card,{variant:"outlined",bodyStyle:i.section,children:[_jsx(Text,{variant:"bodySmall",children:`This ticket is ${n.statusLabel}. Reopen it if you still need help.`}),_jsx(Button,{title:"Reopen ticket",variant:"outline",size:"sm",loading:d,disabled:d,onPress:()=>{u()},testID:"support-reopen"})]}),n.satisfaction?_jsxs(Card,{variant:"outlined",bodyStyle:i.section,testID:"support-rating",children:[_jsx(Text,{variant:"bodySmall",accessibilityLiveRegion:"polite",children:SATISFACTION_TEXT[n.satisfaction]}),n.satisfactionComment?_jsx(Text,{variant:"bodySmall",color:"secondary",children:`Your comment: ${n.satisfactionComment}`}):null]}):n.canRate?_jsxs(Card,{variant:"outlined",bodyStyle:i.section,testID:"support-rating",children:[_jsx(Text,{variant:"label",children:"Did this solve your problem?"}),_jsxs(View,{style:i.ratingRow,children:[_jsx(Button,{title:"Yes, it is solved",size:"sm",leftIcon:"like",variant:"Satisfied"===_?"solid":"outline",tone:"success",accessibilityState:{selected:"Satisfied"===_},onPress:()=>v("Satisfied"),testID:"support-rate-satisfied"}),_jsx(Button,{title:"No, it is not",size:"sm",leftIcon:"dislike",variant:"Unsatisfied"===_?"solid":"outline",tone:"error",accessibilityState:{selected:"Unsatisfied"===_},onPress:()=>v("Unsatisfied"),testID:"support-rate-unsatisfied"})]}),_&&_jsxs(_Fragment,{children:[_jsx(Input,{label:"Anything to add? (optional)",helperText:"Your comment goes to the support team.",value:w,onChangeText:I,multiline:!0,maxLength:a?.satisfactionCommentMaxLength,testID:"support-rating-comment"}),_jsx(Button,{title:"Send answer",size:"sm",loading:d,disabled:d,onPress:()=>{(async()=>{_&&await g({satisfaction:_,comment:w})&&(v(null),I(""))})()},testID:"support-rating-send"})]})]}):null,_jsx(View,{style:i.thread,accessibilityLabel:"Conversation",children:D.map(e=>_jsx(MessageBubble,{message:e,styles:i,timeZone:o,onOpenImage:(e,t)=>y({uri:e,name:t})},e.id))}),_jsxs(View,{style:i.section,children:[_jsx(Input,{label:"Your reply",placeholder:"Write a reply to the support team",value:h,onChangeText:b,multiline:!0,maxLength:a?.bodyMaxLength,error:f??void 0,testID:"support-reply-input"}),a&&_jsx(PhotoTray,{photos:j,onChange:S,remaining:a.maxAttachmentsPerMessage-j.length,maxBytes:a.maxAttachmentBytes,disabled:d}),n.canReopen&&_jsx(Text,{variant:"caption",color:"secondary",children:"Replying reopens this ticket."}),c&&_jsx(Text,{variant:"bodySmall",color:"error",accessibilityLiveRegion:"polite",children:c.message}),_jsx(Button,{title:"Send reply",leftIcon:"send",loading:d,disabled:d,onPress:()=>{(async()=>{const e=h.trim(),t=a?validateBody(e,a)??validateFiles(j,a):e?void 0:"Write a message.";t?T(t):(T(null),await p({body:e,files:j})&&(b(""),S([])))})()},testID:"support-reply-send"})]})]}),_jsx(ImageViewer,{image:x,onClose:()=>y(null)})]})};const buildStyles=e=>StyleSheet.create({root:{flex:1},content:{padding:e.spacing.md,gap:e.spacing.md},center:{flex:1,alignItems:"center",justifyContent:"center",padding:e.spacing.xl,gap:e.spacing.sm},head:{gap:e.spacing.xxs},headRow:{flexDirection:"row",alignItems:"center",gap:e.spacing.sm,marginTop:e.spacing.xs},section:{gap:e.spacing.sm},ratingRow:{flexDirection:"row",flexWrap:"wrap",gap:e.spacing.sm},thread:{gap:e.spacing.sm},system:{paddingHorizontal:e.spacing.lg,paddingVertical:e.spacing.xxs},bubbleRow:{flexDirection:"row"},mineRow:{justifyContent:"flex-end"},theirsRow:{justifyContent:"flex-start"},bubble:{maxWidth:"85%",borderRadius:e.radius.lg,padding:e.spacing.sm,gap:e.spacing.xxs},mine:{backgroundColor:e.colors.primaryMuted},theirs:{backgroundColor:e.colors.background.secondary}});
@@ -6,6 +6,10 @@ export interface NewSupportTicketProps {
6
6
  onCancel?: () => void;
7
7
  /** Prefill, typically from the report-an-issue button: screenshot, page and device. */
8
8
  initialDraft?: SupportTicketDraft;
9
+ /** Preselected when the product's categories list it and the draft names none. */
10
+ defaultCategory?: string;
11
+ /** The app's user-visible version, recorded on the ticket when the draft carries none. */
12
+ appVersion?: string;
9
13
  testID?: string;
10
14
  }
11
15
  export declare const NewSupportTicket: React.FC<NewSupportTicketProps>;
@@ -6,6 +6,10 @@ export interface NewSupportTicketProps {
6
6
  onCancel?: () => void;
7
7
  /** Prefill, typically from the report-an-issue button: screenshot, page and device. */
8
8
  initialDraft?: SupportTicketDraft;
9
+ /** Preselected when the product's categories list it and the draft names none. */
10
+ defaultCategory?: string;
11
+ /** The app's user-visible version, recorded on the ticket when the draft carries none. */
12
+ appVersion?: string;
9
13
  testID?: string;
10
14
  }
11
15
  export declare const NewSupportTicket: React.FC<NewSupportTicketProps>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/mobile-support",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "Customer support tickets for Webority React Native apps: the support API client, hooks, ticket screens, contact card and a report-an-issue button that attaches a screenshot.",
5
5
  "keywords": [
6
6
  "react-native",
@@ -61,15 +61,6 @@
61
61
  "!**/*.spec.*",
62
62
  "!**/*.map"
63
63
  ],
64
- "scripts": {
65
- "prepack": "node ../../scripts/package-guard-pack.mjs --output-dirs lib --allow-file ../../.webority/package-allow.json",
66
- "build": "bob build && node ../../scripts/minify-lib.mjs",
67
- "clean": "rimraf lib",
68
- "lint": "biome lint ./src",
69
- "lint:fix": "biome lint --write ./src",
70
- "test": "jest",
71
- "typecheck": "tsc --noEmit"
72
- },
73
64
  "peerDependencies": {
74
65
  "@webority/mobile-core": ">=0.8.0 <0.9.0",
75
66
  "@webority/mobile-ui": ">=0.8.0 <0.9.0",
@@ -123,7 +114,15 @@
123
114
  ]
124
115
  },
125
116
  "devDependencies": {
126
- "@webority/mobile-core": "file:../core",
127
- "@webority/mobile-ui": "file:../ui"
117
+ "@webority/mobile-core": "0.8.2",
118
+ "@webority/mobile-ui": "0.8.2"
119
+ },
120
+ "scripts": {
121
+ "build": "bob build && node ../../scripts/minify-lib.mjs",
122
+ "clean": "rimraf lib",
123
+ "lint": "biome lint ./src",
124
+ "lint:fix": "biome lint --write ./src",
125
+ "test": "jest",
126
+ "typecheck": "tsc --noEmit"
128
127
  }
129
- }
128
+ }