rn-vs-lb 1.0.63 → 1.0.65
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/components/Button/DeleteAccountButton.stories.tsx +12 -0
- package/components/Button/DeleteAccountButton.tsx +28 -8
- package/components/Button/TelegramFeedbackLink.stories.tsx +6 -0
- package/components/Button/TelegramFeedbackLink.tsx +12 -4
- package/components/Cards/EventCard.stories.tsx +3 -0
- package/components/Cards/EventCard.tsx +9 -2
- package/components/Chat/InputMessage.stories.tsx +11 -0
- package/components/Chat/InputMessage.tsx +5 -3
- package/components/Header/HeaderWithImg.stories.tsx +9 -0
- package/components/Header/HeaderWithImg.tsx +27 -7
- package/components/Modals/GuestAiChatModal.stories.tsx +11 -3
- package/components/Modals/GuestAiChatModal.tsx +9 -3
- package/components/Modals/ReportModal.stories.tsx +34 -1
- package/components/Modals/ReportModal.tsx +23 -24
- package/components/Poll/PollCardList.stories.tsx +4 -0
- package/components/Poll/PollCardList.tsx +4 -2
- package/components/Profile/ProfilePhotoBanner.stories.tsx +10 -1
- package/components/Profile/ProfilePhotoBanner.tsx +5 -3
- package/components/Specialist/Hero.stories.tsx +1 -0
- package/components/Specialist/Hero.tsx +3 -1
- package/components/Specialist/ServicesList.stories.tsx +1 -0
- package/components/Specialist/ServicesList.tsx +4 -3
- package/components/UI/DeletedState.stories.tsx +6 -1
- package/components/UI/DeletedState.tsx +12 -3
- package/components/UI/DescriptionMore.stories.tsx +2 -0
- package/components/UI/DescriptionMore.tsx +13 -3
- package/components/UI/EmptyState.stories.tsx +4 -1
- package/components/UI/EmptyState.tsx +3 -2
- package/components/UI/NoAuth.stories.tsx +3 -0
- package/components/UI/NoAuth.tsx +7 -6
- package/components/UI/ParticipantItem.stories.tsx +21 -0
- package/components/UI/ParticipantItem.tsx +30 -6
- package/components/UI/StepProgress.tsx +1 -1
- package/components/UI/ThemeSwitcher.stories.tsx +5 -1
- package/components/UI/ThemeSwitcher.tsx +7 -2
- package/components/UI/UpdateRequiredView.stories.tsx +2 -0
- package/components/UI/UpdateRequiredView.tsx +3 -2
- package/components/UserCards/Organazer.tsx +3 -2
- package/components/UserCards/Organizer.stories.tsx +4 -0
- package/components/UserCards/SpecialistCard.stories.tsx +2 -0
- package/components/UserCards/SpecialistCard.tsx +3 -2
- package/package.json +1 -1
|
@@ -29,6 +29,7 @@ Default.args = {
|
|
|
29
29
|
creatorAvatar: 'https://i.pravatar.cc/150?img=11',
|
|
30
30
|
votesCount: 42,
|
|
31
31
|
createdAt: '2 days ago',
|
|
32
|
+
votesLabel: 'votes',
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
export const WithLongQuestion = Template.bind({});
|
|
@@ -39,6 +40,7 @@ WithLongQuestion.args = {
|
|
|
39
40
|
creatorAvatar: 'https://i.pravatar.cc/150?img=5',
|
|
40
41
|
votesCount: 128,
|
|
41
42
|
createdAt: '5 hours ago',
|
|
43
|
+
votesLabel: 'votes',
|
|
42
44
|
};
|
|
43
45
|
|
|
44
46
|
export const WithoutDate = Template.bind({});
|
|
@@ -48,6 +50,7 @@ WithoutDate.args = {
|
|
|
48
50
|
creatorAvatar: 'https://i.pravatar.cc/150?img=24',
|
|
49
51
|
votesCount: 8,
|
|
50
52
|
createdAt: null,
|
|
53
|
+
votesLabel: 'votes',
|
|
51
54
|
};
|
|
52
55
|
|
|
53
56
|
export const MinimalInfo = Template.bind({});
|
|
@@ -57,4 +60,5 @@ MinimalInfo.args = {
|
|
|
57
60
|
creatorAvatar: 'https://i.pravatar.cc/150?img=36',
|
|
58
61
|
votesCount: 230,
|
|
59
62
|
createdAt: 'just now',
|
|
63
|
+
votesLabel: 'votes',
|
|
60
64
|
};
|
|
@@ -9,6 +9,7 @@ interface PollCardProps {
|
|
|
9
9
|
votesCount: number;
|
|
10
10
|
onPress?: () => void;
|
|
11
11
|
createdAt: string | null;
|
|
12
|
+
votesLabel: string;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
const PollCardList: React.FC<PollCardProps> = ({
|
|
@@ -17,7 +18,8 @@ const PollCardList: React.FC<PollCardProps> = ({
|
|
|
17
18
|
creatorAvatar,
|
|
18
19
|
votesCount,
|
|
19
20
|
onPress,
|
|
20
|
-
createdAt
|
|
21
|
+
createdAt,
|
|
22
|
+
votesLabel,
|
|
21
23
|
}) => {
|
|
22
24
|
const { globalStyleSheet, commonStyles, typography } = useTheme();
|
|
23
25
|
const styles = getStyles({ commonStyles });
|
|
@@ -33,7 +35,7 @@ const PollCardList: React.FC<PollCardProps> = ({
|
|
|
33
35
|
</View>
|
|
34
36
|
<Text style={typography.bodyXs}>{creatorName}</Text>
|
|
35
37
|
<View style={globalStyleSheet.flexRowCenterBetween}>
|
|
36
|
-
<Text style={typography.bodyXs}>{votesCount}
|
|
38
|
+
<Text style={typography.bodyXs}>{votesCount} {votesLabel}</Text>
|
|
37
39
|
<Text style={typography.bodyXs}>{createdAt}</Text>
|
|
38
40
|
</View>
|
|
39
41
|
</View>
|
|
@@ -34,11 +34,18 @@ const closeHandler = () => {
|
|
|
34
34
|
|
|
35
35
|
export const Default = Template.bind({});
|
|
36
36
|
Default.args = {
|
|
37
|
+
message: 'Upload a photo — it will help others recognize and trust you.',
|
|
38
|
+
buttonText: 'Add Photo',
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
export const InsideScrollableList: StoryFn = () => (
|
|
40
42
|
<ScrollView contentContainerStyle={{ gap: 12, padding: 16 }}>
|
|
41
|
-
<ProfilePhotoBanner
|
|
43
|
+
<ProfilePhotoBanner
|
|
44
|
+
onAddPhoto={addPhotoHandler}
|
|
45
|
+
onClose={closeHandler}
|
|
46
|
+
message="Upload a photo — it will help others recognize and trust you."
|
|
47
|
+
buttonText="Add Photo"
|
|
48
|
+
/>
|
|
42
49
|
<View style={{ height: 150, backgroundColor: '#f0f0f0', borderRadius: 12 }} />
|
|
43
50
|
<View style={{ height: 150, backgroundColor: '#f5f5f5', borderRadius: 12 }} />
|
|
44
51
|
<View style={{ height: 150, backgroundColor: '#fafafa', borderRadius: 12 }} />
|
|
@@ -61,6 +68,8 @@ export const DismissibleBehaviour: StoryFn = () => {
|
|
|
61
68
|
closeHandler();
|
|
62
69
|
setVisible(false);
|
|
63
70
|
}}
|
|
71
|
+
message="Upload a photo — it will help others recognize and trust you."
|
|
72
|
+
buttonText="Add Photo"
|
|
64
73
|
/>
|
|
65
74
|
)}
|
|
66
75
|
<View style={{ height: 160, backgroundColor: '#d9ecff', borderRadius: 16 }} />
|
|
@@ -7,21 +7,23 @@ import Button from '../Button/Button';
|
|
|
7
7
|
interface Props {
|
|
8
8
|
onAddPhoto: () => void;
|
|
9
9
|
onClose: () => void;
|
|
10
|
+
message: string;
|
|
11
|
+
buttonText: string;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
const ProfilePhotoBanner: React.FC<Props> = ({ onAddPhoto, onClose }) => {
|
|
14
|
+
const ProfilePhotoBanner: React.FC<Props> = ({ onAddPhoto, onClose, message, buttonText }) => {
|
|
13
15
|
const { theme, typography } = useTheme();
|
|
14
16
|
const styles = getStyles({ theme });
|
|
15
17
|
|
|
16
18
|
return (
|
|
17
19
|
<View style={styles.container}>
|
|
18
20
|
<View style={styles.row}>
|
|
19
|
-
<Text style={[typography.body, styles.text]}>
|
|
21
|
+
<Text style={[typography.body, styles.text]}>{message}</Text>
|
|
20
22
|
<TouchableOpacity onPress={onClose} style={styles.closeButton}>
|
|
21
23
|
<Ionicons name="close" size={20} color={theme.text} />
|
|
22
24
|
</TouchableOpacity>
|
|
23
25
|
</View>
|
|
24
|
-
<Button title=
|
|
26
|
+
<Button title={buttonText} onPress={onAddPhoto} />
|
|
25
27
|
</View>
|
|
26
28
|
);
|
|
27
29
|
};
|
|
@@ -15,6 +15,7 @@ export type HeroProps = {
|
|
|
15
15
|
onMessage?: () => void;
|
|
16
16
|
onPressMap?: () => void;
|
|
17
17
|
socials?: React.ReactNode; // сюда можно передать <SocialIconsRow .../>
|
|
18
|
+
mapLabel: string;
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
const Hero: React.FC<HeroProps> = ({
|
|
@@ -29,6 +30,7 @@ const Hero: React.FC<HeroProps> = ({
|
|
|
29
30
|
onMessage,
|
|
30
31
|
onPressMap,
|
|
31
32
|
socials,
|
|
33
|
+
mapLabel,
|
|
32
34
|
}) => {
|
|
33
35
|
const { theme, globalStyleSheet, typography } = useTheme();
|
|
34
36
|
const s = getStyles({ theme, globalStyleSheet });
|
|
@@ -67,7 +69,7 @@ const Hero: React.FC<HeroProps> = ({
|
|
|
67
69
|
|
|
68
70
|
{showOnMap && (
|
|
69
71
|
<TouchableOpacity style={[globalStyleSheet.flexRowCenterEnd, { marginTop: 6 }]} onPress={onPressMap} activeOpacity={0.8}>
|
|
70
|
-
<Text style={{ color: theme.primary, fontWeight: '600' }}>
|
|
72
|
+
<Text style={{ color: theme.primary, fontWeight: '600' }}>{mapLabel}</Text>
|
|
71
73
|
<Ionicons name="chevron-forward" size={16} color={theme.primary} />
|
|
72
74
|
</TouchableOpacity>
|
|
73
75
|
)}
|
|
@@ -14,15 +14,16 @@ export type ServiceItem = {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
export type ServicesListProps = {
|
|
17
|
-
title
|
|
17
|
+
title: string;
|
|
18
18
|
total?: number; // для счетчика справа от заголовка
|
|
19
19
|
services: ServiceItem[];
|
|
20
20
|
onPressService?: (item: ServiceItem, index: number) => void;
|
|
21
21
|
onPressMore?: () => void;
|
|
22
22
|
style?: ViewStyle;
|
|
23
|
+
moreLabel: string;
|
|
23
24
|
};
|
|
24
25
|
|
|
25
|
-
const ServicesList: React.FC<ServicesListProps> = ({ title
|
|
26
|
+
const ServicesList: React.FC<ServicesListProps> = ({ title, total, services, onPressService, onPressMore, style, moreLabel }) => {
|
|
26
27
|
const { theme } = useTheme();
|
|
27
28
|
const s = getStyles(theme);
|
|
28
29
|
|
|
@@ -36,7 +37,7 @@ const ServicesList: React.FC<ServicesListProps> = ({ title = 'Services', total,
|
|
|
36
37
|
</Text>
|
|
37
38
|
{!!onPressMore && (
|
|
38
39
|
<TouchableOpacity onPress={onPressMore}>
|
|
39
|
-
<Text style={s.moreLink}>
|
|
40
|
+
<Text style={s.moreLink}>{moreLabel}</Text>
|
|
40
41
|
</TouchableOpacity>
|
|
41
42
|
)}
|
|
42
43
|
</View>
|
|
@@ -16,9 +16,14 @@ const Template: StoryFn<DeletedStateProps> = (args) => <DeletedState {...args} /
|
|
|
16
16
|
const goBackHandler = () => {};
|
|
17
17
|
|
|
18
18
|
export const WithoutAction = Template.bind({});
|
|
19
|
-
WithoutAction.args = {
|
|
19
|
+
WithoutAction.args = {
|
|
20
|
+
title: 'Deleted',
|
|
21
|
+
buttonText: 'Go back',
|
|
22
|
+
};
|
|
20
23
|
|
|
21
24
|
export const WithGoBack = Template.bind({});
|
|
22
25
|
WithGoBack.args = {
|
|
23
26
|
goBack: goBackHandler,
|
|
27
|
+
title: 'Deleted',
|
|
28
|
+
buttonText: 'Go back',
|
|
24
29
|
};
|
|
@@ -7,9 +7,11 @@ import { Button } from '../Button';
|
|
|
7
7
|
|
|
8
8
|
type Props = {
|
|
9
9
|
goBack?: () => void;
|
|
10
|
+
title: string;
|
|
11
|
+
buttonText: string;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
const DeletedState: FC<Props> = ({ goBack }) => {
|
|
14
|
+
const DeletedState: FC<Props> = ({ goBack, title, buttonText }) => {
|
|
13
15
|
const { theme, commonStyles, typography } = useTheme();
|
|
14
16
|
const styles = getStyles(theme);
|
|
15
17
|
|
|
@@ -17,9 +19,16 @@ const DeletedState: FC<Props> = ({ goBack }) => {
|
|
|
17
19
|
<View style={[commonStyles.container, styles.container]}>
|
|
18
20
|
<Ionicons name="file-tray-outline" size={50} color={theme.placeholder} />
|
|
19
21
|
<Spacer size='xxs' />
|
|
20
|
-
<Text style={[typography.titleH6Regular, { color: theme.placeholder }]}>
|
|
22
|
+
<Text style={[typography.titleH6Regular, { color: theme.placeholder }]}>{title}</Text>
|
|
21
23
|
<Spacer size='lg' />
|
|
22
|
-
{goBack &&
|
|
24
|
+
{goBack && (
|
|
25
|
+
<Button
|
|
26
|
+
onPress={goBack}
|
|
27
|
+
type='gray-outline'
|
|
28
|
+
title={buttonText}
|
|
29
|
+
textStyle={[typography.body, { color: theme.greyText }]}
|
|
30
|
+
/>
|
|
31
|
+
)}
|
|
23
32
|
</View>
|
|
24
33
|
);
|
|
25
34
|
};
|
|
@@ -15,6 +15,8 @@ const meta = {
|
|
|
15
15
|
'Passionate about natural looks, skin preparation, and color theory. ' +
|
|
16
16
|
'Open for travel and on-location work; kit is fully sanitized and cruelty-free.',
|
|
17
17
|
expanded: false,
|
|
18
|
+
expandedLabel: 'Less',
|
|
19
|
+
collapsedLabel: 'More details',
|
|
18
20
|
},
|
|
19
21
|
} satisfies Meta<typeof DescriptionSection>;
|
|
20
22
|
|
|
@@ -4,14 +4,24 @@ import { useTheme, ThemeType } from '../../theme';
|
|
|
4
4
|
import CardContainer from './CardContainer';
|
|
5
5
|
|
|
6
6
|
export type DescriptionSectionProps = {
|
|
7
|
-
title
|
|
7
|
+
title: string;
|
|
8
8
|
text: string;
|
|
9
9
|
expanded: boolean;
|
|
10
10
|
onToggle: () => void;
|
|
11
11
|
style?: ViewStyle;
|
|
12
|
+
expandedLabel: string;
|
|
13
|
+
collapsedLabel: string;
|
|
12
14
|
};
|
|
13
15
|
|
|
14
|
-
const DescriptionSection: React.FC<DescriptionSectionProps> = ({
|
|
16
|
+
const DescriptionSection: React.FC<DescriptionSectionProps> = ({
|
|
17
|
+
title,
|
|
18
|
+
text,
|
|
19
|
+
expanded,
|
|
20
|
+
onToggle,
|
|
21
|
+
style,
|
|
22
|
+
expandedLabel,
|
|
23
|
+
collapsedLabel,
|
|
24
|
+
}) => {
|
|
15
25
|
const { theme, typography } = useTheme();
|
|
16
26
|
const s = getStyles(theme);
|
|
17
27
|
|
|
@@ -23,7 +33,7 @@ const DescriptionSection: React.FC<DescriptionSectionProps> = ({ title = 'Descri
|
|
|
23
33
|
{text}
|
|
24
34
|
</Text>
|
|
25
35
|
<TouchableOpacity onPress={onToggle}>
|
|
26
|
-
<Text style={s.moreLink}>{expanded ?
|
|
36
|
+
<Text style={s.moreLink}>{expanded ? expandedLabel : collapsedLabel}</Text>
|
|
27
37
|
</TouchableOpacity>
|
|
28
38
|
</CardContainer>
|
|
29
39
|
</View>
|
|
@@ -9,6 +9,9 @@ const meta: Meta = {
|
|
|
9
9
|
|
|
10
10
|
export default meta;
|
|
11
11
|
|
|
12
|
-
const Template: StoryFn = () => <EmptyState />;
|
|
12
|
+
const Template: StoryFn<React.ComponentProps<typeof EmptyState>> = (args) => <EmptyState {...args} />;
|
|
13
13
|
|
|
14
14
|
export const Default = Template.bind({});
|
|
15
|
+
Default.args = {
|
|
16
|
+
message: 'No Data',
|
|
17
|
+
};
|
|
@@ -6,9 +6,10 @@ import { ThemeType, useTheme } from '../../theme';
|
|
|
6
6
|
|
|
7
7
|
type Props = {
|
|
8
8
|
reverted?: boolean;
|
|
9
|
+
message: string;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
const EmptyState = () => {
|
|
12
|
+
const EmptyState: React.FC<Props> = ({ message }) => {
|
|
12
13
|
const { theme, commonStyles, typography } = useTheme();
|
|
13
14
|
const styles = getStyles(theme);
|
|
14
15
|
|
|
@@ -16,7 +17,7 @@ const EmptyState = () => {
|
|
|
16
17
|
<View style={[commonStyles.container, styles.container]}>
|
|
17
18
|
<Ionicons name="file-tray-outline" size={50} color={theme.placeholder} />
|
|
18
19
|
<Spacer size='xxs' />
|
|
19
|
-
<Text style={[typography.titleH6Regular, { color: theme.placeholder }]}>
|
|
20
|
+
<Text style={[typography.titleH6Regular, { color: theme.placeholder }]}>{message}</Text>
|
|
20
21
|
</View>
|
|
21
22
|
);
|
|
22
23
|
};
|
package/components/UI/NoAuth.tsx
CHANGED
|
@@ -7,21 +7,22 @@ import { useTheme } from '../../theme';
|
|
|
7
7
|
|
|
8
8
|
type NoAuthProps = {
|
|
9
9
|
onPress: () => void;
|
|
10
|
+
title: string;
|
|
11
|
+
description: string;
|
|
12
|
+
buttonText: string;
|
|
10
13
|
}
|
|
11
14
|
|
|
12
|
-
export const NoAuth: FC<NoAuthProps> = ({ onPress }) => {
|
|
15
|
+
export const NoAuth: FC<NoAuthProps> = ({ onPress, title, description, buttonText }) => {
|
|
13
16
|
const { commonStyles, typography, theme } = useTheme();
|
|
14
17
|
|
|
15
18
|
return (
|
|
16
19
|
<View style={[commonStyles.container, {backgroundColor: theme.background}]}>
|
|
17
|
-
<Text style={typography.titleH3}>
|
|
20
|
+
<Text style={typography.titleH3}>{title}</Text>
|
|
18
21
|
<Spacer size='xs' />
|
|
19
|
-
<Text style={typography.body}>
|
|
20
|
-
To continue, please log in to the system.
|
|
21
|
-
</Text>
|
|
22
|
+
<Text style={typography.body}>{description}</Text>
|
|
22
23
|
<Spacer size='lg' />
|
|
23
24
|
<View style={styles.button}>
|
|
24
|
-
<Button title=
|
|
25
|
+
<Button title={buttonText} onPress={onPress} />
|
|
25
26
|
</View>
|
|
26
27
|
</View>
|
|
27
28
|
);
|
|
@@ -32,12 +32,19 @@ PendingParticipant.args = {
|
|
|
32
32
|
participant: {
|
|
33
33
|
_id: 'participant-1',
|
|
34
34
|
status: 'PENDING',
|
|
35
|
+
name: 'Jane',
|
|
36
|
+
lastname: 'Cooper',
|
|
37
|
+
avatarFile: '',
|
|
35
38
|
},
|
|
36
39
|
fullName: 'Jane Cooper',
|
|
37
40
|
avatarUrl: 'https://i.pravatar.cc/100?img=5',
|
|
38
41
|
isMe: true,
|
|
39
42
|
myId: 'host-1',
|
|
40
43
|
isModerated: true,
|
|
44
|
+
confirmLabel: 'Confirm',
|
|
45
|
+
rejectLabel: 'Reject',
|
|
46
|
+
deleteLabel: 'Delete',
|
|
47
|
+
youLabel: 'you',
|
|
41
48
|
};
|
|
42
49
|
|
|
43
50
|
export const ConfirmedGuest = Template.bind({});
|
|
@@ -45,12 +52,19 @@ ConfirmedGuest.args = {
|
|
|
45
52
|
participant: {
|
|
46
53
|
_id: 'participant-2',
|
|
47
54
|
status: 'CONFIRMED',
|
|
55
|
+
name: 'Robert',
|
|
56
|
+
lastname: 'Fox',
|
|
57
|
+
avatarFile: '',
|
|
48
58
|
},
|
|
49
59
|
fullName: 'Robert Fox',
|
|
50
60
|
avatarUrl: 'https://i.pravatar.cc/100?img=12',
|
|
51
61
|
isMe: true,
|
|
52
62
|
myId: 'participant-2',
|
|
53
63
|
isModerated: false,
|
|
64
|
+
confirmLabel: 'Confirm',
|
|
65
|
+
rejectLabel: 'Reject',
|
|
66
|
+
deleteLabel: 'Delete',
|
|
67
|
+
youLabel: 'you',
|
|
54
68
|
};
|
|
55
69
|
|
|
56
70
|
export const ReadOnlyView = Template.bind({});
|
|
@@ -58,10 +72,17 @@ ReadOnlyView.args = {
|
|
|
58
72
|
participant: {
|
|
59
73
|
_id: 'participant-3',
|
|
60
74
|
status: 'REJECTED',
|
|
75
|
+
name: 'Theresa',
|
|
76
|
+
lastname: 'Webb',
|
|
77
|
+
avatarFile: '',
|
|
61
78
|
},
|
|
62
79
|
fullName: 'Theresa Webb',
|
|
63
80
|
avatarUrl: 'https://i.pravatar.cc/100?img=45',
|
|
64
81
|
isMe: false,
|
|
65
82
|
myId: 'host-1',
|
|
66
83
|
isModerated: false,
|
|
84
|
+
confirmLabel: 'Confirm',
|
|
85
|
+
rejectLabel: 'Reject',
|
|
86
|
+
deleteLabel: 'Delete',
|
|
87
|
+
youLabel: 'you',
|
|
67
88
|
};
|
|
@@ -15,11 +15,35 @@ type ParticipantItemProps = {
|
|
|
15
15
|
onReject?: (userId: string) => void;
|
|
16
16
|
onProfilePress: (profileId: string) => void;
|
|
17
17
|
isModerated: boolean;
|
|
18
|
+
confirmLabel: string;
|
|
19
|
+
rejectLabel: string;
|
|
20
|
+
deleteLabel: string;
|
|
21
|
+
youLabel: string;
|
|
22
|
+
statusLabels?: Partial<Record<NonNullable<EventParticipant['status']>, string>>;
|
|
18
23
|
};
|
|
19
24
|
|
|
20
|
-
export const ParticipantItem: FC<ParticipantItemProps> = ({
|
|
25
|
+
export const ParticipantItem: FC<ParticipantItemProps> = ({
|
|
26
|
+
fullName,
|
|
27
|
+
avatarUrl,
|
|
28
|
+
isModerated,
|
|
29
|
+
participant,
|
|
30
|
+
isMe,
|
|
31
|
+
myId,
|
|
32
|
+
onActionPress,
|
|
33
|
+
onProfilePress,
|
|
34
|
+
onConfirm,
|
|
35
|
+
onReject,
|
|
36
|
+
confirmLabel,
|
|
37
|
+
rejectLabel,
|
|
38
|
+
deleteLabel,
|
|
39
|
+
youLabel,
|
|
40
|
+
statusLabels,
|
|
41
|
+
}) => {
|
|
21
42
|
const { globalStyleSheet, theme, sizes, commonStyles, typography } = useTheme();
|
|
22
43
|
const styles = getStyles({ theme, sizes, commonStyles });
|
|
44
|
+
const statusKey = participant.status as NonNullable<EventParticipant['status']> | undefined;
|
|
45
|
+
const statusText = statusKey ? statusLabels?.[statusKey] ?? participant.status?.toLowerCase() : undefined;
|
|
46
|
+
const statusStyle = statusKey ? (styles as Record<string, typeof styles.status_default>)[`status_${statusKey}`] : undefined;
|
|
23
47
|
|
|
24
48
|
return (
|
|
25
49
|
<View key={participant._id} style={globalStyleSheet.flexRowCenterBetween}>
|
|
@@ -28,19 +52,19 @@ export const ParticipantItem: FC<ParticipantItemProps> = ({ fullName, avatarUrl,
|
|
|
28
52
|
<Text style={typography.body}>{fullName}</Text>
|
|
29
53
|
</TouchableOpacity>
|
|
30
54
|
<View style={globalStyleSheet.flexRowCenter}>
|
|
31
|
-
{
|
|
32
|
-
<Text style={[styles.statusText,
|
|
55
|
+
{statusText && (
|
|
56
|
+
<Text style={[styles.statusText, statusStyle ?? styles.status_default]}>{statusText}</Text>
|
|
33
57
|
)}
|
|
34
58
|
{isMe && myId !== participant._id && (
|
|
35
59
|
<ThreeDotsMenu
|
|
36
60
|
items={[
|
|
37
61
|
{
|
|
38
|
-
label:
|
|
62
|
+
label: confirmLabel,
|
|
39
63
|
icon: 'checkmark-outline',
|
|
40
64
|
onPress: () => onConfirm && onConfirm(participant._id),
|
|
41
65
|
},
|
|
42
66
|
{
|
|
43
|
-
label: isModerated ?
|
|
67
|
+
label: isModerated ? rejectLabel : deleteLabel,
|
|
44
68
|
icon: 'close-outline',
|
|
45
69
|
colorIcon: theme.red,
|
|
46
70
|
onPress: () => isModerated ? (onReject && onReject(participant._id)) : onActionPress(participant._id),
|
|
@@ -49,7 +73,7 @@ export const ParticipantItem: FC<ParticipantItemProps> = ({ fullName, avatarUrl,
|
|
|
49
73
|
/>
|
|
50
74
|
|
|
51
75
|
)}
|
|
52
|
-
{isMe && myId === participant._id && <Text style={styles.youText}>
|
|
76
|
+
{isMe && myId === participant._id && <Text style={styles.youText}>{youLabel}</Text>}
|
|
53
77
|
</View>
|
|
54
78
|
</View>
|
|
55
79
|
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useMemo } from "react";
|
|
2
2
|
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
|
3
|
-
import { ThemeType, TypographytType, SizesType, useTheme } from "
|
|
3
|
+
import { ThemeType, TypographytType, SizesType, useTheme } from "../../theme";
|
|
4
4
|
|
|
5
5
|
interface StepProgressProps {
|
|
6
6
|
steps: { title: string; description?: string }[];
|
|
@@ -17,6 +17,10 @@ const meta: Meta = {
|
|
|
17
17
|
|
|
18
18
|
export default meta;
|
|
19
19
|
|
|
20
|
-
const Template: StoryFn = () => <ThemeSwitcher />;
|
|
20
|
+
const Template: StoryFn<React.ComponentProps<typeof ThemeSwitcher>> = (args) => <ThemeSwitcher {...args} />;
|
|
21
21
|
|
|
22
22
|
export const Default = Template.bind({});
|
|
23
|
+
Default.args = {
|
|
24
|
+
lightModeLabel: 'Light Mode',
|
|
25
|
+
darkModeLabel: 'Dark Mode',
|
|
26
|
+
};
|
|
@@ -3,7 +3,12 @@ import { View, Text, Switch, StyleSheet } from 'react-native';
|
|
|
3
3
|
import { FontAwesome } from '@expo/vector-icons';
|
|
4
4
|
import { useTheme } from '../../theme';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
interface ThemeSwitcherProps {
|
|
7
|
+
lightModeLabel: string;
|
|
8
|
+
darkModeLabel: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const ThemeSwitcher: React.FC<ThemeSwitcherProps> = ({ lightModeLabel, darkModeLabel }) => {
|
|
7
12
|
const { theme, toggleTheme, isDark, globalStyleSheet, typography } = useTheme();
|
|
8
13
|
// th-list puzzle-piece
|
|
9
14
|
return (
|
|
@@ -11,7 +16,7 @@ const ThemeSwitcher: React.FC = () => {
|
|
|
11
16
|
<View style={globalStyleSheet.flexRowCenter}>
|
|
12
17
|
<FontAwesome style={styles.iconContainer} name={"th-list"} size={18} color={theme.text} />
|
|
13
18
|
<Text style={[typography.titleH6Regular, { color: theme.text }]}>
|
|
14
|
-
{isDark ?
|
|
19
|
+
{isDark ? darkModeLabel : lightModeLabel}
|
|
15
20
|
</Text>
|
|
16
21
|
</View>
|
|
17
22
|
<Switch
|
|
@@ -58,6 +58,7 @@ export const Default: Story = {
|
|
|
58
58
|
title: 'Необходимо обновление',
|
|
59
59
|
description:
|
|
60
60
|
'Для корректной работы приложения установите последнюю версию. Нажмите кнопку ниже, чтобы перейти в магазин.',
|
|
61
|
+
updateButtonText: 'Обновить',
|
|
61
62
|
},
|
|
62
63
|
};
|
|
63
64
|
|
|
@@ -67,5 +68,6 @@ export const Refreshing: Story = {
|
|
|
67
68
|
refreshing: true,
|
|
68
69
|
title: 'Проверка обновлений...',
|
|
69
70
|
description: 'Подождите, идет проверка доступных обновлений.',
|
|
71
|
+
updateButtonText: 'Обновить',
|
|
70
72
|
},
|
|
71
73
|
};
|
|
@@ -19,9 +19,10 @@ type Props = {
|
|
|
19
19
|
onPressUpdate: () => void;
|
|
20
20
|
title: string;
|
|
21
21
|
description: string;
|
|
22
|
+
updateButtonText: string;
|
|
22
23
|
};
|
|
23
24
|
|
|
24
|
-
export const UpdateRequiredView = memo(({ anim, refreshing, onRefresh, onPressUpdate, title, description }: Props) => {
|
|
25
|
+
export const UpdateRequiredView = memo(({ anim, refreshing, onRefresh, onPressUpdate, title, description, updateButtonText }: Props) => {
|
|
25
26
|
const { theme, commonStyles, typography } = useTheme() as any;
|
|
26
27
|
|
|
27
28
|
const ui = {
|
|
@@ -51,7 +52,7 @@ export const UpdateRequiredView = memo(({ anim, refreshing, onRefresh, onPressUp
|
|
|
51
52
|
|
|
52
53
|
<Spacer size="xl" />
|
|
53
54
|
<View style={styles.button}>
|
|
54
|
-
<Button title=
|
|
55
|
+
<Button title={updateButtonText} onPress={onPressUpdate} />
|
|
55
56
|
</View>
|
|
56
57
|
</ScrollView>
|
|
57
58
|
);
|
|
@@ -7,9 +7,10 @@ interface OrganizerContainerProps {
|
|
|
7
7
|
avatarUri: string;
|
|
8
8
|
organizerName: string;
|
|
9
9
|
onPress: () => void;
|
|
10
|
+
roleLabel: string;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
const Organizer: React.FC<OrganizerContainerProps> = ({ avatarUri, organizerName, onPress }) => {
|
|
13
|
+
const Organizer: React.FC<OrganizerContainerProps> = ({ avatarUri, organizerName, onPress, roleLabel }) => {
|
|
13
14
|
const { globalStyleSheet, sizes, commonStyles, typography } = useTheme();
|
|
14
15
|
const styles = getStyles({ sizes, commonStyles });
|
|
15
16
|
|
|
@@ -17,7 +18,7 @@ const Organizer: React.FC<OrganizerContainerProps> = ({ avatarUri, organizerName
|
|
|
17
18
|
<TouchableOpacity onPress={onPress} style={globalStyleSheet.flexRowCenter}>
|
|
18
19
|
<Image source={{ uri: avatarUri }} style={styles.avatar} />
|
|
19
20
|
<View>
|
|
20
|
-
<Text style={typography.body}>
|
|
21
|
+
<Text style={typography.body}>{roleLabel}</Text>
|
|
21
22
|
<Text
|
|
22
23
|
style={typography.titleH6Regular}
|
|
23
24
|
numberOfLines={1}
|
|
@@ -33,22 +33,26 @@ export const Default = Template.bind({});
|
|
|
33
33
|
Default.args = {
|
|
34
34
|
avatarUri: 'https://i.pravatar.cc/150?img=5',
|
|
35
35
|
organizerName: 'Maria Antonova',
|
|
36
|
+
roleLabel: 'Organizer',
|
|
36
37
|
};
|
|
37
38
|
|
|
38
39
|
export const LongName = Template.bind({});
|
|
39
40
|
LongName.args = {
|
|
40
41
|
avatarUri: 'https://i.pravatar.cc/150?img=47',
|
|
41
42
|
organizerName: 'Ассоциация содействия развитию креативных индустрий Белграда',
|
|
43
|
+
roleLabel: 'Organizer',
|
|
42
44
|
};
|
|
43
45
|
|
|
44
46
|
export const CustomAvatar = Template.bind({});
|
|
45
47
|
CustomAvatar.args = {
|
|
46
48
|
avatarUri: 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?auto=format&fit=crop&w=200&q=80',
|
|
47
49
|
organizerName: 'Volunteer Labs',
|
|
50
|
+
roleLabel: 'Organizer',
|
|
48
51
|
};
|
|
49
52
|
|
|
50
53
|
export const WithoutAvatar = Template.bind({});
|
|
51
54
|
WithoutAvatar.args = {
|
|
52
55
|
avatarUri: 'https://via.placeholder.com/80x80.png?text=Org',
|
|
53
56
|
organizerName: 'Placeholder Collective',
|
|
57
|
+
roleLabel: 'Organizer',
|
|
54
58
|
};
|
|
@@ -59,6 +59,7 @@ Default.args = {
|
|
|
59
59
|
services,
|
|
60
60
|
gallery,
|
|
61
61
|
link: 'https://images.unsplash.com/',
|
|
62
|
+
actionLabel: 'More',
|
|
62
63
|
};
|
|
63
64
|
|
|
64
65
|
export const WithoutServices = Template.bind({});
|
|
@@ -83,6 +84,7 @@ MinimalInfo.args = {
|
|
|
83
84
|
fullName: 'Unknown Specialist',
|
|
84
85
|
avatarUri: 'https://i.pravatar.cc/150?img=60',
|
|
85
86
|
link: 'https://images.unsplash.com/',
|
|
87
|
+
actionLabel: 'More',
|
|
86
88
|
};
|
|
87
89
|
|
|
88
90
|
export const ExtendedServices = Template.bind({});
|
|
@@ -13,9 +13,10 @@ interface SpecialistCardProps {
|
|
|
13
13
|
gallery?: string[];
|
|
14
14
|
link: string;
|
|
15
15
|
onPress: () => void;
|
|
16
|
+
actionLabel: string;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
const SpecialistCard: React.FC<SpecialistCardProps> = ({avatarUri, services, gallery, onPress, link, fullName, profession, city, country }) => {
|
|
19
|
+
const SpecialistCard: React.FC<SpecialistCardProps> = ({avatarUri, services, gallery, onPress, link, fullName, profession, city, country, actionLabel }) => {
|
|
19
20
|
const { theme, typography } = useTheme() as any;
|
|
20
21
|
const styles = getStyles(theme);
|
|
21
22
|
|
|
@@ -52,7 +53,7 @@ const SpecialistCard: React.FC<SpecialistCardProps> = ({avatarUri, services, gal
|
|
|
52
53
|
style={styles.bookBtn}
|
|
53
54
|
activeOpacity={0.85}
|
|
54
55
|
>
|
|
55
|
-
<Text style={styles.bookText}>
|
|
56
|
+
<Text style={styles.bookText}>{actionLabel}</Text>
|
|
56
57
|
</TouchableOpacity>
|
|
57
58
|
</View>
|
|
58
59
|
|