@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,22 @@
|
|
|
1
|
-
import React, { Component } from
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import
|
|
19
|
-
import
|
|
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 { FontAwesome } from '@expo/vector-icons';
|
|
6
|
+
import { Services } from '../feature.config';
|
|
7
|
+
import { Components, Colours } from '../core.config';
|
|
8
|
+
import { values } from '../values.config';
|
|
9
|
+
import { selectListings, selectFeatureDefinition } from '../utils/selectors';
|
|
10
|
+
import { SPACING } from '../js/spacing';
|
|
11
|
+
import { getMainBrandingColourFromState } from '../js';
|
|
12
|
+
import { getSummaryFieldValue } from '../js/helpers';
|
|
13
|
+
import { loadTargetFeature } from '../actions/featureBuilderActions';
|
|
14
|
+
|
|
15
|
+
// Layouts
|
|
16
|
+
import RoundImageList from './layouts/RoundImageList';
|
|
17
|
+
import CondensedList from './layouts/CondensedList';
|
|
18
|
+
import SquareImageList from './layouts/SquareImageList';
|
|
19
|
+
import FeatureImageList from './layouts/FeatureImageList';
|
|
21
20
|
|
|
22
21
|
class WidgetLarge extends Component {
|
|
23
22
|
constructor(props) {
|
|
@@ -42,22 +41,34 @@ class WidgetLarge extends Component {
|
|
|
42
41
|
if (featureDefinition?.title || featureDefinition?.displayName) {
|
|
43
42
|
return featureDefinition.title || featureDefinition.displayName;
|
|
44
43
|
}
|
|
45
|
-
return values.featureName ||
|
|
44
|
+
return values.featureName || 'Custom Features';
|
|
46
45
|
};
|
|
47
46
|
|
|
48
47
|
getEmptyStateText = () => {
|
|
49
|
-
const { options } = this.props;
|
|
48
|
+
const { options, featureDefinition } = this.props;
|
|
50
49
|
if (options && !_.isEmpty(options.EmptyText)) return options.EmptyText;
|
|
51
|
-
|
|
50
|
+
|
|
51
|
+
const featureName = featureDefinition?.title || featureDefinition?.displayName || values.featureName || 'Feature';
|
|
52
|
+
return `No listings for ${featureName}`;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
getLayoutComponent = layoutType => {
|
|
56
|
+
switch (layoutType) {
|
|
57
|
+
case values.layoutTypes.round:
|
|
58
|
+
return RoundImageList;
|
|
59
|
+
case values.layoutTypes.square:
|
|
60
|
+
return SquareImageList;
|
|
61
|
+
case values.layoutTypes.feature:
|
|
62
|
+
return FeatureImageList;
|
|
63
|
+
default:
|
|
64
|
+
return CondensedList;
|
|
65
|
+
}
|
|
52
66
|
};
|
|
53
67
|
|
|
54
68
|
refresh = () => {
|
|
55
69
|
this.onLoadingChanged(true, async () => {
|
|
56
70
|
try {
|
|
57
|
-
await loadTargetFeature()
|
|
58
|
-
this.props.dispatch,
|
|
59
|
-
() => this.props.getState,
|
|
60
|
-
);
|
|
71
|
+
await this.props.dispatch(loadTargetFeature());
|
|
61
72
|
} finally {
|
|
62
73
|
this.onLoadingChanged(false);
|
|
63
74
|
}
|
|
@@ -66,138 +77,65 @@ class WidgetLarge extends Component {
|
|
|
66
77
|
|
|
67
78
|
onLoadingChanged = (loading, callback) => {
|
|
68
79
|
this.setState({ loading }, () => {
|
|
69
|
-
if (this.props.onLoadingChanged)
|
|
70
|
-
this.props.onLoadingChanged(this.state.loading);
|
|
80
|
+
if (this.props.onLoadingChanged) this.props.onLoadingChanged(this.state.loading);
|
|
71
81
|
if (callback) callback();
|
|
72
82
|
});
|
|
73
83
|
};
|
|
74
84
|
|
|
75
|
-
|
|
76
|
-
if (!imageField) return null;
|
|
77
|
-
|
|
78
|
-
if (typeof imageField === "string") {
|
|
79
|
-
return { uri: imageField };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (typeof imageField === "object" && imageField.uri) {
|
|
83
|
-
return imageField;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (typeof imageField === "object" && imageField.url) {
|
|
87
|
-
return { uri: imageField.url };
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return null;
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
onListingPress = (listing) => {
|
|
85
|
+
onItemPress = item => {
|
|
94
86
|
const { featureDefinition } = this.props;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
renderListingCard = (listing) => {
|
|
104
|
-
const { colourBrandingMain, featureDefinition } = this.props;
|
|
105
|
-
const title = listing.fields?.[values.mandatoryFields.title] || "Untitled";
|
|
106
|
-
const summary = getSummaryFieldValue(listing, featureDefinition);
|
|
107
|
-
const imageField = listing.fields?.[values.mandatoryFields.featureImage];
|
|
108
|
-
const imageSource = this.getImageSource(imageField);
|
|
109
|
-
|
|
110
|
-
return (
|
|
111
|
-
<TouchableOpacity
|
|
112
|
-
key={listing.id}
|
|
113
|
-
style={styles.listItem}
|
|
114
|
-
onPress={() => this.onListingPress(listing)}
|
|
115
|
-
>
|
|
116
|
-
{/* Small circular avatar image */}
|
|
117
|
-
<View style={styles.avatarContainer}>
|
|
118
|
-
{imageSource ? (
|
|
119
|
-
<Image
|
|
120
|
-
source={imageSource}
|
|
121
|
-
style={styles.avatar}
|
|
122
|
-
resizeMode="cover"
|
|
123
|
-
/>
|
|
124
|
-
) : (
|
|
125
|
-
<View style={[styles.avatar, styles.placeholderAvatar]}>
|
|
126
|
-
<FontAwesome name="image" size={16} color={Colours.TEXT_LIGHT} />
|
|
127
|
-
</View>
|
|
128
|
-
)}
|
|
129
|
-
</View>
|
|
130
|
-
|
|
131
|
-
{/* Text content */}
|
|
132
|
-
<View style={styles.textContainer}>
|
|
133
|
-
<Text style={styles.titleText} numberOfLines={1}>
|
|
134
|
-
{title}
|
|
135
|
-
</Text>
|
|
136
|
-
{summary && (
|
|
137
|
-
<Text style={styles.descriptionText} numberOfLines={1}>
|
|
138
|
-
{summary}
|
|
139
|
-
</Text>
|
|
140
|
-
)}
|
|
141
|
-
</View>
|
|
142
|
-
|
|
143
|
-
{/* Chevron icon */}
|
|
144
|
-
<View style={styles.chevronContainer}>
|
|
145
|
-
<FontAwesome
|
|
146
|
-
name="chevron-right"
|
|
147
|
-
size={14}
|
|
148
|
-
color={Colours.TEXT_LIGHT}
|
|
149
|
-
/>
|
|
150
|
-
</View>
|
|
151
|
-
</TouchableOpacity>
|
|
152
|
-
);
|
|
87
|
+
if (featureDefinition) {
|
|
88
|
+
Services.navigation.navigate(values.screens.featureDetail, {
|
|
89
|
+
listing: item,
|
|
90
|
+
featureDefinition: featureDefinition,
|
|
91
|
+
featureTitle: featureDefinition.title || featureDefinition.displayName,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
153
94
|
};
|
|
154
95
|
|
|
155
96
|
renderContent() {
|
|
156
|
-
const { listings } = this.props;
|
|
97
|
+
const { listings, featureDefinition, colourBrandingMain } = this.props;
|
|
157
98
|
|
|
158
|
-
//
|
|
159
|
-
if (
|
|
160
|
-
return
|
|
99
|
+
// Show loading state if no definition or loading
|
|
100
|
+
if (!featureDefinition || this.state.loading) {
|
|
101
|
+
return (
|
|
102
|
+
<View style={styles.loadingPadding}>
|
|
103
|
+
<Components.LoadingStateWidget height={300} />
|
|
104
|
+
</View>
|
|
105
|
+
);
|
|
161
106
|
}
|
|
162
107
|
|
|
108
|
+
// Show empty state if no listings are available
|
|
163
109
|
if (_.isEmpty(listings)) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
<
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
return null;
|
|
110
|
+
return (
|
|
111
|
+
<View style={styles.emptyPadding}>
|
|
112
|
+
<Components.EmptyStateWidget title={this.getTitle()} height={120} />
|
|
113
|
+
</View>
|
|
114
|
+
);
|
|
172
115
|
}
|
|
173
116
|
|
|
117
|
+
const layoutType = featureDefinition.layout?.type || 'condensed';
|
|
118
|
+
const LayoutComponent = this.getLayoutComponent(layoutType);
|
|
119
|
+
const title = this.getTitle();
|
|
120
|
+
|
|
174
121
|
return (
|
|
175
|
-
<
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
{
|
|
180
|
-
|
|
122
|
+
<LayoutComponent
|
|
123
|
+
listings={listings}
|
|
124
|
+
featureDefinition={featureDefinition}
|
|
125
|
+
colourBrandingMain={colourBrandingMain}
|
|
126
|
+
title={title}
|
|
127
|
+
onItemPress={this.onItemPress}
|
|
128
|
+
/>
|
|
181
129
|
);
|
|
182
130
|
}
|
|
183
131
|
|
|
184
132
|
render() {
|
|
185
|
-
const { colourBrandingMain } = this.props;
|
|
186
|
-
|
|
187
|
-
const content = this.renderContent();
|
|
188
|
-
// Don't render widget section if content is null (no features available)
|
|
189
|
-
if (content === null) {
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
133
|
return (
|
|
194
134
|
<View style={styles.sectionContainer}>
|
|
195
135
|
<View style={styles.sectionPadding}>
|
|
196
|
-
<
|
|
197
|
-
<Text style={styles.sectionTitle}>{this.getTitle()}</Text>
|
|
198
|
-
</View>
|
|
136
|
+
<Text style={styles.sectionTitle}>{this.getTitle()}</Text>
|
|
199
137
|
</View>
|
|
200
|
-
{
|
|
138
|
+
{this.renderContent()}
|
|
201
139
|
</View>
|
|
202
140
|
);
|
|
203
141
|
}
|
|
@@ -205,7 +143,7 @@ class WidgetLarge extends Component {
|
|
|
205
143
|
|
|
206
144
|
const styles = StyleSheet.create({
|
|
207
145
|
sectionContainer: {
|
|
208
|
-
backgroundColor:
|
|
146
|
+
backgroundColor: '#fff',
|
|
209
147
|
flex: 1,
|
|
210
148
|
},
|
|
211
149
|
sectionPadding: {
|
|
@@ -216,65 +154,17 @@ const styles = StyleSheet.create({
|
|
|
216
154
|
loadingPadding: {
|
|
217
155
|
paddingHorizontal: SPACING.MD,
|
|
218
156
|
},
|
|
219
|
-
|
|
220
|
-
|
|
157
|
+
emptyPadding: {
|
|
158
|
+
paddingHorizontal: SPACING.MD,
|
|
221
159
|
},
|
|
222
160
|
sectionTitle: {
|
|
223
|
-
fontFamily:
|
|
161
|
+
fontFamily: 'sf-bold',
|
|
224
162
|
fontSize: 24,
|
|
225
|
-
color:
|
|
226
|
-
},
|
|
227
|
-
featuresContainer: {
|
|
228
|
-
paddingHorizontal: SPACING.MD,
|
|
229
|
-
paddingBottom: SPACING.MD,
|
|
230
|
-
},
|
|
231
|
-
// Listing item styles (similar to CondensedListItem)
|
|
232
|
-
listItem: {
|
|
233
|
-
flexDirection: "row",
|
|
234
|
-
alignItems: "center",
|
|
235
|
-
paddingHorizontal: 16,
|
|
236
|
-
paddingVertical: 8,
|
|
237
|
-
backgroundColor: "#fff",
|
|
238
|
-
},
|
|
239
|
-
avatarContainer: {
|
|
240
|
-
width: 40,
|
|
241
|
-
height: 40,
|
|
242
|
-
borderRadius: 20,
|
|
243
|
-
marginRight: 12,
|
|
244
|
-
},
|
|
245
|
-
avatar: {
|
|
246
|
-
width: 40,
|
|
247
|
-
height: 40,
|
|
248
|
-
borderRadius: 20,
|
|
249
|
-
backgroundColor: Colours.BACKGROUND_LIGHT || "#f0f0f0",
|
|
250
|
-
},
|
|
251
|
-
placeholderAvatar: {
|
|
252
|
-
backgroundColor: Colours.BACKGROUND_LIGHT || "#f0f0f0",
|
|
253
|
-
justifyContent: "center",
|
|
254
|
-
alignItems: "center",
|
|
255
|
-
},
|
|
256
|
-
textContainer: {
|
|
257
|
-
flex: 1,
|
|
258
|
-
justifyContent: "center",
|
|
259
|
-
},
|
|
260
|
-
titleText: {
|
|
261
|
-
fontFamily: "sf-semibold",
|
|
262
|
-
fontSize: 16,
|
|
263
|
-
color: Colours.TEXT_DARK || "#333",
|
|
264
|
-
marginBottom: 2,
|
|
265
|
-
},
|
|
266
|
-
descriptionText: {
|
|
267
|
-
fontFamily: "sf-regular",
|
|
268
|
-
fontSize: 14,
|
|
269
|
-
color: Colours.TEXT_LIGHT || "#666",
|
|
270
|
-
lineHeight: 18,
|
|
271
|
-
},
|
|
272
|
-
chevronContainer: {
|
|
273
|
-
paddingLeft: 8,
|
|
163
|
+
color: '#000',
|
|
274
164
|
},
|
|
275
165
|
});
|
|
276
166
|
|
|
277
|
-
const mapStateToProps =
|
|
167
|
+
const mapStateToProps = state => {
|
|
278
168
|
const { user, notifications } = state;
|
|
279
169
|
|
|
280
170
|
return {
|
|
@@ -287,6 +177,4 @@ const mapStateToProps = (state) => {
|
|
|
287
177
|
};
|
|
288
178
|
};
|
|
289
179
|
|
|
290
|
-
export default connect(mapStateToProps, null, null, { forwardRef: true })(
|
|
291
|
-
WidgetLarge,
|
|
292
|
-
);
|
|
180
|
+
export default connect(mapStateToProps, null, null, { forwardRef: true })(WidgetLarge);
|