rn-vs-lb 1.0.65 → 1.0.66

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 (86) hide show
  1. package/components/Button/Button.stories.tsx +1 -1
  2. package/components/Button/DeleteAccountButton.stories.tsx +1 -1
  3. package/components/Button/PostButton.stories.tsx +1 -1
  4. package/components/Button/TelegramFeedbackLink.stories.tsx +1 -1
  5. package/components/Cards/BusinessIdeaCard.stories.tsx +73 -0
  6. package/components/Cards/BusinessIdeaCard.tsx +251 -0
  7. package/components/Cards/EventCard.stories.tsx +1 -1
  8. package/components/Cards/PlaceCard.stories.tsx +1 -1
  9. package/components/Cards/index.tsx +1 -0
  10. package/components/Chat/ChatItem.stories.tsx +1 -1
  11. package/components/Chat/ChatTab/ChatTabs.stories.tsx +1 -1
  12. package/components/Chat/ChatTab/SubTabButton.stories.tsx +1 -1
  13. package/components/Chat/InputMessage.stories.tsx +1 -1
  14. package/components/Chat/MessageItem/MessageItem.stories.tsx +1 -1
  15. package/components/Chat/PinnedMessagesBar/PinnedMessagesBar.stories.tsx +1 -1
  16. package/components/Gallery/AiAgentGallery.stories.tsx +1 -1
  17. package/components/Gallery/ProfileMediaGallery.stories.tsx +66 -0
  18. package/components/Gallery/ProfileMediaGallery.tsx +239 -0
  19. package/components/Gallery/ProfileMediaNavigationItem.tsx +73 -0
  20. package/components/Gallery/ProfileSelfiesGallery.pure.tsx +97 -0
  21. package/components/Gallery/ProfileSelfiesGallery.stories.tsx +86 -0
  22. package/components/Gallery/index.ts +4 -1
  23. package/components/Header/HeaderDefault.stories.tsx +1 -1
  24. package/components/Header/HeaderEdit.stories.tsx +1 -1
  25. package/components/Header/HeaderHome.stories.tsx +1 -1
  26. package/components/Header/HeaderSwitcher.stories.tsx +1 -1
  27. package/components/Header/HeaderWithImg.stories.tsx +1 -1
  28. package/components/Modals/GalleryModal.stories.tsx +1 -1
  29. package/components/Modals/GuestAiChatModal.stories.tsx +1 -1
  30. package/components/Modals/ReportModal.stories.tsx +1 -1
  31. package/components/Poll/CommentItem.stories.tsx +1 -1
  32. package/components/Poll/PollCardList.stories.tsx +1 -1
  33. package/components/Posts/EventCardList.stories.tsx +1 -1
  34. package/components/Posts/PlaceCardList.stories.tsx +1 -1
  35. package/components/Prank/HeroPrankCard.stories.tsx +47 -0
  36. package/components/Prank/HeroPrankCard.tsx +114 -0
  37. package/components/Prank/HomelessPrankPage.stories.tsx +58 -0
  38. package/components/Prank/UploadPromptCard.stories.tsx +55 -0
  39. package/components/Prank/UploadPromptCard.tsx +130 -0
  40. package/components/Prank/index.ts +5 -0
  41. package/components/Profile/ModalProfilePhoto.stories.tsx +1 -1
  42. package/components/Profile/ProfileCard/ProfileCard.stories.tsx +1 -1
  43. package/components/Profile/ProfilePhotoBanner.stories.tsx +1 -1
  44. package/components/Profile/ProfilePhotoUpload/ProfilePhotoUpload.stories.tsx +1 -1
  45. package/components/Profile/ProfileSummary/ProfileSummary.stories.tsx +52 -0
  46. package/components/Profile/ProfileSummary/ProfileSummary.tsx +188 -0
  47. package/components/Profile/ProfileTabs/UserProfileTabs.stories.tsx +1 -1
  48. package/components/Profile/index.ts +2 -0
  49. package/components/Screens/AppScreens.stories.tsx +572 -0
  50. package/components/Screens/HomeScreen.stories.tsx +159 -0
  51. package/components/Screens/LibraryScreen.stories.tsx +97 -0
  52. package/components/Settings/AppSettingsScreen.stories.tsx +134 -0
  53. package/components/Settings/AppSettingsScreen.tsx +215 -0
  54. package/components/Settings/SettingsHeader.tsx +37 -0
  55. package/components/Settings/SettingsListItem.tsx +142 -0
  56. package/components/Settings/SettingsManageAccountButton.tsx +58 -0
  57. package/components/Settings/SettingsOptionList.tsx +82 -0
  58. package/components/Settings/SettingsProfileCard.tsx +58 -0
  59. package/components/Settings/SettingsScreen.stories.tsx +66 -0
  60. package/components/Settings/SettingsScreen.tsx +129 -0
  61. package/components/Settings/SettingsSection.tsx +56 -0
  62. package/components/Settings/SettingsToggleItem.tsx +70 -0
  63. package/components/Settings/index.ts +23 -0
  64. package/components/Specialist/Hero.stories.tsx +1 -1
  65. package/components/Specialist/PortfolioCarousel.stories.tsx +1 -1
  66. package/components/Specialist/ServicesList.stories.tsx +1 -1
  67. package/components/Tooltip/DangerTooltip.stories.tsx +1 -1
  68. package/components/Tooltip/InfoTooltip.stories.tsx +1 -1
  69. package/components/Tooltip/InfoTooltipBase.stories.tsx +1 -1
  70. package/components/Tooltip/SucceedTooltip.stories.tsx +1 -1
  71. package/components/Tooltip/WarningTooltip.stories.tsx +1 -1
  72. package/components/UI/HorizontalCardSection.stories.tsx +85 -0
  73. package/components/UI/HorizontalCardSection.tsx +199 -0
  74. package/components/UI/TabBar/BottomTabBar.stories.tsx +87 -0
  75. package/components/UI/TabBar/BottomTabBar.tsx +128 -0
  76. package/components/UI/index.ts +4 -0
  77. package/components/UserCards/AiAgentHeroCard.stories.tsx +66 -0
  78. package/components/UserCards/AiAgentHeroCard.tsx +242 -0
  79. package/components/UserCards/Organizer.stories.tsx +1 -1
  80. package/components/UserCards/SpecialistCard.stories.tsx +1 -1
  81. package/components/UserCards/StoryCard.stories.tsx +1 -1
  82. package/components/UserCards/UserProfileCard.stories.tsx +1 -1
  83. package/components/UserCards/UserRow.stories.tsx +1 -1
  84. package/components/UserCards/index.ts +2 -0
  85. package/components/index.ts +2 -0
  86. package/package.json +2 -1
@@ -0,0 +1,572 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import { Meta, StoryFn } from '@storybook/react';
3
+ import { ScrollView, View, Text, StyleSheet } from 'react-native';
4
+ import { ThemeProvider, useTheme } from '../../theme';
5
+ import HeaderDefault from '../Header/HeaderDefault';
6
+ import { HeaderHome } from '../Header/HeaderHome';
7
+ import StatusFilter, { StatusOption } from '../UI/StatusFilter/StatusFilter';
8
+ import TabBar, { TabItem } from '../UI/TabBar/TabBar';
9
+ import HorizontalCardSection, { HorizontalCard } from '../UI/HorizontalCardSection';
10
+ import EventCardList from '../Posts/EventCardList';
11
+ import PlaceCardList from '../Posts/PlaceCardList';
12
+ import ProfileSummary from '../Profile/ProfileSummary/ProfileSummary';
13
+ import ProfilePhotoBanner from '../Profile/ProfilePhotoBanner';
14
+ import UserProfileTabs, { UserProfileTab } from '../Profile/ProfileTabs/UserProfileTabs';
15
+ import {
16
+ ChatItem,
17
+ ChatItemProps,
18
+ ChatTabs,
19
+ InputMessage,
20
+ MessageItem,
21
+ PinnedMessagesBar,
22
+ type MessageItemProps,
23
+ } from '../Chat';
24
+ import type { MessageDTO as TransportMessageDTO } from '../../types/message';
25
+ import Spacer from '../UI/Spacer';
26
+
27
+ const meta: Meta = {
28
+ title: 'Screens/Compositions/AppScreens',
29
+ component: () => null,
30
+ decorators: [
31
+ (Story) => (
32
+ <ThemeProvider>
33
+ <View style={styles.previewBackground}>
34
+ <Story />
35
+ </View>
36
+ </ThemeProvider>
37
+ ),
38
+ ],
39
+ };
40
+
41
+ export default meta;
42
+
43
+ type Story = StoryFn;
44
+
45
+ const ScreenSurface: React.FC<React.PropsWithChildren<{ background?: string }>> = ({ children, background = '#f5f6f8' }) => (
46
+ <View style={styles.screenWrapper}>
47
+ <View style={[styles.screenSurface, { backgroundColor: background }]}>{children}</View>
48
+ </View>
49
+ );
50
+
51
+ type EventCardData = {
52
+ imageUri: string;
53
+ date: string;
54
+ title: string;
55
+ description: string;
56
+ isInvitation: boolean;
57
+ participantsCount?: number;
58
+ maxParticipants?: number;
59
+ };
60
+
61
+ type PlaceCardData = {
62
+ imageUri: string;
63
+ title: string;
64
+ description: string;
65
+ };
66
+
67
+ const storyHighlights: HorizontalCard[] = [
68
+ {
69
+ id: '1',
70
+ title: 'City clean-up day',
71
+ image: { uri: 'https://images.unsplash.com/photo-1500530855697-b586d89ba3ee?auto=format&fit=crop&w=400&q=80' },
72
+ },
73
+ {
74
+ id: '2',
75
+ title: 'Street art workshop',
76
+ image: { uri: 'https://images.unsplash.com/photo-1489515217757-5fd1be406fef?auto=format&fit=crop&w=400&q=80' },
77
+ },
78
+ {
79
+ id: '3',
80
+ title: 'Local farmer market',
81
+ image: { uri: 'https://images.unsplash.com/photo-1504753793650-d4a2b783c15e?auto=format&fit=crop&w=400&q=80' },
82
+ },
83
+ ];
84
+
85
+ const eventFeed: EventCardData[] = [
86
+ {
87
+ imageUri: 'https://images.unsplash.com/photo-1515169067865-5387ec356754?auto=format&fit=crop&w=800&q=80',
88
+ date: 'Tomorrow · 19:00',
89
+ title: 'Community jazz evening',
90
+ description: 'Bring your instrument or just enjoy. Open jam session with local musicians.',
91
+ isInvitation: true,
92
+ participantsCount: 24,
93
+ maxParticipants: 40,
94
+ },
95
+ {
96
+ imageUri: 'https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?auto=format&fit=crop&w=800&q=80',
97
+ date: 'Sat, 12 Oct · 10:00',
98
+ title: 'Kids science fair',
99
+ description: 'Interactive experiments, robotics corner and eco-workshops for the whole family.',
100
+ isInvitation: false,
101
+ participantsCount: 75,
102
+ maxParticipants: 120,
103
+ },
104
+ ];
105
+
106
+ const placeFeed: PlaceCardData[] = [
107
+ {
108
+ imageUri: 'https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?auto=format&fit=crop&w=800&q=80',
109
+ title: 'Neighbourhood brunch spot',
110
+ description: 'Seasonal menu, rooftop seating and a cosy corner for remote work sessions.',
111
+ },
112
+ {
113
+ imageUri: 'https://images.unsplash.com/photo-1504674900247-0877df9cc836?auto=format&fit=crop&w=800&q=80',
114
+ title: 'Artisan bakery & coffee',
115
+ description: 'Fresh sourdough every morning, latte art classes on weekends and playlists curated by DJs.',
116
+ },
117
+ ];
118
+
119
+ const profileStats = [
120
+ { label: 'Followers', value: '4 812' },
121
+ { label: 'Following', value: '326' },
122
+ { label: 'Projects', value: 48 },
123
+ ];
124
+
125
+ const chatPreviewItems: ChatItemProps[] = [
126
+ {
127
+ variant: 'person',
128
+ senderFullName: 'Alex Johnson',
129
+ imgUrl: 'https://images.unsplash.com/photo-1529626455594-4ff0802cfb7e?auto=format&fit=crop&w=200&q=60',
130
+ isUserOnline: true,
131
+ lastMessage: 'See you at the community hub in 10?',
132
+ createdAt: '10:42',
133
+ unread: '+',
134
+ },
135
+ {
136
+ variant: 'group',
137
+ chatName: 'Organizers',
138
+ senderFullName: 'Nora',
139
+ imgUrl: 'https://images.unsplash.com/photo-1519340241574-2cec6aef0c01?auto=format&fit=crop&w=200&q=60',
140
+ lastMessage: 'Deck updated with logistics timeline.',
141
+ createdAt: '09:15',
142
+ unread: '+',
143
+ },
144
+ {
145
+ variant: 'bot',
146
+ chatName: 'Event summary bot',
147
+ lastMessage: 'Digest for yesterday is ready. Tap to open.',
148
+ createdAt: '08:00',
149
+ },
150
+ {
151
+ variant: 'person',
152
+ senderFullName: 'Jess Carter',
153
+ imgUrl: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=200&q=60',
154
+ isUserOnline: false,
155
+ lastMessage: 'Uploading the press photos tonight.',
156
+ createdAt: 'Yesterday',
157
+ },
158
+ ];
159
+
160
+ const getChatPreviewLabel = (item: ChatItemProps) =>
161
+ item.variant === 'person' ? item.chatName ?? item.senderFullName : item.chatName;
162
+
163
+ const conversationMessages: MessageItemProps['item'][] = [
164
+ {
165
+ _id: 'm-1',
166
+ sender: { _id: 'alex', fullName: 'Alex Johnson' },
167
+ content: 'Hey! Quick reminder that the venue opens at 18:30. Need help with setup?',
168
+ createdAt: '18:02',
169
+ },
170
+ {
171
+ _id: 'm-2',
172
+ sender: { _id: 'me', fullName: 'You' },
173
+ content: 'All good! Flyers are printed and the volunteer brief is in the shared folder.',
174
+ createdAt: '18:05',
175
+ isEdited: true,
176
+ },
177
+ {
178
+ _id: 'm-3',
179
+ sender: { _id: 'alex', fullName: 'Alex Johnson' },
180
+ content: 'Legend. Dropping the floor plan here 👉 https://example.com/layout',
181
+ createdAt: '18:06',
182
+ },
183
+ {
184
+ _id: 'm-4',
185
+ sender: { _id: 'alex', fullName: 'Alex Johnson' },
186
+ images: ['https://images.unsplash.com/photo-1556740749-887f6717d7e4?auto=format&fit=crop&w=600&q=80'],
187
+ content: 'Stage lighting looks like this right now.',
188
+ createdAt: '18:07',
189
+ },
190
+ {
191
+ _id: 'm-5',
192
+ sender: { _id: 'me', fullName: 'You' },
193
+ content: 'Perfect, thanks! I will pin the checklist so everyone sees it.',
194
+ createdAt: '18:08',
195
+ replyTo: {
196
+ _id: 'm-1',
197
+ sender: { _id: 'alex', fullName: 'Alex Johnson' },
198
+ content: 'Hey! Quick reminder that the venue opens at 18:30. Need help with setup?',
199
+ },
200
+ },
201
+ ];
202
+
203
+ const pinnedConversationMessages: TransportMessageDTO[] = conversationMessages.slice(0, 3).map((message) => {
204
+ const mapped: TransportMessageDTO = {
205
+ _id: message._id,
206
+ sender: { _id: message.sender._id },
207
+ content: message.content ?? '',
208
+ createdAt: message.createdAt ?? '',
209
+ readBy: ['me'],
210
+ isEdited: !!message.isEdited,
211
+ };
212
+
213
+ if (message.images?.length) {
214
+ mapped.images = message.images;
215
+ }
216
+
217
+ if (message.attachments?.length) {
218
+ mapped.attachments = message.attachments;
219
+ }
220
+
221
+ if (message.replyTo) {
222
+ mapped.replyTo = {
223
+ _id: message.replyTo._id,
224
+ sender: { _id: message.replyTo.sender?._id ?? 'unknown' },
225
+ content: message.replyTo.content ?? '',
226
+ createdAt: '',
227
+ readBy: ['me'],
228
+ isEdited: false,
229
+ images: message.replyTo.images,
230
+ attachments: message.replyTo.attachments,
231
+ };
232
+ }
233
+
234
+ return mapped;
235
+ });
236
+
237
+ const useScreenPadding = () => {
238
+ const { sizes } = useTheme();
239
+ return useMemo(() => ({ paddingHorizontal: sizes.md, paddingBottom: sizes.lg }), [sizes]);
240
+ };
241
+
242
+ export const HomeFeed: Story = () => {
243
+ const [activeTab, setActiveTab] = useState(0);
244
+ const [selectedStatus, setSelectedStatus] = useState<StatusOption['key']>('all');
245
+ const padding = useScreenPadding();
246
+
247
+ const tabs: TabItem[] = [
248
+ { key: 'feed', label: 'Events', icon: 'event' },
249
+ { key: 'places', label: 'Places', icon: 'place' },
250
+ { key: 'news', label: 'News', icon: 'article' },
251
+ { key: 'tasks', label: 'Tasks', icon: 'check-circle' },
252
+ ];
253
+
254
+ const statusOptions: StatusOption[] = [
255
+ { key: 'all', label: 'All' },
256
+ { key: 'today', label: 'Today' },
257
+ { key: 'weekend', label: 'Weekend' },
258
+ { key: 'foryou', label: 'For you' },
259
+ ];
260
+
261
+ return (
262
+ <ScreenSurface>
263
+ <ScrollView
264
+ showsVerticalScrollIndicator={false}
265
+ contentContainerStyle={[styles.scrollContent, padding]}
266
+ >
267
+ <Spacer size="sm" />
268
+ <HeaderHome
269
+ logo={<Text style={styles.logo}>CityLife</Text>}
270
+ onPressCity={() => console.log('city')}
271
+ onPressMap={() => console.log('map')}
272
+ onPress={() => console.log('filters')}
273
+ onPressSpecialists={() => console.log('specialists')}
274
+ specialistsActive={activeTab === 3}
275
+ />
276
+
277
+ <StatusFilter
278
+ selectedStatus={selectedStatus}
279
+ onChangeStatus={setSelectedStatus}
280
+ options={statusOptions}
281
+ type="rounded"
282
+ />
283
+
284
+ <HorizontalCardSection
285
+ title="Highlights nearby"
286
+ cards={storyHighlights}
287
+ onPressSeeAll={() => console.log('see all highlights')}
288
+ />
289
+
290
+ <TabBar activeTabIndex={activeTab} onChangeTab={setActiveTab} tabs={tabs} />
291
+
292
+ <View style={styles.feedSection}>
293
+ {activeTab === 1
294
+ ? placeFeed.map((card, index) => (
295
+ <PlaceCardList
296
+ key={`place-${index}`}
297
+ imageUri={card.imageUri}
298
+ title={card.title}
299
+ description={card.description}
300
+ />
301
+ ))
302
+ : eventFeed.map((card, index) => (
303
+ <EventCardList
304
+ key={`event-${index}`}
305
+ imageUri={card.imageUri}
306
+ date={card.date}
307
+ title={card.title}
308
+ description={card.description}
309
+ isInvitation={card.isInvitation}
310
+ participantsCount={card.participantsCount}
311
+ maxParticipants={card.maxParticipants}
312
+ />
313
+ ))}
314
+ </View>
315
+ </ScrollView>
316
+ </ScreenSurface>
317
+ );
318
+ };
319
+
320
+ export const ProfilePublic: Story = () => {
321
+ const [activeTab, setActiveTab] = useState<UserProfileTab>('events');
322
+ const padding = useScreenPadding();
323
+
324
+ return (
325
+ <ScreenSurface>
326
+ <ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={[styles.scrollContent, padding]}>
327
+ <ProfileSummary
328
+ avatarUri="https://images.unsplash.com/photo-1524504388940-b1c1722653e1?auto=format&fit=crop&w=200&q=80"
329
+ name="Maria Ortega"
330
+ username="@maria.designs"
331
+ stats={profileStats}
332
+ website="maria.designs/community"
333
+ showAddButton={false}
334
+ onAvatarPress={() => console.log('open avatar')}
335
+ onEditPress={() => console.log('edit profile')}
336
+ />
337
+
338
+ <UserProfileTabs activeTab={activeTab} onChangeTab={setActiveTab} />
339
+
340
+ <View style={styles.feedSection}>
341
+ {activeTab === 'events'
342
+ ? eventFeed.map((card, index) => (
343
+ <EventCardList
344
+ key={`profile-event-${index}`}
345
+ imageUri={card.imageUri}
346
+ date={card.date}
347
+ title={card.title}
348
+ description={card.description}
349
+ isInvitation={false}
350
+ maxParticipants={card.maxParticipants}
351
+ participantsCount={card.participantsCount}
352
+ />
353
+ ))
354
+ : placeFeed.map((card, index) => (
355
+ <PlaceCardList
356
+ key={`profile-place-${index}`}
357
+ imageUri={card.imageUri}
358
+ title={card.title}
359
+ description={card.description}
360
+ />
361
+ ))}
362
+ </View>
363
+ </ScrollView>
364
+ </ScreenSurface>
365
+ );
366
+ };
367
+
368
+ export const ProfileOwner: Story = () => {
369
+ const [activeTab, setActiveTab] = useState<UserProfileTab>('events');
370
+ const padding = useScreenPadding();
371
+
372
+ return (
373
+ <ScreenSurface>
374
+ <ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={[styles.scrollContent, padding]}>
375
+ <ProfilePhotoBanner
376
+ message="Add a cover photo so neighbours recognise your projects faster."
377
+ buttonText="Upload cover"
378
+ onAddPhoto={() => console.log('add photo')}
379
+ onClose={() => console.log('dismiss banner')}
380
+ />
381
+
382
+ <ProfileSummary
383
+ avatarUri="https://images.unsplash.com/photo-1544723795-3fb6469f5b39?auto=format&fit=crop&w=200&q=80"
384
+ name="You"
385
+ username="@city.creator"
386
+ stats={profileStats}
387
+ onAvatarPress={() => console.log('change avatar')}
388
+ onAddPress={() => console.log('add avatar')}
389
+ onEditPress={() => console.log('edit profile')}
390
+ editLabel="Edit profile"
391
+ />
392
+
393
+ <UserProfileTabs activeTab={activeTab} onChangeTab={setActiveTab} />
394
+
395
+ <View style={styles.feedSection}>
396
+ {activeTab === 'events'
397
+ ? eventFeed.map((card, index) => (
398
+ <EventCardList
399
+ key={`owner-event-${index}`}
400
+ imageUri={card.imageUri}
401
+ date={card.date}
402
+ title={card.title}
403
+ description={card.description}
404
+ isInvitation={index === 0}
405
+ maxParticipants={card.maxParticipants}
406
+ participantsCount={card.participantsCount}
407
+ />
408
+ ))
409
+ : placeFeed.map((card, index) => (
410
+ <PlaceCardList
411
+ key={`owner-place-${index}`}
412
+ imageUri={card.imageUri}
413
+ title={card.title}
414
+ description={card.description}
415
+ />
416
+ ))}
417
+ </View>
418
+ </ScrollView>
419
+ </ScreenSurface>
420
+ );
421
+ };
422
+
423
+ export const ChatList: Story = () => {
424
+ const [activeTab, setActiveTab] = useState<'person' | 'group' | 'bot'>('person');
425
+ const [botSubTab, setBotSubTab] = useState<'my' | 'others'>('my');
426
+ const padding = useScreenPadding();
427
+
428
+ return (
429
+ <ScreenSurface>
430
+ <ScrollView
431
+ showsVerticalScrollIndicator={false}
432
+ contentContainerStyle={[styles.scrollContent, padding]}
433
+ >
434
+ <HeaderDefault title="Messages" onBackPress={() => console.log('back')} />
435
+
436
+ <ChatTabs
437
+ activeTab={activeTab}
438
+ onChangeTab={setActiveTab}
439
+ hasUnreadPrivate
440
+ hasUnreadGroup
441
+ hasUnreadBot
442
+ showBotSubTabs
443
+ activeBotSubTab={botSubTab}
444
+ onChangeBotSubTab={setBotSubTab}
445
+ />
446
+
447
+ <View style={[styles.feedSection, { paddingTop: 8 }]}>
448
+ {chatPreviewItems
449
+ .filter((item) =>
450
+ activeTab === 'bot'
451
+ ? item.variant === 'bot'
452
+ : activeTab === 'group'
453
+ ? item.variant === 'group'
454
+ : item.variant !== 'bot'
455
+ )
456
+ .map((item, index) => (
457
+ <ChatItem
458
+ key={`${item.variant}-${index}`}
459
+ {...item}
460
+ onPress={() => console.log('open chat', getChatPreviewLabel(item))}
461
+ />
462
+ ))}
463
+ </View>
464
+ </ScrollView>
465
+ </ScreenSurface>
466
+ );
467
+ };
468
+
469
+ export const Conversation: Story = () => {
470
+ const [messageValue, setMessageValue] = useState('');
471
+ const padding = useScreenPadding();
472
+
473
+ return (
474
+ <ScreenSurface background="#eef1f6">
475
+ <View style={[styles.conversationContainer, padding]}>
476
+ <HeaderDefault title="Alex Johnson" onBackPress={() => console.log('back')} />
477
+
478
+ <PinnedMessagesBar
479
+ pinnedMessages={pinnedConversationMessages}
480
+ onUnpin={(id) => console.log('unpin', id)}
481
+ onPress={(id) => console.log('open pinned message', id)}
482
+ isGroupChat={false}
483
+ myId="me"
484
+ lastReadMessageIdOpponent={null}
485
+ fixedItemHeight={84}
486
+ />
487
+
488
+ <ScrollView
489
+ style={styles.messageList}
490
+ contentContainerStyle={styles.messageListContent}
491
+ showsVerticalScrollIndicator={false}
492
+ >
493
+ <Spacer size="sm" />
494
+ {conversationMessages.map((item) => (
495
+ <MessageItem
496
+ key={item._id}
497
+ item={item}
498
+ myId="me"
499
+ isGroupChat={false}
500
+ isReadByOpponent={item.sender._id === 'me'}
501
+ linkHandler={(url) => console.log('open link', url)}
502
+ timeText={item.createdAt}
503
+ />
504
+ ))}
505
+ </ScrollView>
506
+
507
+ <InputMessage
508
+ value={messageValue}
509
+ onChange={setMessageValue}
510
+ placeholder="Write a message"
511
+ editingLabel="Editing"
512
+ onSubmit={async () => {
513
+ console.log('send message', messageValue);
514
+ setMessageValue('');
515
+ return true;
516
+ }}
517
+ onAttachPress={async () => []}
518
+ />
519
+ </View>
520
+ </ScreenSurface>
521
+ );
522
+ };
523
+
524
+ const styles = StyleSheet.create({
525
+ previewBackground: {
526
+ flex: 1,
527
+ alignItems: 'center',
528
+ justifyContent: 'center',
529
+ backgroundColor: '#e5e7eb',
530
+ paddingVertical: 32,
531
+ },
532
+ screenWrapper: {
533
+ width: '100%',
534
+ maxWidth: 420,
535
+ paddingHorizontal: 16,
536
+ },
537
+ screenSurface: {
538
+ width: '100%',
539
+ borderRadius: 28,
540
+ overflow: 'hidden',
541
+ borderWidth: 1,
542
+ borderColor: 'rgba(0,0,0,0.08)',
543
+ minHeight: 720,
544
+ },
545
+ scrollContent: {
546
+ paddingTop: 16,
547
+ gap: 16,
548
+ },
549
+ logo: {
550
+ fontSize: 24,
551
+ fontWeight: '700',
552
+ letterSpacing: 1,
553
+ },
554
+ feedSection: {
555
+ gap: 12,
556
+ paddingBottom: 32,
557
+ },
558
+ conversationContainer: {
559
+ flex: 1,
560
+ backgroundColor: '#ffffff',
561
+ gap: 12,
562
+ },
563
+ messageList: {
564
+ flex: 1,
565
+ },
566
+ messageListContent: {
567
+ paddingHorizontal: 8,
568
+ paddingBottom: 12,
569
+ gap: 12,
570
+ },
571
+ });
572
+