@nuskin/routine-feature 1.0.1 → 2.0.1

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/src/index.tsx CHANGED
@@ -1,166 +1,217 @@
1
- import React, { useEffect } from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import {
3
3
  FlatList,
4
4
  Image,
5
5
  SafeAreaView,
6
- SectionList,
7
6
  StyleSheet,
8
7
  Text,
9
8
  TouchableOpacity,
10
9
  View,
10
+ ActivityIndicator,
11
11
  } from 'react-native';
12
- import { createNativeStackNavigator } from '@nuskin/mobile-navigation';
13
- import { VeraHeader, Logo, HeaderCart } from '@ns/mobile-ui';
14
-
15
- const Stack = createNativeStackNavigator();
16
-
17
- const SECTIONS = [
18
- {
19
- title: 'My Routines',
20
- horizontal: true,
21
- data: [
22
- {
23
- key: '1',
24
- text: 'Card Title Onessssss',
25
- uri: 'https://picsum.photos/id/1/200',
26
- },
27
- {
28
- key: '2',
29
- text: 'Card Title 2',
30
- uri: 'https://picsum.photos/id/10/200',
31
- },
32
-
33
- {
34
- key: '3',
35
- text: 'Card Title 3',
36
- uri: 'https://picsum.photos/id/1002/200',
37
- },
38
- ],
39
- },
40
- {
41
- title: 'Featured Routines',
42
- horizontal: true,
43
- data: [
44
- {
45
- key: '1',
46
- text: 'Card Title 1',
47
- uri: 'https://picsum.photos/id/1011/200',
48
- },
49
- {
50
- key: '2',
51
- text: 'Card Title 2',
52
- uri: 'https://picsum.photos/id/1012/200',
53
- },
54
-
55
- {
56
- key: '3',
57
- text: 'Card Title 3',
58
- uri: 'https://picsum.photos/id/1013/200',
59
- },
60
- ],
61
- },
62
- {
63
- title: 'Suggested Routines',
64
- horizontal: true,
65
- data: [
66
- {
67
- key: '1',
68
- text: 'Card Title 1',
69
- uri: 'https://picsum.photos/id/1020/200',
70
- },
71
- {
72
- key: '2',
73
- text: 'Card Title 2',
74
- uri: 'https://picsum.photos/id/1024/200',
75
- },
12
+ import { gql, useQuery } from '@apollo/client';
13
+ import { useNavigation } from '@react-navigation/native';
14
+ import {
15
+ VeraHeader,
16
+ Logo,
17
+ HeaderCart,
18
+ colors,
19
+ ErrorScreen,
20
+ } from '@ns/mobile-ui';
21
+ import { localization, localizationState } from '@nuskin/utils-module';
22
+ import { useSnapshot } from 'valtio';
23
+ import RoutineDetails from './RoutineDetails';
24
+ import { Logger } from '@nuskin/mobile-logging';
25
+ import { accessibility } from './helpers/Accessibility';
26
+ import { createStackNavigator } from '@react-navigation/stack';
76
27
 
77
- {
78
- key: '3',
79
- text: 'Card Title 3',
80
- uri: 'https://picsum.photos/id/1027/200',
81
- },
82
- ],
83
- },
84
- ];
28
+ const Stack = createStackNavigator();
29
+ export const FETCH_ROUTINES_PAGE = gql`
30
+ query fetchAllHomePages($locale: String) {
31
+ result: all_routine(fallback_locale: true, locale: $locale) {
32
+ items {
33
+ products_used_label
34
+ sort_list_label
35
+ title
36
+ routines {
37
+ products {
38
+ product_name
39
+ product_category
40
+ product_imageConnection {
41
+ edges {
42
+ node {
43
+ url
44
+ }
45
+ }
46
+ }
47
+ }
48
+ products_used_label
49
+ routine_title
50
+ routine_subtitle
51
+ routines_description
52
+ routine_step_label
53
+ reference
54
+ routine_imageConnection {
55
+ edges {
56
+ node {
57
+ url
58
+ }
59
+ }
60
+ }
61
+ steps {
62
+ imageConnection {
63
+ edges {
64
+ node {
65
+ url
66
+ }
67
+ }
68
+ }
69
+ step_sub_description
70
+ step_title
71
+ step_description
72
+ style
73
+ image_title
74
+ image_description
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ `;
85
81
 
86
82
  const ListItem = ({ item, index }) => {
83
+ const navigation = useNavigation();
84
+ const handleOnPress = () => {
85
+ navigation.navigate('RoutineDetails' as never, item as never);
86
+ };
87
87
  return (
88
- <View style={[styles.item, index === 0 ? { marginLeft: 0 } : {}]}>
89
- <Image
90
- source={{
91
- uri: item.uri,
92
- }}
93
- style={styles.itemPhoto}
94
- resizeMode="cover"
95
- />
96
- <Text style={styles.itemText}>{item.text}</Text>
88
+ <View style={styles.itemContainer}>
89
+ <TouchableOpacity onPress={handleOnPress}>
90
+ <View>
91
+ <Image
92
+ {...accessibility(`list-item-${index}`)}
93
+ source={{
94
+ uri: item.routine_imageConnection?.edges[0]?.node?.url,
95
+ }}
96
+ style={styles.itemPhoto}
97
+ />
98
+ </View>
99
+ <View style={styles.itemTextContainer}>
100
+ <View style={styles.itemTitleContainer}>
101
+ <Text
102
+ {...accessibility(`list-item-title-${index}`)}
103
+ style={styles.itemTextTitle}
104
+ >
105
+ {item.routine_title}
106
+ </Text>
107
+ <Text style={styles.itemTextSteps}>
108
+ {item.steps.length} {item.routine_step_label}
109
+ </Text>
110
+ </View>
111
+ <View style={styles.listContainer}>
112
+ <Text style={styles.itemText}>{item.products_used_label}</Text>
113
+ <FlatList
114
+ data={item.products}
115
+ horizontal
116
+ renderItem={({ item, index }) => (
117
+ <Image
118
+ key={index}
119
+ {...accessibility(`list-item-product-${index}`)}
120
+ source={{
121
+ uri: item.product_imageConnection?.edges[0]?.node?.url,
122
+ }}
123
+ style={styles.productPhoto}
124
+ resizeMode="contain"
125
+ />
126
+ )}
127
+ showsHorizontalScrollIndicator={false}
128
+ />
129
+ </View>
130
+ </View>
131
+ </TouchableOpacity>
97
132
  </View>
98
133
  );
99
134
  };
100
135
 
101
136
  const Routines = () => {
102
- const handleOnPress = () => {
103
- // console.log('onPress', section)
104
- };
137
+ const localizationStore = useSnapshot(localizationState);
138
+ const [refresh, setRefresh] = useState(false);
139
+ const locale = localization.getLocalization(
140
+ localization.LocalizationFormat.CONTENT_STACK
141
+ );
142
+
143
+ const { loading, error, data, refetch } = useQuery(FETCH_ROUTINES_PAGE, {
144
+ variables: { locale },
145
+ });
146
+
147
+ useEffect(() => {
148
+ setRefresh(!refresh);
149
+ }, [localizationStore]);
150
+
151
+ const routinesPageData = data ? data.result.items[0] : {};
152
+ if (error || !routinesPageData) {
153
+ const errorCode = error?.graphQLErrors[0]?.extensions?.errors[0]?.code;
154
+
155
+ return (
156
+ <SafeAreaView style={styles.container}>
157
+ <ErrorScreen errorCode={errorCode} refresh={() => refetch()} />
158
+ </SafeAreaView>
159
+ );
160
+ }
161
+ if (loading) {
162
+ return (
163
+ <SafeAreaView
164
+ style={styles.container}
165
+ {...accessibility('routine-container-loading')}
166
+ >
167
+ <ActivityIndicator
168
+ size="large"
169
+ {...accessibility('routine-activity-indicator')}
170
+ />
171
+ </SafeAreaView>
172
+ );
173
+ }
105
174
 
106
175
  return (
107
176
  <SafeAreaView style={styles.container} testID="routineStack">
108
177
  <VeraHeader
109
178
  left={<Logo accessibilityLabel="logo" />}
110
179
  right={<HeaderCart accessibilityLabel="crt-btn" />}
111
- title="Routines"
112
- accessibilityLabel="header"
180
+ title={routinesPageData.title}
181
+ {...accessibility('routine-activity-indicator')}
113
182
  />
114
- <View style={{ flex: 1, backgroundColor: 'white' }}>
115
- <SectionList
116
- stickySectionHeadersEnabled={false}
117
- sections={SECTIONS}
118
- renderSectionHeader={({ section }) => (
119
- <>
120
- <Text style={styles.sectionHeader}>{section.title}</Text>
121
- <FlatList
122
- horizontal
123
- data={section.data}
124
- renderItem={({ item, index }) => (
125
- <TouchableOpacity onPress={handleOnPress}>
126
- <ListItem item={item} index={index} />
127
- </TouchableOpacity>
128
- )}
129
- showsHorizontalScrollIndicator={false}
130
- contentContainerStyle={{ paddingHorizontal: 15 }}
131
- />
132
- </>
133
- )}
134
- renderItem={({ item, section, index }) => {
135
- if (section.horizontal) {
136
- return null;
137
- }
138
- return <ListItem item={item} index={index} />;
139
- }}
140
- />
183
+ <View style={styles.routinesContainer}>
184
+ {routinesPageData && (
185
+ <>
186
+ <Text style={styles.sortListText}>
187
+ {routinesPageData.sort_list_label}
188
+ </Text>
189
+ <FlatList
190
+ data={routinesPageData.routines}
191
+ renderItem={({ item, index }) => (
192
+ <ListItem index={index} item={item} key={index} />
193
+ )}
194
+ showsHorizontalScrollIndicator={false}
195
+ contentContainerStyle={{ paddingHorizontal: 15 }}
196
+ />
197
+ </>
198
+ )}
141
199
  </View>
142
200
  </SafeAreaView>
143
201
  );
144
202
  };
145
203
 
146
- function RoutineDetails() {
147
- return (
148
- <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
149
- <Text>Routine</Text>
150
- </View>
151
- );
152
- }
153
-
154
- function RoutineStack(LOG, { navigation }) {
204
+ function RoutineStack() {
205
+ const navigation = useNavigation();
155
206
  useEffect(() => {
156
207
  const unsubscribe = navigation.addListener('focus', () => {
157
- LOG.info('User navigated to the RoutineStack page.');
208
+ Logger.info('User navigated to the RoutineStack page.');
158
209
  });
159
210
  return unsubscribe;
160
211
  }, [navigation]);
161
212
 
162
213
  return (
163
- <Stack.Navigator>
214
+ <Stack.Navigator initialRouteName="Routines">
164
215
  <Stack.Screen
165
216
  name="Routines"
166
217
  component={Routines}
@@ -175,20 +226,25 @@ function RoutineStack(LOG, { navigation }) {
175
226
  );
176
227
  }
177
228
 
178
- function useRoutine() {
179
- //
180
- }
181
-
182
229
  const styles = StyleSheet.create({
183
230
  container: {
184
231
  flex: 1,
185
- backgroundColor: '#F9F9F9',
232
+ backgroundColor: colors.white,
233
+ },
234
+ routinesContainer: {
235
+ backgroundColor: colors.primaryGray,
236
+ flex: 1,
237
+ paddingTop: 10,
238
+ },
239
+ listContainer: {
240
+ flexDirection: 'column',
241
+ paddingHorizontal: 15,
242
+ paddingVertical: 10,
186
243
  },
187
244
  sectionHeader: {
188
245
  textTransform: 'uppercase',
189
246
  fontWeight: '600',
190
247
  fontSize: 14,
191
- // color: '#f4f4f4',
192
248
  marginTop: 20,
193
249
  paddingHorizontal: 15,
194
250
  marginBottom: 5,
@@ -197,19 +253,61 @@ const styles = StyleSheet.create({
197
253
  margin: 10,
198
254
  borderRadius: 14,
199
255
  },
256
+ itemContainer: {
257
+ backgroundColor: 'transparent',
258
+ flex: 1,
259
+ marginBottom: 10,
260
+ },
261
+ itemTextContainer: {
262
+ backgroundColor: colors.white,
263
+ paddingTop: 20,
264
+ paddingBottom: 10,
265
+ },
200
266
  itemPhoto: {
201
- width: 230,
202
- height: 160,
203
- borderRadius: 14,
267
+ width: '100%',
268
+ minHeight: 160,
269
+ },
270
+ productPhoto: {
271
+ margin: 2,
272
+ width: 40,
273
+ height: 40,
274
+ borderRadius: 50,
275
+ borderColor: '#EDEDED',
276
+ borderWidth: 1,
277
+ },
278
+ itemTitleContainer: {
279
+ flexDirection: 'row',
280
+ justifyContent: 'space-between',
281
+ paddingHorizontal: 15,
282
+ },
283
+ itemTextTitle: {
284
+ color: colors.primaryBlack,
285
+ fontWeight: '600',
286
+ fontSize: 18,
204
287
  },
205
288
  itemText: {
206
- color: 'rgba(255, 255, 255, 1)',
289
+ color: colors.primaryBlack,
207
290
  fontWeight: 'bold',
208
- marginTop: 5,
209
- position: 'absolute',
210
- left: 16,
211
- bottom: 16,
291
+ fontSize: 12,
292
+ letterSpacing: 0.05,
293
+ paddingBottom: 5,
294
+ textTransform: 'uppercase',
295
+ },
296
+ itemTextSteps: {
297
+ color: colors.primaryBlack,
298
+ fontWeight: 'bold',
299
+ textTransform: 'uppercase',
300
+ },
301
+ sortListText: {
302
+ color: colors.primaryBlack,
303
+ fontWeight: 'bold',
304
+ textTransform: 'uppercase',
305
+ textAlign: 'right',
306
+ marginRight: 10,
307
+ letterSpacing: 0.5,
308
+ paddingVertical: 10,
309
+ paddingRight: 20,
212
310
  },
213
311
  });
214
312
 
215
- export { RoutineStack, useRoutine };
313
+ export { RoutineStack };