@repzo/widget-react-native 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/lib/commonjs/api/client.js +8 -0
  2. package/lib/commonjs/api/client.js.map +1 -1
  3. package/lib/commonjs/i18n.js +14 -0
  4. package/lib/commonjs/i18n.js.map +1 -1
  5. package/lib/commonjs/locales.js +13 -0
  6. package/lib/commonjs/locales.js.map +1 -1
  7. package/lib/commonjs/state/widget-store.js +44 -4
  8. package/lib/commonjs/state/widget-store.js.map +1 -1
  9. package/lib/commonjs/types.js +3 -0
  10. package/lib/commonjs/types.js.map +1 -1
  11. package/lib/commonjs/ui/WidgetProvider.js +93 -64
  12. package/lib/commonjs/ui/WidgetProvider.js.map +1 -1
  13. package/lib/commonjs/ui/components/Gradient.js +18 -2
  14. package/lib/commonjs/ui/components/Gradient.js.map +1 -1
  15. package/lib/commonjs/ui/components/RatingCard.js +347 -0
  16. package/lib/commonjs/ui/components/RatingCard.js.map +1 -0
  17. package/lib/commonjs/ui/hooks/use-top-inset.js +22 -0
  18. package/lib/commonjs/ui/hooks/use-top-inset.js.map +1 -0
  19. package/lib/commonjs/ui/screens/chat/ChatView.js +30 -2
  20. package/lib/commonjs/ui/screens/chat/ChatView.js.map +1 -1
  21. package/lib/commonjs/ui/screens/home/HomeView.js +42 -9
  22. package/lib/commonjs/ui/screens/home/HomeView.js.map +1 -1
  23. package/lib/commonjs/ui/screens/home/HomeView.styles.js +5 -3
  24. package/lib/commonjs/ui/screens/home/HomeView.styles.js.map +1 -1
  25. package/lib/module/api/client.js +8 -0
  26. package/lib/module/api/client.js.map +1 -1
  27. package/lib/module/i18n.js +14 -0
  28. package/lib/module/i18n.js.map +1 -1
  29. package/lib/module/locales.js +13 -0
  30. package/lib/module/locales.js.map +1 -1
  31. package/lib/module/state/widget-store.js +44 -4
  32. package/lib/module/state/widget-store.js.map +1 -1
  33. package/lib/module/types.js +3 -0
  34. package/lib/module/types.js.map +1 -1
  35. package/lib/module/ui/WidgetProvider.js +96 -67
  36. package/lib/module/ui/WidgetProvider.js.map +1 -1
  37. package/lib/module/ui/components/Gradient.js +18 -2
  38. package/lib/module/ui/components/Gradient.js.map +1 -1
  39. package/lib/module/ui/components/RatingCard.js +341 -0
  40. package/lib/module/ui/components/RatingCard.js.map +1 -0
  41. package/lib/module/ui/hooks/use-top-inset.js +17 -0
  42. package/lib/module/ui/hooks/use-top-inset.js.map +1 -0
  43. package/lib/module/ui/screens/chat/ChatView.js +31 -3
  44. package/lib/module/ui/screens/chat/ChatView.js.map +1 -1
  45. package/lib/module/ui/screens/home/HomeView.js +44 -12
  46. package/lib/module/ui/screens/home/HomeView.js.map +1 -1
  47. package/lib/module/ui/screens/home/HomeView.styles.js +4 -2
  48. package/lib/module/ui/screens/home/HomeView.styles.js.map +1 -1
  49. package/lib/typescript/commonjs/api/client.d.ts +7 -1
  50. package/lib/typescript/commonjs/api/client.d.ts.map +1 -1
  51. package/lib/typescript/commonjs/i18n.d.ts +13 -0
  52. package/lib/typescript/commonjs/i18n.d.ts.map +1 -1
  53. package/lib/typescript/commonjs/locales.d.ts.map +1 -1
  54. package/lib/typescript/commonjs/state/widget-store.d.ts +18 -1
  55. package/lib/typescript/commonjs/state/widget-store.d.ts.map +1 -1
  56. package/lib/typescript/commonjs/types.d.ts +17 -0
  57. package/lib/typescript/commonjs/types.d.ts.map +1 -1
  58. package/lib/typescript/commonjs/ui/WidgetProvider.d.ts.map +1 -1
  59. package/lib/typescript/commonjs/ui/components/Gradient.d.ts.map +1 -1
  60. package/lib/typescript/commonjs/ui/components/RatingCard.d.ts +57 -0
  61. package/lib/typescript/commonjs/ui/components/RatingCard.d.ts.map +1 -0
  62. package/lib/typescript/commonjs/ui/hooks/use-top-inset.d.ts +11 -0
  63. package/lib/typescript/commonjs/ui/hooks/use-top-inset.d.ts.map +1 -0
  64. package/lib/typescript/commonjs/ui/screens/chat/ChatView.d.ts +1 -1
  65. package/lib/typescript/commonjs/ui/screens/chat/ChatView.d.ts.map +1 -1
  66. package/lib/typescript/commonjs/ui/screens/chat/ChatView.types.d.ts +11 -1
  67. package/lib/typescript/commonjs/ui/screens/chat/ChatView.types.d.ts.map +1 -1
  68. package/lib/typescript/commonjs/ui/screens/home/HomeView.d.ts +7 -0
  69. package/lib/typescript/commonjs/ui/screens/home/HomeView.d.ts.map +1 -1
  70. package/lib/typescript/commonjs/ui/screens/home/HomeView.styles.d.ts +3 -1
  71. package/lib/typescript/commonjs/ui/screens/home/HomeView.styles.d.ts.map +1 -1
  72. package/lib/typescript/module/api/client.d.ts +7 -1
  73. package/lib/typescript/module/api/client.d.ts.map +1 -1
  74. package/lib/typescript/module/i18n.d.ts +13 -0
  75. package/lib/typescript/module/i18n.d.ts.map +1 -1
  76. package/lib/typescript/module/locales.d.ts.map +1 -1
  77. package/lib/typescript/module/state/widget-store.d.ts +18 -1
  78. package/lib/typescript/module/state/widget-store.d.ts.map +1 -1
  79. package/lib/typescript/module/types.d.ts +17 -0
  80. package/lib/typescript/module/types.d.ts.map +1 -1
  81. package/lib/typescript/module/ui/WidgetProvider.d.ts.map +1 -1
  82. package/lib/typescript/module/ui/components/Gradient.d.ts.map +1 -1
  83. package/lib/typescript/module/ui/components/RatingCard.d.ts +57 -0
  84. package/lib/typescript/module/ui/components/RatingCard.d.ts.map +1 -0
  85. package/lib/typescript/module/ui/hooks/use-top-inset.d.ts +11 -0
  86. package/lib/typescript/module/ui/hooks/use-top-inset.d.ts.map +1 -0
  87. package/lib/typescript/module/ui/screens/chat/ChatView.d.ts +1 -1
  88. package/lib/typescript/module/ui/screens/chat/ChatView.d.ts.map +1 -1
  89. package/lib/typescript/module/ui/screens/chat/ChatView.types.d.ts +11 -1
  90. package/lib/typescript/module/ui/screens/chat/ChatView.types.d.ts.map +1 -1
  91. package/lib/typescript/module/ui/screens/home/HomeView.d.ts +7 -0
  92. package/lib/typescript/module/ui/screens/home/HomeView.d.ts.map +1 -1
  93. package/lib/typescript/module/ui/screens/home/HomeView.styles.d.ts +3 -1
  94. package/lib/typescript/module/ui/screens/home/HomeView.styles.d.ts.map +1 -1
  95. package/package.json +1 -1
  96. package/src/api/client.ts +13 -0
  97. package/src/i18n.ts +14 -0
  98. package/src/locales.ts +13 -0
  99. package/src/state/widget-store.ts +53 -4
  100. package/src/types.ts +19 -0
  101. package/src/ui/WidgetProvider.tsx +54 -4
  102. package/src/ui/components/Gradient.tsx +19 -2
  103. package/src/ui/components/RatingCard.tsx +355 -0
  104. package/src/ui/hooks/use-top-inset.ts +16 -0
  105. package/src/ui/screens/chat/ChatView.tsx +35 -2
  106. package/src/ui/screens/chat/ChatView.types.ts +11 -0
  107. package/src/ui/screens/home/HomeView.styles.ts +4 -2
  108. package/src/ui/screens/home/HomeView.tsx +36 -8
@@ -1,9 +1,10 @@
1
1
  import type { TeamAvatar } from '../../../types';
2
2
  /** Props and label bundle for the chat thread. */
3
3
  import type { DraftAttachment, PickResult } from '../../../attachments/pickers';
4
- import type { AgentUiAction, AttachmentSource, Message, OutgoingAttachment } from '../../../types';
4
+ import type { AgentUiAction, AttachmentSource, ConversationRatingResult, Message, OutgoingAttachment } from '../../../types';
5
5
  import type { AgentUiBlockLabels } from '../../components/AgentUiBlocks';
6
6
  import type { ImageViewerLabels } from '../../components/ImageViewer';
7
+ import type { RatingCardLabels } from '../../components/RatingCard';
7
8
  export interface ChatLabels {
8
9
  back: string;
9
10
  loading: string;
@@ -27,6 +28,7 @@ export interface ChatLabels {
27
28
  procedureSend: string;
28
29
  procedureSent: string;
29
30
  blocks: AgentUiBlockLabels;
31
+ rating: RatingCardLabels;
30
32
  attach: AttachLabels;
31
33
  viewer: ImageViewerLabels;
32
34
  }
@@ -79,6 +81,14 @@ export interface ChatViewProps {
79
81
  name?: string;
80
82
  phone?: string;
81
83
  }) => Promise<void>;
84
+ /** Answers a rating card; rejects with the server error (409 locked, 410 expired). */
85
+ onRateConversation?: (messageId: string, ratingId: string, data: {
86
+ rating: number;
87
+ reason?: string;
88
+ comment?: string;
89
+ }) => Promise<ConversationRatingResult>;
90
+ /** The widget's default language — rating reasons fall back to it. */
91
+ defaultLocale?: string;
82
92
  onLoadMore: () => void;
83
93
  onTyping: (isTyping: boolean) => void;
84
94
  onBack: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"ChatView.types.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/screens/chat/ChatView.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ChatView.types.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/screens/chat/ChatView.types.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,13 @@
12
12
  * the visitor already has; nothing here assumes a field the backend does not
13
13
  * send today.
14
14
  */
15
+ import type { WidgetConfig } from '../../../types';
15
16
  import type { HomeViewProps } from './HomeView.types';
17
+ /**
18
+ * The admin's explicit black/white toggle always wins. Older configs can omit
19
+ * it, and defaulting to dark text over a dark brand header is unreadable, so
20
+ * derive something legible from the background instead.
21
+ */
22
+ export declare function resolveHeaderTextColor(config: WidgetConfig | null, fallbackColor: string): string;
16
23
  export declare function HomeView({ config, color, visitorName, conversationCount, recentConversations, unreadByConversation, teamAgents, isOnline, offlineMessage, startConversationLabel, replyTimeLabel, allowNewConversations, showPreviousConversations, labels, onClose, onStartConversation, onViewConversations, onOpenConversation, }: HomeViewProps): import("react").JSX.Element;
17
24
  //# sourceMappingURL=HomeView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"HomeView.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/screens/home/HomeView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAqCH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAiBtD,wBAAgB,QAAQ,CAAC,EACvB,MAAM,EACN,KAAK,EACL,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,UAAU,EACV,QAAQ,EACR,cAAc,EACd,sBAAsB,EACtB,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,MAAM,EACN,OAAO,EACP,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,GACnB,EAAE,aAAa,+BAkNf"}
1
+ {"version":3,"file":"HomeView.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/screens/home/HomeView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAcH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AA2BnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAQjG;AAED,wBAAgB,QAAQ,CAAC,EACvB,MAAM,EACN,KAAK,EACL,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,UAAU,EACV,QAAQ,EACR,cAAc,EACd,sBAAsB,EACtB,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,MAAM,EACN,OAAO,EACP,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,GACnB,EAAE,aAAa,+BAmNf"}
@@ -16,6 +16,9 @@ export declare const START_CARD_LIFT = 28;
16
16
  export declare const START_CARD_MIN_HEIGHT = 76;
17
17
  export declare const HEADER_FADE_HEIGHT = 90;
18
18
  export declare const CLOSE_BUTTON_SIZE = 28;
19
+ /** The logo keeps its own shape at this height, up to the web widget's max width. */
20
+ export declare const LOGO_HEIGHT = 40;
21
+ export declare const LOGO_MAX_WIDTH = 152;
19
22
  export declare const CLOSE_ICON_SIZE = 14;
20
23
  export declare const styles: {
21
24
  contentContainer: {
@@ -47,7 +50,6 @@ export declare const styles: {
47
50
  minHeight: number;
48
51
  };
49
52
  logo: {
50
- width: number;
51
53
  height: number;
52
54
  };
53
55
  closeButton: {
@@ -1 +1 @@
1
- {"version":3,"file":"HomeView.styles.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/screens/home/HomeView.styles.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,KAAK,CAAC;AACxC,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,qBAAqB,KAAK,CAAC;AACxC,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0NjB,CAAC"}
1
+ {"version":3,"file":"HomeView.styles.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/screens/home/HomeView.styles.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,KAAK,CAAC;AACxC,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,qBAAqB,KAAK,CAAC;AACxC,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,qFAAqF;AACrF,eAAO,MAAM,WAAW,KAAK,CAAC;AAC9B,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyNjB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@repzo/widget-react-native",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Repzo chat widget for React Native \u2014 pure JavaScript, no native modules",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "./lib/commonjs/index.js",
package/src/api/client.ts CHANGED
@@ -12,6 +12,7 @@ import { SecureStorage, TOKEN_KEY } from '../storage';
12
12
  import type {
13
13
  AgentUiAction,
14
14
  Conversation,
15
+ ConversationRatingResult,
15
16
  InitResponse,
16
17
  Message,
17
18
  OutboundMessage,
@@ -285,6 +286,18 @@ export class WidgetApiClient {
285
286
  );
286
287
  }
287
288
 
289
+ /** Answers (or changes) the rating card posted after a teammate closed the chat. */
290
+ rateConversation(
291
+ conversationId: string,
292
+ ratingId: string,
293
+ data: { rating: number; reason?: string | null; comment?: string | null }
294
+ ): Promise<ConversationRatingResult> {
295
+ return this.request(
296
+ `/api/widget/conversations/${encodeURIComponent(conversationId)}/ratings/${encodeURIComponent(ratingId)}`,
297
+ { method: 'POST', body: data }
298
+ );
299
+ }
300
+
288
301
  identify(data: {
289
302
  email?: string;
290
303
  name?: string;
package/src/i18n.ts CHANGED
@@ -118,6 +118,20 @@ export const DEFAULT_LABELS = {
118
118
  messageSeen: 'Seen',
119
119
  waitingForTeammate: 'Waiting for a teammate',
120
120
  joinedConversation: 'joined the conversation',
121
+ // Conversation rating card, posted after a teammate closes the chat.
122
+ ratingQuestion: 'How would you rate this conversation?',
123
+ ratingReasonPrompt: 'What went wrong?',
124
+ ratingCommentPlaceholder: 'Tell us more (optional)',
125
+ ratingSubmit: 'Submit',
126
+ ratingThanks: 'Thanks for your feedback!',
127
+ ratingLocked: 'This rating can no longer be changed',
128
+ ratingExpired: 'This conversation can no longer be rated',
129
+ ratingFailed: "Couldn't save your rating. Please try again.",
130
+ rating1: 'Terrible',
131
+ rating2: 'Bad',
132
+ rating3: 'OK',
133
+ rating4: 'Great',
134
+ rating5: 'Amazing',
121
135
  // Forms.
122
136
  procedureSend: 'Send details',
123
137
  procedureSent: 'Sent',
package/src/locales.ts CHANGED
@@ -74,6 +74,19 @@ const ar: LabelMap = {
74
74
  messageSeen: 'تمت المشاهدة',
75
75
  waitingForTeammate: 'بانتظار أحد أعضاء الفريق',
76
76
  joinedConversation: 'انضم إلى المحادثة',
77
+ ratingQuestion: 'كيف تقيّم هذه المحادثة؟',
78
+ ratingReasonPrompt: 'ما الذي لم يكن جيداً؟',
79
+ ratingCommentPlaceholder: 'أخبرنا المزيد (اختياري)',
80
+ ratingSubmit: 'إرسال',
81
+ ratingThanks: 'شكراً على ملاحظاتك!',
82
+ ratingLocked: 'لم يعد بالإمكان تغيير هذا التقييم',
83
+ ratingExpired: 'لم يعد بالإمكان تقييم هذه المحادثة',
84
+ ratingFailed: 'تعذّر حفظ تقييمك. حاول مرة أخرى.',
85
+ rating1: 'سيئ جداً',
86
+ rating2: 'سيئ',
87
+ rating3: 'مقبول',
88
+ rating4: 'جيد',
89
+ rating5: 'ممتاز',
77
90
  procedureSend: 'إرسال التفاصيل',
78
91
  procedureSent: 'تم الإرسال',
79
92
  fieldRequired: '{field} مطلوب',
@@ -22,6 +22,7 @@ import type {
22
22
  AgentUiAction,
23
23
  BootOptions,
24
24
  Conversation,
25
+ ConversationRatingResult,
25
26
  Message,
26
27
  OutgoingAttachment,
27
28
  RepzoWidgetErrorCode,
@@ -35,7 +36,7 @@ import type {
35
36
  } from '../types';
36
37
  import { setOpenUrlHandler } from '../ui/utils/safe-url';
37
38
 
38
- const SDK_VERSION = '@repzo/widget-react-native@1.0.4';
39
+ const SDK_VERSION = '@repzo/widget-react-native@1.0.5';
39
40
 
40
41
  /** The platform this session reports — mobile sessions get the Mobile SDKs overrides. */
41
42
  function sessionPlatform(): 'ios' | 'android' | 'web' {
@@ -489,7 +490,7 @@ export class WidgetStore {
489
490
  loading: false,
490
491
  error: null,
491
492
  errorCode: null,
492
- config: result.config,
493
+ config: this.hydrateConfig(result.config),
493
494
  identityId: result.identityId,
494
495
  conversations,
495
496
  // Also seeds the launcher badge, so a reply that landed while the app
@@ -512,7 +513,7 @@ export class WidgetStore {
512
513
  },
513
514
  }));
514
515
 
515
- this.persistConfig(result.config);
516
+ this.persistConfig(this.hydrateConfig(result.config));
516
517
  this.connectRealtime(result.token);
517
518
  this.watchAppState();
518
519
  this.loadOutboundMessage();
@@ -558,13 +559,28 @@ export class WidgetStore {
558
559
  cached.platform === sessionPlatform() &&
559
560
  !this.state.config
560
561
  ) {
561
- this.setState({ config: cached.config });
562
+ this.setState({ config: this.hydrateConfig(cached.config) });
562
563
  }
563
564
  } catch {
564
565
  // Corrupt cache — the network config overwrites it shortly.
565
566
  }
566
567
  }
567
568
 
569
+ /**
570
+ * The server sends the home logo and background image as paths relative to
571
+ * Workstation (`/api/media/:id/download`), which a React Native Image can't
572
+ * load. Resolved against the boot `baseUrl` they become full links (public
573
+ * media redirects to the CDN). Absolute URLs pass through unchanged.
574
+ */
575
+ private hydrateConfig(config: WidgetConfig): WidgetConfig {
576
+ if (!config) return config;
577
+ return {
578
+ ...config,
579
+ homeLogoUrl: this.client.resolveUrl(config.homeLogoUrl),
580
+ homeBackgroundImageUrl: this.client.resolveUrl(config.homeBackgroundImageUrl),
581
+ };
582
+ }
583
+
568
584
  private persistConfig(config: WidgetConfig): void {
569
585
  if (!this.bootConfig) return;
570
586
  const entry: CachedConfig = {
@@ -1835,6 +1851,39 @@ export class WidgetStore {
1835
1851
  await this.client.identify(data);
1836
1852
  }
1837
1853
 
1854
+ /**
1855
+ * Answers a rating card in the thread on screen and mirrors the answer onto
1856
+ * its message, so the card keeps it across a re-render. Rejects with the
1857
+ * server's error (409 locked, 410 expired) for the card to show.
1858
+ */
1859
+ async rateConversation(
1860
+ messageId: string,
1861
+ ratingId: string,
1862
+ data: { rating: number; reason?: string | null; comment?: string | null }
1863
+ ): Promise<ConversationRatingResult> {
1864
+ const conversationId = this.state.activeConversationId;
1865
+ if (!conversationId) throw new RepzoWidgetError('No conversation is open', 0, 'http');
1866
+ const result = await this.client.rateConversation(conversationId, ratingId, data);
1867
+ if (this.state.activeConversationId === conversationId) {
1868
+ this.setState((current) => ({
1869
+ messages: current.messages.map((message) =>
1870
+ message.id === messageId
1871
+ ? {
1872
+ ...message,
1873
+ metadata: {
1874
+ ...message.metadata,
1875
+ rating: result.rating,
1876
+ ratingReason: result.reason,
1877
+ ratingComment: result.comment,
1878
+ },
1879
+ }
1880
+ : message
1881
+ ),
1882
+ }));
1883
+ }
1884
+ return result;
1885
+ }
1886
+
1838
1887
  /** Fire-and-forget visitor typing ping, throttled well under the 30/min cap. */
1839
1888
  notifyTyping(isTyping: boolean): void {
1840
1889
  const conversationId = this.state.activeConversationId;
package/src/types.ts CHANGED
@@ -480,6 +480,25 @@ export interface RepzoWidgetStorageAdapter {
480
480
  * - `identity_verification_failed` — `userHash` missing/wrong while the
481
481
  * channel enforces identity verification.
482
482
  */
483
+ /** A bad-rating reason on the rating card, labelled per language. */
484
+ export interface RatingReason {
485
+ id: string;
486
+ /** Locale code → label. */
487
+ labels: Record<string, string>;
488
+ }
489
+
490
+ /** The visitor's answer to a conversation rating card. */
491
+ export interface ConversationRatingResult {
492
+ id: string;
493
+ /** 1 (Terrible) … 5 (Amazing). */
494
+ rating: number;
495
+ /** Id of the reason picked after a bad rating (1–2), if any. */
496
+ reason: string | null;
497
+ comment: string | null;
498
+ /** A comment was left: the rating can't change any more. */
499
+ locked: boolean;
500
+ }
501
+
483
502
  export type RepzoWidgetErrorCode =
484
503
  | 'network'
485
504
  | 'http'
@@ -12,6 +12,7 @@ import {
12
12
  Modal,
13
13
  Platform,
14
14
  Pressable,
15
+ StatusBar,
15
16
  StyleSheet,
16
17
  Text,
17
18
  View,
@@ -35,13 +36,22 @@ import { InAppNotification } from './components/InAppNotification';
35
36
  import { OutboundMessageCard } from './components/OutboundMessageCard';
36
37
  import { WidgetPanel } from './components/WidgetPanel';
37
38
  import { useKeyboardOverlap } from './hooks/use-keyboard-overlap';
39
+ import { TopInsetContext } from './hooks/use-top-inset';
38
40
  import { useWidgetInsets } from './hooks/use-widget-insets';
39
41
  import { ChatView } from './screens/chat/ChatView';
40
42
  import { ConversationsList } from './screens/conversations/ConversationsList';
41
- import { HomeView } from './screens/home/HomeView';
43
+ import { HomeView, resolveHeaderTextColor } from './screens/home/HomeView';
42
44
  import { PreChatForm } from './screens/pre-chat/PreChatForm';
43
45
  import { globalStyles } from './styles/global';
44
- import { buildTheme, palette, radius, spacing, fontSize, withAlpha } from './styles/theme';
46
+ import {
47
+ buildTheme,
48
+ contrastingTextColor,
49
+ palette,
50
+ radius,
51
+ spacing,
52
+ fontSize,
53
+ withAlpha,
54
+ } from './styles/theme';
45
55
  import { pickRecentConversations, pickTeamAgents } from './utils/conversations';
46
56
 
47
57
  export interface RepzoWidgetProviderProps {
@@ -192,6 +202,21 @@ export function RepzoWidgetProvider({
192
202
  : null;
193
203
  const isHomeSurface = state.view === 'home';
194
204
 
205
+ // Home and chat paint their brand header under the status bar; every other
206
+ // screen (and an outbound card stacked above home) keeps a plain white top.
207
+ const outboundVisible =
208
+ !!state.outboundMessage && !blockingError && state.view !== 'chat' && state.view !== 'prechat';
209
+ const headerOwnsTopInset =
210
+ !blockingError &&
211
+ !(state.loading && !state.config) &&
212
+ !outboundVisible &&
213
+ (state.view === 'chat' || isHomeSurface);
214
+ const topBarColor = !headerOwnsTopInset
215
+ ? palette.ink
216
+ : state.view === 'chat'
217
+ ? contrastingTextColor(theme.primaryColor)
218
+ : resolveHeaderTextColor(localizedConfig, theme.primaryColor);
219
+
195
220
  const renderContent = () => {
196
221
  if (state.loading && !state.config) {
197
222
  return (
@@ -270,6 +295,7 @@ export function RepzoWidgetProvider({
270
295
  teamAvatars={teamAvatars}
271
296
  replyTimeLabel={theme.replyTimeLabel}
272
297
  locale={state.locale}
298
+ defaultLocale={state.config?.defaultLocale}
273
299
  prefillText={state.prefillText}
274
300
  offlineMessage={theme.offlineMessage}
275
301
  labels={{
@@ -295,6 +321,17 @@ export function RepzoWidgetProvider({
295
321
  procedureSend: labels.procedureSend,
296
322
  procedureSent: labels.procedureSent,
297
323
  blocks: blockLabels,
324
+ rating: {
325
+ question: labels.ratingQuestion,
326
+ reasonPrompt: labels.ratingReasonPrompt,
327
+ commentPlaceholder: labels.ratingCommentPlaceholder,
328
+ submit: labels.ratingSubmit,
329
+ thanks: labels.ratingThanks,
330
+ locked: labels.ratingLocked,
331
+ expired: labels.ratingExpired,
332
+ failed: labels.ratingFailed,
333
+ scale: [labels.rating1, labels.rating2, labels.rating3, labels.rating4, labels.rating5],
334
+ },
298
335
  attach: attachLabels,
299
336
  viewer: {
300
337
  close: labels.close,
@@ -306,6 +343,7 @@ export function RepzoWidgetProvider({
306
343
  onPickAttachments={pickAttachments}
307
344
  onSendMessage={handleSendMessage}
308
345
  onIdentifyVisitor={(data) => store.identifyVisitor(data)}
346
+ onRateConversation={(messageId, ratingId, data) => store.rateConversation(messageId, ratingId, data)}
309
347
  onLoadMore={() => store.loadMoreMessages()}
310
348
  onTyping={(isTyping) => store.notifyTyping(isTyping)}
311
349
  onBack={handleBack}
@@ -405,8 +443,19 @@ export function RepzoWidgetProvider({
405
443
  animationType="slide"
406
444
  presentationStyle={Platform.OS === 'ios' ? presentationStyle : undefined}
407
445
  onRequestClose={handleClose}
408
- statusBarTranslucent={false}>
409
- <View style={[globalStyles.screen, { paddingTop: topInset, paddingBottom: insets.bottom }]}>
446
+ // Edge to edge on every Android version, so the insets below are the
447
+ // only top spacing (a non-translucent modal used to add a second one).
448
+ statusBarTranslucent>
449
+ <StatusBar
450
+ barStyle={topBarColor === palette.white ? 'light-content' : 'dark-content'}
451
+ animated
452
+ />
453
+ <View
454
+ style={[
455
+ globalStyles.screen,
456
+ { paddingTop: headerOwnsTopInset ? 0 : topInset, paddingBottom: insets.bottom },
457
+ ]}>
458
+ <TopInsetContext.Provider value={headerOwnsTopInset ? topInset : 0}>
410
459
  <View
411
460
  onLayout={keyboard.onLayout}
412
461
  style={[globalStyles.fill, { paddingBottom: keyboard.overlap }]}>
@@ -463,6 +512,7 @@ export function RepzoWidgetProvider({
463
512
  </WidgetPanel>
464
513
  </WidgetErrorBoundary>
465
514
  </View>
515
+ </TopInsetContext.Provider>
466
516
  </View>
467
517
  </Modal>
468
518
  </>
@@ -104,6 +104,22 @@ function GradientFill({ colors, bands }: { colors: string[]; bands?: number }) {
104
104
  );
105
105
  }
106
106
 
107
+ /**
108
+ * Alpha at evenly spaced points down the fade. An eased curve instead of a
109
+ * straight line: a linear ramp shows a visible edge where it starts and goes
110
+ * opaque too late, so the brand colour reads as a band rather than melting
111
+ * into the page. Shared with the web widget's fade so both look the same.
112
+ */
113
+ const FADE_STOPS = [0, 0.04, 0.12, 0.26, 0.46, 0.68, 0.86, 0.96, 1];
114
+
115
+ function fadeAlphaAt(progress: number): number {
116
+ const scaled = Math.min(Math.max(progress, 0), 1) * (FADE_STOPS.length - 1);
117
+ const index = Math.min(Math.floor(scaled), FADE_STOPS.length - 2);
118
+ const from = FADE_STOPS[index] as number;
119
+ const to = FADE_STOPS[index + 1] as number;
120
+ return from + (to - from) * (scaled - index);
121
+ }
122
+
107
123
  /**
108
124
  * Washes the bottom of a header out into the page colour: a straight ramp from
109
125
  * fully transparent at the top to opaque at the bottom edge, the same
@@ -129,7 +145,8 @@ export function FadeOverlay({
129
145
  <View style={[styles.fadeOverlay, { height }, style]} pointerEvents="none">
130
146
  {NativeGradient ? (
131
147
  <NativeGradient
132
- colors={[withAlpha(color, 0), color]}
148
+ colors={FADE_STOPS.map((alpha) => withAlpha(color, alpha))}
149
+ locations={FADE_STOPS.map((_, index) => index / (FADE_STOPS.length - 1))}
133
150
  start={VERTICAL.start}
134
151
  end={VERTICAL.end}
135
152
  style={StyleSheet.absoluteFill}
@@ -144,7 +161,7 @@ export function FadeOverlay({
144
161
  // body colour, with no hairline where the two meet.
145
162
  <View
146
163
  key={index}
147
- style={[styles.band, { backgroundColor: withAlpha(color, (index + 1) / all.length) }]}
164
+ style={[styles.band, { backgroundColor: withAlpha(color, fadeAlphaAt((index + 1) / all.length)) }]}
148
165
  />
149
166
  ))
150
167
  )}