@plusscommunities/pluss-feature-builder-app-d 8.0.8-beta.0 → 8.0.9
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/dist/module/components/WidgetLarge.js +80 -163
- package/dist/module/components/WidgetLarge.js.map +1 -1
- package/dist/module/components/WidgetSmall.js +82 -208
- package/dist/module/components/WidgetSmall.js.map +1 -1
- package/dist/module/feature.config.js +3 -2
- package/dist/module/feature.config.js.map +1 -1
- package/package.json +1 -1
- package/src/components/WidgetLarge.js +81 -193
- package/src/components/WidgetSmall.js +82 -233
- package/src/feature.config.js +2 -1
|
@@ -1,23 +1,20 @@
|
|
|
1
|
-
import React, { Component } from
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import { getMainBrandingColourFromState } from "../js";
|
|
19
|
-
import { getSummaryFieldValue } from "../js/helpers";
|
|
20
|
-
import { loadTargetFeature } from "../actions/featureBuilderActions";
|
|
1
|
+
import React, { Component } from 'react';
|
|
2
|
+
import { Text, View, StyleSheet } from 'react-native';
|
|
3
|
+
import { connect } from 'react-redux';
|
|
4
|
+
import _ from 'lodash';
|
|
5
|
+
import { Services } from '../feature.config';
|
|
6
|
+
import { Components, Colours } from '../core.config';
|
|
7
|
+
import { values } from '../values.config';
|
|
8
|
+
import { selectListings, selectFeatureDefinition } from '../utils/selectors';
|
|
9
|
+
import { SPACING } from '../js/spacing';
|
|
10
|
+
import { getMainBrandingColourFromState } from '../js';
|
|
11
|
+
import { loadTargetFeature } from '../actions/featureBuilderActions';
|
|
12
|
+
|
|
13
|
+
// Layouts
|
|
14
|
+
import RoundImageList from './layouts/RoundImageList';
|
|
15
|
+
import CondensedList from './layouts/CondensedList';
|
|
16
|
+
import SquareImageList from './layouts/SquareImageList';
|
|
17
|
+
import FeatureImageList from './layouts/FeatureImageList';
|
|
21
18
|
|
|
22
19
|
class WidgetSmall extends Component {
|
|
23
20
|
constructor(props) {
|
|
@@ -42,22 +39,34 @@ class WidgetSmall extends Component {
|
|
|
42
39
|
if (featureDefinition?.title || featureDefinition?.displayName) {
|
|
43
40
|
return featureDefinition.title || featureDefinition.displayName;
|
|
44
41
|
}
|
|
45
|
-
return values.featureName ||
|
|
42
|
+
return values.featureName || 'Features';
|
|
46
43
|
};
|
|
47
44
|
|
|
48
45
|
getEmptyStateText = () => {
|
|
49
|
-
const { options } = this.props;
|
|
46
|
+
const { options, featureDefinition } = this.props;
|
|
50
47
|
if (options && !_.isEmpty(options.EmptyText)) return options.EmptyText;
|
|
51
|
-
|
|
48
|
+
|
|
49
|
+
const featureName = featureDefinition?.title || featureDefinition?.displayName || values.featureName || 'Feature';
|
|
50
|
+
return `No listings for ${featureName}`;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
getLayoutComponent = layoutType => {
|
|
54
|
+
switch (layoutType) {
|
|
55
|
+
case values.layoutTypes.round:
|
|
56
|
+
return RoundImageList;
|
|
57
|
+
case values.layoutTypes.square:
|
|
58
|
+
return SquareImageList;
|
|
59
|
+
case values.layoutTypes.feature:
|
|
60
|
+
return FeatureImageList;
|
|
61
|
+
default:
|
|
62
|
+
return CondensedList;
|
|
63
|
+
}
|
|
52
64
|
};
|
|
53
65
|
|
|
54
66
|
refresh = () => {
|
|
55
67
|
this.onLoadingChanged(true, async () => {
|
|
56
68
|
try {
|
|
57
|
-
await loadTargetFeature()
|
|
58
|
-
this.props.dispatch,
|
|
59
|
-
() => this.props.getState,
|
|
60
|
-
);
|
|
69
|
+
await this.props.dispatch(loadTargetFeature());
|
|
61
70
|
} finally {
|
|
62
71
|
this.onLoadingChanged(false);
|
|
63
72
|
}
|
|
@@ -66,156 +75,65 @@ class WidgetSmall extends Component {
|
|
|
66
75
|
|
|
67
76
|
onLoadingChanged = (loading, callback) => {
|
|
68
77
|
this.setState({ loading }, () => {
|
|
69
|
-
if (this.props.onLoadingChanged)
|
|
70
|
-
this.props.onLoadingChanged(this.state.loading);
|
|
78
|
+
if (this.props.onLoadingChanged) this.props.onLoadingChanged(this.state.loading);
|
|
71
79
|
if (callback) callback();
|
|
72
80
|
});
|
|
73
81
|
};
|
|
74
82
|
|
|
75
|
-
|
|
76
|
-
Services.navigation.navigate(values.screens.featureList, {
|
|
77
|
-
options: this.props.options,
|
|
78
|
-
});
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
getImageSource = (imageField) => {
|
|
82
|
-
if (!imageField) return null;
|
|
83
|
-
|
|
84
|
-
if (typeof imageField === "string") {
|
|
85
|
-
return { uri: imageField };
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (typeof imageField === "object" && imageField.uri) {
|
|
89
|
-
return imageField;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (typeof imageField === "object" && imageField.url) {
|
|
93
|
-
return { uri: imageField.url };
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return null;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
onListingPress = (listing) => {
|
|
83
|
+
onItemPress = item => {
|
|
100
84
|
const { featureDefinition } = this.props;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
renderListingCard = (listing) => {
|
|
110
|
-
const { colourBrandingMain, featureDefinition } = this.props;
|
|
111
|
-
const title = listing.fields?.[values.mandatoryFields.title] || "Untitled";
|
|
112
|
-
const summary = getSummaryFieldValue(listing, featureDefinition);
|
|
113
|
-
const imageField = listing.fields?.[values.mandatoryFields.featureImage];
|
|
114
|
-
const imageSource = this.getImageSource(imageField);
|
|
115
|
-
|
|
116
|
-
return (
|
|
117
|
-
<TouchableOpacity
|
|
118
|
-
key={listing.id}
|
|
119
|
-
style={styles.cardContainer}
|
|
120
|
-
onPress={() => this.onListingPress(listing)}
|
|
121
|
-
>
|
|
122
|
-
<View style={styles.borderContainer}>
|
|
123
|
-
{imageSource ? (
|
|
124
|
-
<Image
|
|
125
|
-
source={imageSource}
|
|
126
|
-
style={styles.cardImage}
|
|
127
|
-
resizeMode="cover"
|
|
128
|
-
/>
|
|
129
|
-
) : (
|
|
130
|
-
<View style={[styles.cardImage, styles.placeholderImage]}>
|
|
131
|
-
<FontAwesome name="image" size={24} color={Colours.TEXT_LIGHT} />
|
|
132
|
-
</View>
|
|
133
|
-
)}
|
|
134
|
-
<Text style={styles.cardTitle} numberOfLines={1}>
|
|
135
|
-
{title}
|
|
136
|
-
</Text>
|
|
137
|
-
{summary && (
|
|
138
|
-
<Text style={styles.cardSummary} numberOfLines={1}>
|
|
139
|
-
{summary}
|
|
140
|
-
</Text>
|
|
141
|
-
)}
|
|
142
|
-
</View>
|
|
143
|
-
</TouchableOpacity>
|
|
144
|
-
);
|
|
85
|
+
if (featureDefinition) {
|
|
86
|
+
Services.navigation.navigate(values.screens.featureDetail, {
|
|
87
|
+
listing: item,
|
|
88
|
+
featureDefinition: featureDefinition,
|
|
89
|
+
featureTitle: featureDefinition.title || featureDefinition.displayName,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
145
92
|
};
|
|
146
93
|
|
|
147
94
|
renderContent() {
|
|
148
|
-
const { listings } = this.props;
|
|
95
|
+
const { listings, featureDefinition, colourBrandingMain } = this.props;
|
|
149
96
|
|
|
150
|
-
//
|
|
151
|
-
if (
|
|
152
|
-
return
|
|
97
|
+
// Show loading state if no definition or loading
|
|
98
|
+
if (!featureDefinition || this.state.loading) {
|
|
99
|
+
return (
|
|
100
|
+
<View style={styles.loadingPadding}>
|
|
101
|
+
<Components.LoadingStateWidget height={180} />
|
|
102
|
+
</View>
|
|
103
|
+
);
|
|
153
104
|
}
|
|
154
105
|
|
|
106
|
+
// Show empty state if no listings are available
|
|
155
107
|
if (_.isEmpty(listings)) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
return null;
|
|
108
|
+
return (
|
|
109
|
+
<View style={styles.emptyPadding}>
|
|
110
|
+
<Components.EmptyStateWidget title={this.getTitle()} height={120} />
|
|
111
|
+
</View>
|
|
112
|
+
);
|
|
164
113
|
}
|
|
165
114
|
|
|
166
|
-
|
|
167
|
-
const
|
|
115
|
+
const layoutType = featureDefinition.layout?.type || 'condensed';
|
|
116
|
+
const LayoutComponent = this.getLayoutComponent(layoutType);
|
|
117
|
+
const title = this.getTitle();
|
|
168
118
|
|
|
169
119
|
return (
|
|
170
|
-
<
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
>
|
|
178
|
-
{listingsToShow.map((listing) => this.renderListingCard(listing))}
|
|
179
|
-
{listings.length > values.widget.maxItems && (
|
|
180
|
-
<TouchableOpacity
|
|
181
|
-
style={[styles.cardContainer, styles.viewMoreCard]}
|
|
182
|
-
onPress={this.onPressAll}
|
|
183
|
-
>
|
|
184
|
-
<View style={[styles.borderContainer, styles.viewMoreContainer]}>
|
|
185
|
-
<Text style={styles.viewMoreText}>View all</Text>
|
|
186
|
-
<Text style={styles.viewMoreCount}>{listings.length} items</Text>
|
|
187
|
-
</View>
|
|
188
|
-
</TouchableOpacity>
|
|
189
|
-
)}
|
|
190
|
-
</ScrollView>
|
|
120
|
+
<LayoutComponent
|
|
121
|
+
listings={listings}
|
|
122
|
+
featureDefinition={featureDefinition}
|
|
123
|
+
colourBrandingMain={colourBrandingMain}
|
|
124
|
+
title={title}
|
|
125
|
+
onItemPress={this.onItemPress}
|
|
126
|
+
/>
|
|
191
127
|
);
|
|
192
128
|
}
|
|
193
129
|
|
|
194
130
|
render() {
|
|
195
|
-
const { colourBrandingMain } = this.props;
|
|
196
|
-
|
|
197
|
-
const content = this.renderContent();
|
|
198
|
-
// Don't render widget section if content is null (no features available)
|
|
199
|
-
if (content === null) {
|
|
200
|
-
return null;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
131
|
return (
|
|
204
132
|
<View style={styles.sectionContainer}>
|
|
205
133
|
<View style={styles.sectionPadding}>
|
|
206
|
-
<
|
|
207
|
-
<Text style={styles.sectionTitle}>{this.getTitle()}</Text>
|
|
208
|
-
<Components.InlineButton
|
|
209
|
-
onPress={this.onPressAll}
|
|
210
|
-
color={colourBrandingMain}
|
|
211
|
-
touchableStyle={{ paddingTop: SPACING.XS + 2 }}
|
|
212
|
-
textStyle={{ color: "#fff" }}
|
|
213
|
-
>
|
|
214
|
-
{values.labels.viewAll}
|
|
215
|
-
</Components.InlineButton>
|
|
216
|
-
</View>
|
|
134
|
+
<Text style={styles.sectionTitle}>{this.getTitle()}</Text>
|
|
217
135
|
</View>
|
|
218
|
-
{
|
|
136
|
+
{this.renderContent()}
|
|
219
137
|
</View>
|
|
220
138
|
);
|
|
221
139
|
}
|
|
@@ -223,7 +141,7 @@ class WidgetSmall extends Component {
|
|
|
223
141
|
|
|
224
142
|
const styles = StyleSheet.create({
|
|
225
143
|
sectionContainer: {
|
|
226
|
-
backgroundColor:
|
|
144
|
+
backgroundColor: '#fff',
|
|
227
145
|
paddingTop: SPACING.MD,
|
|
228
146
|
},
|
|
229
147
|
sectionPadding: {
|
|
@@ -233,98 +151,29 @@ const styles = StyleSheet.create({
|
|
|
233
151
|
loadingPadding: {
|
|
234
152
|
paddingHorizontal: SPACING.MD,
|
|
235
153
|
},
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
flexDirection: "row",
|
|
239
|
-
alignContent: "flex-start",
|
|
240
|
-
justifyContent: "space-between",
|
|
154
|
+
emptyPadding: {
|
|
155
|
+
paddingHorizontal: SPACING.MD,
|
|
241
156
|
},
|
|
242
157
|
sectionTitle: {
|
|
243
|
-
fontFamily:
|
|
158
|
+
fontFamily: 'sf-bold',
|
|
244
159
|
fontSize: 24,
|
|
245
|
-
color:
|
|
246
|
-
},
|
|
247
|
-
// Listing card styles
|
|
248
|
-
cardContainer: {
|
|
249
|
-
marginRight: SPACING.SM + 4,
|
|
250
|
-
width: values.widget.itemMaxWidth,
|
|
251
|
-
},
|
|
252
|
-
borderContainer: {
|
|
253
|
-
borderRadius: SPACING.SM,
|
|
254
|
-
backgroundColor: "#fff",
|
|
255
|
-
shadowColor: "#000",
|
|
256
|
-
shadowOffset: {
|
|
257
|
-
width: 0,
|
|
258
|
-
height: 2,
|
|
259
|
-
},
|
|
260
|
-
shadowOpacity: 0.1,
|
|
261
|
-
shadowRadius: 3.84,
|
|
262
|
-
elevation: 4,
|
|
263
|
-
padding: SPACING.SM,
|
|
264
|
-
margin: SPACING.SM,
|
|
265
|
-
minHeight: values.widget.itemMinWidth,
|
|
266
|
-
},
|
|
267
|
-
cardImage: {
|
|
268
|
-
width: 88,
|
|
269
|
-
height: 88,
|
|
270
|
-
borderRadius: 44,
|
|
271
|
-
backgroundColor: "#f0f0f0",
|
|
272
|
-
alignSelf: "center",
|
|
273
|
-
marginBottom: SPACING.XS,
|
|
274
|
-
},
|
|
275
|
-
placeholderImage: {
|
|
276
|
-
justifyContent: "center",
|
|
277
|
-
alignItems: "center",
|
|
278
|
-
backgroundColor: "#f0f0f0",
|
|
279
|
-
},
|
|
280
|
-
cardTitle: {
|
|
281
|
-
fontFamily: "sf-semibold",
|
|
282
|
-
fontSize: 14,
|
|
283
|
-
color: "#000",
|
|
284
|
-
textAlign: "center",
|
|
285
|
-
marginBottom: 4,
|
|
286
|
-
},
|
|
287
|
-
cardSummary: {
|
|
288
|
-
fontFamily: "sf-regular",
|
|
289
|
-
fontSize: 12,
|
|
290
|
-
color: "#666",
|
|
291
|
-
textAlign: "center",
|
|
292
|
-
},
|
|
293
|
-
// View more card
|
|
294
|
-
viewMoreCard: {
|
|
295
|
-
justifyContent: "center",
|
|
296
|
-
},
|
|
297
|
-
viewMoreContainer: {
|
|
298
|
-
justifyContent: "center",
|
|
299
|
-
alignItems: "center",
|
|
300
|
-
minHeight: values.widget.itemMinWidth,
|
|
301
|
-
},
|
|
302
|
-
viewMoreText: {
|
|
303
|
-
fontFamily: "sf-semibold",
|
|
304
|
-
fontSize: 14,
|
|
305
|
-
color: Colours.TEXT_DARK || "#000",
|
|
306
|
-
},
|
|
307
|
-
viewMoreCount: {
|
|
308
|
-
fontFamily: "sf-regular",
|
|
309
|
-
fontSize: 12,
|
|
310
|
-
color: "#666",
|
|
311
|
-
marginTop: 2,
|
|
160
|
+
color: '#000',
|
|
312
161
|
},
|
|
313
162
|
});
|
|
314
163
|
|
|
315
|
-
const mapStateToProps =
|
|
164
|
+
const mapStateToProps = state => {
|
|
316
165
|
const { user, notifications } = state;
|
|
166
|
+
const listings = selectListings(state);
|
|
167
|
+
const featureDefinition = selectFeatureDefinition(state);
|
|
317
168
|
|
|
318
169
|
return {
|
|
319
170
|
colourBrandingMain: getMainBrandingColourFromState(state),
|
|
320
|
-
listings:
|
|
321
|
-
featureDefinition:
|
|
171
|
+
listings: listings,
|
|
172
|
+
featureDefinition: featureDefinition,
|
|
322
173
|
site: user.site,
|
|
323
174
|
dataUpdated: notifications.dataUpdated[values.notificationKey],
|
|
324
175
|
strings: state.strings?.config || {},
|
|
325
176
|
};
|
|
326
177
|
};
|
|
327
178
|
|
|
328
|
-
export default connect(mapStateToProps, null, null, { forwardRef: true })(
|
|
329
|
-
WidgetSmall,
|
|
330
|
-
);
|
|
179
|
+
export default connect(mapStateToProps, null, null, { forwardRef: true })(WidgetSmall);
|
package/src/feature.config.js
CHANGED
|
@@ -121,7 +121,8 @@ const FeatureConfig = {
|
|
|
121
121
|
|
|
122
122
|
afterStoreInit: (dispatch, getState) => {
|
|
123
123
|
// Get the site from state (guaranteed to be available due to polling)
|
|
124
|
-
const
|
|
124
|
+
const state = getState();
|
|
125
|
+
const site = state?.user?.site;
|
|
125
126
|
|
|
126
127
|
if (site) {
|
|
127
128
|
// Show loading state before fetching
|