@plusscommunities/pluss-feature-builder-app-d 1.0.1-beta.3
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/actions/featureBuilderActions.js +106 -0
- package/dist/module/actions/featureBuilderActions.js.map +1 -0
- package/dist/module/actions/featureBuilderStringsActions.js +106 -0
- package/dist/module/actions/featureBuilderStringsActions.js.map +1 -0
- package/dist/module/actions/index.js +12 -0
- package/dist/module/actions/index.js.map +1 -0
- package/dist/module/actions/types.js +7 -0
- package/dist/module/actions/types.js.map +1 -0
- package/dist/module/components/FeatureDetailScreen.js +725 -0
- package/dist/module/components/FeatureDetailScreen.js.map +1 -0
- package/dist/module/components/FeatureListItem.js +174 -0
- package/dist/module/components/FeatureListItem.js.map +1 -0
- package/dist/module/components/FeatureListScreen.js +159 -0
- package/dist/module/components/FeatureListScreen.js.map +1 -0
- package/dist/module/components/FieldRenderer.js +218 -0
- package/dist/module/components/FieldRenderer.js.map +1 -0
- package/dist/module/components/FileDownload.js +74 -0
- package/dist/module/components/FileDownload.js.map +1 -0
- package/dist/module/components/WidgetGrid.js +158 -0
- package/dist/module/components/WidgetGrid.js.map +1 -0
- package/dist/module/components/WidgetLarge.js +274 -0
- package/dist/module/components/WidgetLarge.js.map +1 -0
- package/dist/module/components/WidgetSmall.js +315 -0
- package/dist/module/components/WidgetSmall.js.map +1 -0
- package/dist/module/components/common/index.js +25 -0
- package/dist/module/components/common/index.js.map +1 -0
- package/dist/module/components/layouts/CondensedList.js +195 -0
- package/dist/module/components/layouts/CondensedList.js.map +1 -0
- package/dist/module/components/layouts/FeatureImageList.js +172 -0
- package/dist/module/components/layouts/FeatureImageList.js.map +1 -0
- package/dist/module/components/layouts/RoundImageList.js +198 -0
- package/dist/module/components/layouts/RoundImageList.js.map +1 -0
- package/dist/module/components/layouts/SquareImageList.js +185 -0
- package/dist/module/components/layouts/SquareImageList.js.map +1 -0
- package/dist/module/config/index.js +10 -0
- package/dist/module/config/index.js.map +1 -0
- package/dist/module/core.config.js +17 -0
- package/dist/module/core.config.js.map +1 -0
- package/dist/module/feature.config.js +113 -0
- package/dist/module/feature.config.js.map +1 -0
- package/dist/module/index.js +24 -0
- package/dist/module/index.js.map +1 -0
- package/dist/module/js/Colors.js +25 -0
- package/dist/module/js/Colors.js.map +1 -0
- package/dist/module/js/FieldTypes.js +123 -0
- package/dist/module/js/FieldTypes.js.map +1 -0
- package/dist/module/js/NavigationService.js +10 -0
- package/dist/module/js/NavigationService.js.map +1 -0
- package/dist/module/js/Styles.js +3 -0
- package/dist/module/js/Styles.js.map +1 -0
- package/dist/module/js/helpers.js +29 -0
- package/dist/module/js/helpers.js.map +1 -0
- package/dist/module/js/index.js +24 -0
- package/dist/module/js/index.js.map +1 -0
- package/dist/module/js/spacing.js +29 -0
- package/dist/module/js/spacing.js.map +1 -0
- package/dist/module/js/types.js +254 -0
- package/dist/module/js/types.js.map +1 -0
- package/dist/module/reducers/featureBuilderReducer.js +75 -0
- package/dist/module/reducers/featureBuilderReducer.js.map +1 -0
- package/dist/module/utils/featureSelectors.js +9 -0
- package/dist/module/utils/featureSelectors.js.map +1 -0
- package/dist/module/values.config.a.js +96 -0
- package/dist/module/values.config.a.js.map +1 -0
- package/dist/module/values.config.b.js +96 -0
- package/dist/module/values.config.b.js.map +1 -0
- package/dist/module/values.config.c.js +96 -0
- package/dist/module/values.config.c.js.map +1 -0
- package/dist/module/values.config.d.js +96 -0
- package/dist/module/values.config.d.js.map +1 -0
- package/dist/module/values.config.js +96 -0
- package/dist/module/values.config.js.map +1 -0
- package/dist/module/webapi/featureBuilderAPI.js +59 -0
- package/dist/module/webapi/featureBuilderAPI.js.map +1 -0
- package/dist/module/webapi/helper.js +4 -0
- package/dist/module/webapi/helper.js.map +1 -0
- package/dist/module/webapi/index.js +8 -0
- package/dist/module/webapi/index.js.map +1 -0
- package/package.json +62 -0
- package/src/actions/featureBuilderActions.js +112 -0
- package/src/actions/featureBuilderStringsActions.js +114 -0
- package/src/actions/index.js +12 -0
- package/src/actions/types.js +7 -0
- package/src/components/FeatureDetailScreen.js +817 -0
- package/src/components/FeatureListItem.js +198 -0
- package/src/components/FeatureListScreen.js +160 -0
- package/src/components/FieldRenderer.js +272 -0
- package/src/components/FileDownload.js +79 -0
- package/src/components/WidgetGrid.js +181 -0
- package/src/components/WidgetLarge.js +305 -0
- package/src/components/WidgetSmall.js +344 -0
- package/src/components/common/index.js +25 -0
- package/src/components/layouts/CondensedList.js +230 -0
- package/src/components/layouts/FeatureImageList.js +193 -0
- package/src/components/layouts/RoundImageList.js +219 -0
- package/src/components/layouts/SquareImageList.js +205 -0
- package/src/config/index.js +10 -0
- package/src/core.config.js +29 -0
- package/src/feature.config.js +127 -0
- package/src/index.js +27 -0
- package/src/js/Colors.js +30 -0
- package/src/js/FieldTypes.js +131 -0
- package/src/js/NavigationService.js +12 -0
- package/src/js/Styles.js +3 -0
- package/src/js/helpers.js +30 -0
- package/src/js/index.js +24 -0
- package/src/js/spacing.js +30 -0
- package/src/js/types.js +253 -0
- package/src/reducers/featureBuilderReducer.js +64 -0
- package/src/utils/featureSelectors.js +8 -0
- package/src/values.config.a.js +104 -0
- package/src/values.config.b.js +104 -0
- package/src/values.config.c.js +104 -0
- package/src/values.config.d.js +104 -0
- package/src/values.config.js +104 -0
- package/src/webapi/featureBuilderAPI.js +65 -0
- package/src/webapi/helper.js +4 -0
- package/src/webapi/index.js +8 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
2
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
3
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
4
|
+
import React, { Component } from "react";
|
|
5
|
+
import { Text, View, ScrollView, StyleSheet, TouchableOpacity, Image } from "react-native";
|
|
6
|
+
import { connect } from "react-redux";
|
|
7
|
+
import _ from "lodash";
|
|
8
|
+
import { Icon } from "react-native-elements";
|
|
9
|
+
import { Services } from "../feature.config";
|
|
10
|
+
import { Components, Colours } from "../core.config";
|
|
11
|
+
import { values } from "../values.config";
|
|
12
|
+
import { selectListings, selectFeatureDefinition } from "../reducers/featureBuilderReducer";
|
|
13
|
+
import { SPACING } from "../js/spacing";
|
|
14
|
+
import { getMainBrandingColourFromState } from "../js";
|
|
15
|
+
import { getSummaryFieldValue } from "../js/helpers";
|
|
16
|
+
class WidgetLarge extends Component {
|
|
17
|
+
constructor(props) {
|
|
18
|
+
super(props);
|
|
19
|
+
_defineProperty(this, "getTitle", () => {
|
|
20
|
+
const {
|
|
21
|
+
options,
|
|
22
|
+
featureDefinition
|
|
23
|
+
} = this.props;
|
|
24
|
+
if (options && !_.isEmpty(options.Title)) return options.Title;
|
|
25
|
+
// Use feature definition title
|
|
26
|
+
if (featureDefinition !== null && featureDefinition !== void 0 && featureDefinition.title || featureDefinition !== null && featureDefinition !== void 0 && featureDefinition.displayName) {
|
|
27
|
+
return featureDefinition.title || featureDefinition.displayName;
|
|
28
|
+
}
|
|
29
|
+
return values.featureName || "Custom Features";
|
|
30
|
+
});
|
|
31
|
+
_defineProperty(this, "getEmptyStateText", () => {
|
|
32
|
+
const {
|
|
33
|
+
options
|
|
34
|
+
} = this.props;
|
|
35
|
+
if (options && !_.isEmpty(options.EmptyText)) return options.EmptyText;
|
|
36
|
+
return "No custom features available";
|
|
37
|
+
});
|
|
38
|
+
_defineProperty(this, "refresh", () => {
|
|
39
|
+
this.onLoadingChanged(true, async () => {
|
|
40
|
+
try {
|
|
41
|
+
const {
|
|
42
|
+
initializeFeatureBuilder
|
|
43
|
+
} = await import("../actions/featureBuilderActions");
|
|
44
|
+
await initializeFeatureBuilder()(this.props.dispatch, () => this.props.getState);
|
|
45
|
+
} finally {
|
|
46
|
+
this.onLoadingChanged(false);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
_defineProperty(this, "onLoadingChanged", (loading, callback) => {
|
|
51
|
+
this.setState({
|
|
52
|
+
loading
|
|
53
|
+
}, () => {
|
|
54
|
+
if (this.props.onLoadingChanged) this.props.onLoadingChanged(this.state.loading);
|
|
55
|
+
if (callback) callback();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
_defineProperty(this, "getImageSource", imageField => {
|
|
59
|
+
if (!imageField) return null;
|
|
60
|
+
if (typeof imageField === "string") {
|
|
61
|
+
return {
|
|
62
|
+
uri: imageField
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (typeof imageField === "object" && imageField.uri) {
|
|
66
|
+
return imageField;
|
|
67
|
+
}
|
|
68
|
+
if (typeof imageField === "object" && imageField.url) {
|
|
69
|
+
return {
|
|
70
|
+
uri: imageField.url
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
});
|
|
75
|
+
_defineProperty(this, "onListingPress", listing => {
|
|
76
|
+
const {
|
|
77
|
+
featureDefinition
|
|
78
|
+
} = this.props;
|
|
79
|
+
const title = this.getTitle();
|
|
80
|
+
Services.navigation.navigate(values.screens.featureDetail, {
|
|
81
|
+
listing: listing,
|
|
82
|
+
featureDefinition: featureDefinition,
|
|
83
|
+
featureTitle: title
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
_defineProperty(this, "renderListingCard", listing => {
|
|
87
|
+
var _listing$fields, _listing$fields2;
|
|
88
|
+
const {
|
|
89
|
+
colourBrandingMain,
|
|
90
|
+
featureDefinition
|
|
91
|
+
} = this.props;
|
|
92
|
+
const title = ((_listing$fields = listing.fields) === null || _listing$fields === void 0 ? void 0 : _listing$fields[values.mandatoryFields.title]) || "Untitled";
|
|
93
|
+
const summary = getSummaryFieldValue(listing, featureDefinition);
|
|
94
|
+
const imageField = (_listing$fields2 = listing.fields) === null || _listing$fields2 === void 0 ? void 0 : _listing$fields2[values.mandatoryFields.featureImage];
|
|
95
|
+
const imageSource = this.getImageSource(imageField);
|
|
96
|
+
return /*#__PURE__*/React.createElement(TouchableOpacity, {
|
|
97
|
+
key: listing.id,
|
|
98
|
+
style: styles.listItem,
|
|
99
|
+
onPress: () => this.onListingPress(listing)
|
|
100
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
101
|
+
style: styles.avatarContainer
|
|
102
|
+
}, imageSource ? /*#__PURE__*/React.createElement(Image, {
|
|
103
|
+
source: imageSource,
|
|
104
|
+
style: styles.avatar,
|
|
105
|
+
resizeMode: "cover"
|
|
106
|
+
}) : /*#__PURE__*/React.createElement(View, {
|
|
107
|
+
style: [styles.avatar, styles.placeholderAvatar]
|
|
108
|
+
}, /*#__PURE__*/React.createElement(Icon, {
|
|
109
|
+
name: "image",
|
|
110
|
+
type: "font-awesome",
|
|
111
|
+
size: 16,
|
|
112
|
+
color: Colours.TEXT_LIGHT
|
|
113
|
+
}))), /*#__PURE__*/React.createElement(View, {
|
|
114
|
+
style: styles.textContainer
|
|
115
|
+
}, /*#__PURE__*/React.createElement(Text, {
|
|
116
|
+
style: styles.titleText,
|
|
117
|
+
numberOfLines: 1
|
|
118
|
+
}, title), summary && /*#__PURE__*/React.createElement(Text, {
|
|
119
|
+
style: styles.descriptionText,
|
|
120
|
+
numberOfLines: 1
|
|
121
|
+
}, summary)), /*#__PURE__*/React.createElement(View, {
|
|
122
|
+
style: styles.chevronContainer
|
|
123
|
+
}, /*#__PURE__*/React.createElement(Icon, {
|
|
124
|
+
name: "chevron-right",
|
|
125
|
+
type: "font-awesome",
|
|
126
|
+
size: 14,
|
|
127
|
+
color: Colours.TEXT_LIGHT
|
|
128
|
+
})));
|
|
129
|
+
});
|
|
130
|
+
this.state = {
|
|
131
|
+
loading: false
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
componentDidMount() {
|
|
135
|
+
this.refresh();
|
|
136
|
+
}
|
|
137
|
+
componentDidUpdate(prevProps) {
|
|
138
|
+
if (!prevProps.dataUpdated && this.props.dataUpdated) {
|
|
139
|
+
this.refresh();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
renderContent() {
|
|
143
|
+
const {
|
|
144
|
+
listings
|
|
145
|
+
} = this.props;
|
|
146
|
+
|
|
147
|
+
// Don't render widget if no listings are available (and not loading)
|
|
148
|
+
if (_.isEmpty(listings) && !this.state.loading) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
if (_.isEmpty(listings)) {
|
|
152
|
+
if (this.state.loading) {
|
|
153
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
154
|
+
style: styles.loadingPadding
|
|
155
|
+
}, /*#__PURE__*/React.createElement(Components.LoadingStateWidget, {
|
|
156
|
+
height: 300
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
return /*#__PURE__*/React.createElement(ScrollView, {
|
|
162
|
+
contentContainerStyle: styles.featuresContainer,
|
|
163
|
+
showsVerticalScrollIndicator: false
|
|
164
|
+
}, listings.map(listing => this.renderListingCard(listing)));
|
|
165
|
+
}
|
|
166
|
+
render() {
|
|
167
|
+
const {
|
|
168
|
+
colourBrandingMain
|
|
169
|
+
} = this.props;
|
|
170
|
+
const content = this.renderContent();
|
|
171
|
+
// Don't render widget section if content is null (no features available)
|
|
172
|
+
if (content === null) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
176
|
+
style: styles.sectionContainer
|
|
177
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
178
|
+
style: styles.sectionPadding
|
|
179
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
180
|
+
style: styles.sectionHeading
|
|
181
|
+
}, /*#__PURE__*/React.createElement(Text, {
|
|
182
|
+
style: styles.sectionTitle
|
|
183
|
+
}, this.getTitle()))), content);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const styles = StyleSheet.create({
|
|
187
|
+
sectionContainer: {
|
|
188
|
+
backgroundColor: "#fff",
|
|
189
|
+
flex: 1
|
|
190
|
+
},
|
|
191
|
+
sectionPadding: {
|
|
192
|
+
paddingHorizontal: SPACING.MD,
|
|
193
|
+
paddingBottom: SPACING.XS + 2,
|
|
194
|
+
paddingTop: SPACING.MD
|
|
195
|
+
},
|
|
196
|
+
loadingPadding: {
|
|
197
|
+
paddingHorizontal: SPACING.MD
|
|
198
|
+
},
|
|
199
|
+
sectionHeading: {
|
|
200
|
+
marginBottom: SPACING.MD
|
|
201
|
+
},
|
|
202
|
+
sectionTitle: {
|
|
203
|
+
fontFamily: "sf-bold",
|
|
204
|
+
fontSize: 24,
|
|
205
|
+
color: "#000"
|
|
206
|
+
},
|
|
207
|
+
featuresContainer: {
|
|
208
|
+
paddingHorizontal: SPACING.MD,
|
|
209
|
+
paddingBottom: SPACING.MD
|
|
210
|
+
},
|
|
211
|
+
// Listing item styles (similar to CondensedListItem)
|
|
212
|
+
listItem: {
|
|
213
|
+
flexDirection: "row",
|
|
214
|
+
alignItems: "center",
|
|
215
|
+
paddingHorizontal: 16,
|
|
216
|
+
paddingVertical: 8,
|
|
217
|
+
backgroundColor: "#fff"
|
|
218
|
+
},
|
|
219
|
+
avatarContainer: {
|
|
220
|
+
width: 40,
|
|
221
|
+
height: 40,
|
|
222
|
+
borderRadius: 20,
|
|
223
|
+
marginRight: 12
|
|
224
|
+
},
|
|
225
|
+
avatar: {
|
|
226
|
+
width: 40,
|
|
227
|
+
height: 40,
|
|
228
|
+
borderRadius: 20,
|
|
229
|
+
backgroundColor: Colours.BACKGROUND_LIGHT || "#f0f0f0"
|
|
230
|
+
},
|
|
231
|
+
placeholderAvatar: {
|
|
232
|
+
backgroundColor: Colours.BACKGROUND_LIGHT || "#f0f0f0",
|
|
233
|
+
justifyContent: "center",
|
|
234
|
+
alignItems: "center"
|
|
235
|
+
},
|
|
236
|
+
textContainer: {
|
|
237
|
+
flex: 1,
|
|
238
|
+
justifyContent: "center"
|
|
239
|
+
},
|
|
240
|
+
titleText: {
|
|
241
|
+
fontFamily: "sf-semibold",
|
|
242
|
+
fontSize: 16,
|
|
243
|
+
color: Colours.TEXT_DARK || "#333",
|
|
244
|
+
marginBottom: 2
|
|
245
|
+
},
|
|
246
|
+
descriptionText: {
|
|
247
|
+
fontFamily: "sf-regular",
|
|
248
|
+
fontSize: 14,
|
|
249
|
+
color: Colours.TEXT_LIGHT || "#666",
|
|
250
|
+
lineHeight: 18
|
|
251
|
+
},
|
|
252
|
+
chevronContainer: {
|
|
253
|
+
paddingLeft: 8
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
const mapStateToProps = state => {
|
|
257
|
+
var _state$strings;
|
|
258
|
+
const {
|
|
259
|
+
user,
|
|
260
|
+
notifications
|
|
261
|
+
} = state;
|
|
262
|
+
return {
|
|
263
|
+
colourBrandingMain: getMainBrandingColourFromState(state),
|
|
264
|
+
listings: selectListings(state),
|
|
265
|
+
featureDefinition: selectFeatureDefinition(state),
|
|
266
|
+
site: user.site,
|
|
267
|
+
dataUpdated: notifications.dataUpdated[values.notificationKey],
|
|
268
|
+
strings: ((_state$strings = state.strings) === null || _state$strings === void 0 ? void 0 : _state$strings.config) || {}
|
|
269
|
+
};
|
|
270
|
+
};
|
|
271
|
+
export default connect(mapStateToProps, null, null, {
|
|
272
|
+
forwardRef: true
|
|
273
|
+
})(WidgetLarge);
|
|
274
|
+
//# sourceMappingURL=WidgetLarge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","Component","Text","View","ScrollView","StyleSheet","TouchableOpacity","Image","connect","_","Icon","Services","Components","Colours","values","selectListings","selectFeatureDefinition","SPACING","getMainBrandingColourFromState","getSummaryFieldValue","WidgetLarge","constructor","props","_defineProperty","options","featureDefinition","isEmpty","Title","title","displayName","featureName","EmptyText","onLoadingChanged","initializeFeatureBuilder","dispatch","getState","loading","callback","setState","state","imageField","uri","url","listing","getTitle","navigation","navigate","screens","featureDetail","featureTitle","_listing$fields","_listing$fields2","colourBrandingMain","fields","mandatoryFields","summary","featureImage","imageSource","getImageSource","createElement","key","id","style","styles","listItem","onPress","onListingPress","avatarContainer","source","avatar","resizeMode","placeholderAvatar","name","type","size","color","TEXT_LIGHT","textContainer","titleText","numberOfLines","descriptionText","chevronContainer","componentDidMount","refresh","componentDidUpdate","prevProps","dataUpdated","renderContent","listings","loadingPadding","LoadingStateWidget","height","contentContainerStyle","featuresContainer","showsVerticalScrollIndicator","map","renderListingCard","render","content","sectionContainer","sectionPadding","sectionHeading","sectionTitle","create","backgroundColor","flex","paddingHorizontal","MD","paddingBottom","XS","paddingTop","marginBottom","fontFamily","fontSize","flexDirection","alignItems","paddingVertical","width","borderRadius","marginRight","BACKGROUND_LIGHT","justifyContent","TEXT_DARK","lineHeight","paddingLeft","mapStateToProps","_state$strings","user","notifications","site","notificationKey","strings","config","forwardRef"],"sources":["WidgetLarge.js"],"sourcesContent":["import React, { Component } from \"react\";\nimport {\n\tText,\n\tView,\n\tScrollView,\n\tStyleSheet,\n\tTouchableOpacity,\n\tImage,\n} from \"react-native\";\nimport { connect } from \"react-redux\";\nimport _ from \"lodash\";\nimport { Icon } from \"react-native-elements\";\nimport { Services } from \"../feature.config\";\nimport { Components, Colours } from \"../core.config\";\nimport { values } from \"../values.config\";\nimport { selectListings, selectFeatureDefinition } from \"../reducers/featureBuilderReducer\";\nimport { SPACING } from \"../js/spacing\";\nimport { getMainBrandingColourFromState } from \"../js\";\nimport { getSummaryFieldValue } from \"../js/helpers\";\n\nclass WidgetLarge extends Component {\n\tconstructor(props) {\n\t\tsuper(props);\n\t\tthis.state = { loading: false };\n\t}\n\n\tcomponentDidMount() {\n\t\tthis.refresh();\n\t}\n\n\tcomponentDidUpdate(prevProps) {\n\t\tif (!prevProps.dataUpdated && this.props.dataUpdated) {\n\t\t\tthis.refresh();\n\t\t}\n\t}\n\n\tgetTitle = () => {\n\t\tconst { options, featureDefinition } = this.props;\n\t\tif (options && !_.isEmpty(options.Title)) return options.Title;\n\t\t// Use feature definition title\n\t\tif (\n\t\t\tfeatureDefinition?.title ||\n\t\t\tfeatureDefinition?.displayName\n\t\t) {\n\t\t\treturn (\n\t\t\t\tfeatureDefinition.title || featureDefinition.displayName\n\t\t\t);\n\t\t}\n\t\treturn values.featureName || \"Custom Features\";\n\t};\n\n\tgetEmptyStateText = () => {\n\t\tconst { options } = this.props;\n\t\tif (options && !_.isEmpty(options.EmptyText)) return options.EmptyText;\n\t\treturn \"No custom features available\";\n\t};\n\n\trefresh = () => {\n\t\tthis.onLoadingChanged(true, async () => {\n\t\t\ttry {\n\t\t\t\tconst { initializeFeatureBuilder } = await import(\n\t\t\t\t\t\"../actions/featureBuilderActions\"\n\t\t\t\t);\n\t\t\t\tawait initializeFeatureBuilder()(\n\t\t\t\t\tthis.props.dispatch,\n\t\t\t\t\t() => this.props.getState,\n\t\t\t\t);\n\t\t\t} finally {\n\t\t\t\tthis.onLoadingChanged(false);\n\t\t\t}\n\t\t});\n\t};\n\n\tonLoadingChanged = (loading, callback) => {\n\t\tthis.setState({ loading }, () => {\n\t\t\tif (this.props.onLoadingChanged)\n\t\t\t\tthis.props.onLoadingChanged(this.state.loading);\n\t\t\tif (callback) callback();\n\t\t});\n\t};\n\n\tgetImageSource = (imageField) => {\n\t\tif (!imageField) return null;\n\n\t\tif (typeof imageField === \"string\") {\n\t\t\treturn { uri: imageField };\n\t\t}\n\n\t\tif (typeof imageField === \"object\" && imageField.uri) {\n\t\t\treturn imageField;\n\t\t}\n\n\t\tif (typeof imageField === \"object\" && imageField.url) {\n\t\t\treturn { uri: imageField.url };\n\t\t}\n\n\t\treturn null;\n\t};\n\n\tonListingPress = (listing) => {\n\t\tconst { featureDefinition } = this.props;\n\t\tconst title = this.getTitle();\n\t\tServices.navigation.navigate(values.screens.featureDetail, {\n\t\t\tlisting: listing,\n\t\t\tfeatureDefinition: featureDefinition,\n\t\t\tfeatureTitle: title,\n\t\t});\n\t};\n\n\trenderListingCard = (listing) => {\n\t\tconst { colourBrandingMain, featureDefinition } = this.props;\n\t\tconst title = listing.fields?.[values.mandatoryFields.title] || \"Untitled\";\n\t\tconst summary = getSummaryFieldValue(listing, featureDefinition);\n\t\tconst imageField = listing.fields?.[values.mandatoryFields.featureImage];\n\t\tconst imageSource = this.getImageSource(imageField);\n\n\t\treturn (\n\t\t\t<TouchableOpacity\n\t\t\t\tkey={listing.id}\n\t\t\t\tstyle={styles.listItem}\n\t\t\t\tonPress={() => this.onListingPress(listing)}\n\t\t\t>\n\t\t\t\t{/* Small circular avatar image */}\n\t\t\t\t<View style={styles.avatarContainer}>\n\t\t\t\t\t{imageSource ? (\n\t\t\t\t\t\t<Image\n\t\t\t\t\t\t\tsource={imageSource}\n\t\t\t\t\t\t\tstyle={styles.avatar}\n\t\t\t\t\t\t\tresizeMode=\"cover\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<View style={[styles.avatar, styles.placeholderAvatar]}>\n\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\tname=\"image\"\n\t\t\t\t\t\t\t\ttype=\"font-awesome\"\n\t\t\t\t\t\t\t\tsize={16}\n\t\t\t\t\t\t\t\tcolor={Colours.TEXT_LIGHT}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</View>\n\t\t\t\t\t)}\n\t\t\t\t</View>\n\n\t\t\t\t{/* Text content */}\n\t\t\t\t<View style={styles.textContainer}>\n\t\t\t\t\t<Text style={styles.titleText} numberOfLines={1}>\n\t\t\t\t\t\t{title}\n\t\t\t\t\t</Text>\n\t\t\t\t\t{summary && (\n\t\t\t\t\t\t<Text style={styles.descriptionText} numberOfLines={1}>\n\t\t\t\t\t\t\t{summary}\n\t\t\t\t\t\t</Text>\n\t\t\t\t\t)}\n\t\t\t\t</View>\n\n\t\t\t\t{/* Chevron icon */}\n\t\t\t\t<View style={styles.chevronContainer}>\n\t\t\t\t\t<Icon\n\t\t\t\t\t\tname=\"chevron-right\"\n\t\t\t\t\t\ttype=\"font-awesome\"\n\t\t\t\t\t\tsize={14}\n\t\t\t\t\t\tcolor={Colours.TEXT_LIGHT}\n\t\t\t\t\t/>\n\t\t\t\t</View>\n\t\t\t</TouchableOpacity>\n\t\t);\n\t};\n\n\trenderContent() {\n\t\tconst { listings } = this.props;\n\n\t\t// Don't render widget if no listings are available (and not loading)\n\t\tif (_.isEmpty(listings) && !this.state.loading) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (_.isEmpty(listings)) {\n\t\t\tif (this.state.loading) {\n\t\t\t\treturn (\n\t\t\t\t\t<View style={styles.loadingPadding}>\n\t\t\t\t\t\t<Components.LoadingStateWidget height={300} />\n\t\t\t\t\t</View>\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\treturn (\n\t\t\t<ScrollView\n\t\t\t\tcontentContainerStyle={styles.featuresContainer}\n\t\t\t\tshowsVerticalScrollIndicator={false}\n\t\t\t>\n\t\t\t\t{listings.map((listing) => this.renderListingCard(listing))}\n\t\t\t</ScrollView>\n\t\t);\n\t}\n\n\trender() {\n\t\tconst { colourBrandingMain } = this.props;\n\n\t\tconst content = this.renderContent();\n\t\t// Don't render widget section if content is null (no features available)\n\t\tif (content === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn (\n\t\t\t<View style={styles.sectionContainer}>\n\t\t\t\t<View style={styles.sectionPadding}>\n\t\t\t\t\t<View style={styles.sectionHeading}>\n\t\t\t\t\t\t<Text style={styles.sectionTitle}>{this.getTitle()}</Text>\n\t\t\t\t\t</View>\n\t\t\t\t</View>\n\t\t\t\t{content}\n\t\t\t</View>\n\t\t);\n\t}\n}\n\nconst styles = StyleSheet.create({\n\tsectionContainer: {\n\t\tbackgroundColor: \"#fff\",\n\t\tflex: 1,\n\t},\n\tsectionPadding: {\n\t\tpaddingHorizontal: SPACING.MD,\n\t\tpaddingBottom: SPACING.XS + 2,\n\t\tpaddingTop: SPACING.MD,\n\t},\n\tloadingPadding: {\n\t\tpaddingHorizontal: SPACING.MD,\n\t},\n\tsectionHeading: {\n\t\tmarginBottom: SPACING.MD,\n\t},\n\tsectionTitle: {\n\t\tfontFamily: \"sf-bold\",\n\t\tfontSize: 24,\n\t\tcolor: \"#000\",\n\t},\n\tfeaturesContainer: {\n\t\tpaddingHorizontal: SPACING.MD,\n\t\tpaddingBottom: SPACING.MD,\n\t},\n\t// Listing item styles (similar to CondensedListItem)\n\tlistItem: {\n\t\tflexDirection: \"row\",\n\t\talignItems: \"center\",\n\t\tpaddingHorizontal: 16,\n\t\tpaddingVertical: 8,\n\t\tbackgroundColor: \"#fff\",\n\t},\n\tavatarContainer: {\n\t\twidth: 40,\n\t\theight: 40,\n\t\tborderRadius: 20,\n\t\tmarginRight: 12,\n\t},\n\tavatar: {\n\t\twidth: 40,\n\t\theight: 40,\n\t\tborderRadius: 20,\n\t\tbackgroundColor: Colours.BACKGROUND_LIGHT || \"#f0f0f0\",\n\t},\n\tplaceholderAvatar: {\n\t\tbackgroundColor: Colours.BACKGROUND_LIGHT || \"#f0f0f0\",\n\t\tjustifyContent: \"center\",\n\t\talignItems: \"center\",\n\t},\n\ttextContainer: {\n\t\tflex: 1,\n\t\tjustifyContent: \"center\",\n\t},\n\ttitleText: {\n\t\tfontFamily: \"sf-semibold\",\n\t\tfontSize: 16,\n\t\tcolor: Colours.TEXT_DARK || \"#333\",\n\t\tmarginBottom: 2,\n\t},\n\tdescriptionText: {\n\t\tfontFamily: \"sf-regular\",\n\t\tfontSize: 14,\n\t\tcolor: Colours.TEXT_LIGHT || \"#666\",\n\t\tlineHeight: 18,\n\t},\n\tchevronContainer: {\n\t\tpaddingLeft: 8,\n\t},\n});\n\nconst mapStateToProps = (state) => {\n\tconst { user, notifications } = state;\n\n\treturn {\n\t\tcolourBrandingMain: getMainBrandingColourFromState(state),\n\t\tlistings: selectListings(state),\n\t\tfeatureDefinition: selectFeatureDefinition(state),\n\t\tsite: user.site,\n\t\tdataUpdated: notifications.dataUpdated[values.notificationKey],\n\t\tstrings: state.strings?.config || {},\n\t};\n};\n\nexport default connect(mapStateToProps, null, null, { forwardRef: true })(\n\tWidgetLarge,\n);\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
2
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
3
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
4
|
+
import React, { Component } from "react";
|
|
5
|
+
import { Text, View, ScrollView, StyleSheet, TouchableOpacity, Image } from "react-native";
|
|
6
|
+
import { connect } from "react-redux";
|
|
7
|
+
import _ from "lodash";
|
|
8
|
+
import { Icon } from "react-native-elements";
|
|
9
|
+
import { Services } from "../feature.config";
|
|
10
|
+
import { Components, Colours } from "../core.config";
|
|
11
|
+
import { values } from "../values.config";
|
|
12
|
+
import { selectListings, selectFeatureDefinition } from "../reducers/featureBuilderReducer";
|
|
13
|
+
import { SPACING } from "../js/spacing";
|
|
14
|
+
import { getMainBrandingColourFromState } from "../js";
|
|
15
|
+
import { getSummaryFieldValue } from "../js/helpers";
|
|
16
|
+
class WidgetSmall extends Component {
|
|
17
|
+
constructor(props) {
|
|
18
|
+
super(props);
|
|
19
|
+
_defineProperty(this, "getTitle", () => {
|
|
20
|
+
const {
|
|
21
|
+
options,
|
|
22
|
+
featureDefinition
|
|
23
|
+
} = this.props;
|
|
24
|
+
if (options && !_.isEmpty(options.Title)) return options.Title;
|
|
25
|
+
// Use feature definition title
|
|
26
|
+
if (featureDefinition !== null && featureDefinition !== void 0 && featureDefinition.title || featureDefinition !== null && featureDefinition !== void 0 && featureDefinition.displayName) {
|
|
27
|
+
return featureDefinition.title || featureDefinition.displayName;
|
|
28
|
+
}
|
|
29
|
+
return values.featureName || "Features";
|
|
30
|
+
});
|
|
31
|
+
_defineProperty(this, "getEmptyStateText", () => {
|
|
32
|
+
const {
|
|
33
|
+
options
|
|
34
|
+
} = this.props;
|
|
35
|
+
if (options && !_.isEmpty(options.EmptyText)) return options.EmptyText;
|
|
36
|
+
return values.labels.emptyState;
|
|
37
|
+
});
|
|
38
|
+
_defineProperty(this, "refresh", () => {
|
|
39
|
+
this.onLoadingChanged(true, async () => {
|
|
40
|
+
try {
|
|
41
|
+
// Import actions dynamically to avoid circular dependencies
|
|
42
|
+
const {
|
|
43
|
+
initializeFeatureBuilder
|
|
44
|
+
} = await import("../actions/featureBuilderActions");
|
|
45
|
+
await initializeFeatureBuilder()(this.props.dispatch, () => this.props.getState);
|
|
46
|
+
} finally {
|
|
47
|
+
this.onLoadingChanged(false);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
_defineProperty(this, "onLoadingChanged", (loading, callback) => {
|
|
52
|
+
this.setState({
|
|
53
|
+
loading
|
|
54
|
+
}, () => {
|
|
55
|
+
if (this.props.onLoadingChanged) this.props.onLoadingChanged(this.state.loading);
|
|
56
|
+
if (callback) callback();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
_defineProperty(this, "onPressAll", () => {
|
|
60
|
+
Services.navigation.navigate(values.screens.featureList, {
|
|
61
|
+
options: this.props.options
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
_defineProperty(this, "getImageSource", imageField => {
|
|
65
|
+
if (!imageField) return null;
|
|
66
|
+
if (typeof imageField === "string") {
|
|
67
|
+
return {
|
|
68
|
+
uri: imageField
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (typeof imageField === "object" && imageField.uri) {
|
|
72
|
+
return imageField;
|
|
73
|
+
}
|
|
74
|
+
if (typeof imageField === "object" && imageField.url) {
|
|
75
|
+
return {
|
|
76
|
+
uri: imageField.url
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
});
|
|
81
|
+
_defineProperty(this, "onListingPress", listing => {
|
|
82
|
+
const {
|
|
83
|
+
featureDefinition
|
|
84
|
+
} = this.props;
|
|
85
|
+
const title = this.getTitle();
|
|
86
|
+
Services.navigation.navigate(values.screens.featureDetail, {
|
|
87
|
+
listing: listing,
|
|
88
|
+
featureDefinition: featureDefinition,
|
|
89
|
+
featureTitle: title
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
_defineProperty(this, "renderListingCard", listing => {
|
|
93
|
+
var _listing$fields, _listing$fields2;
|
|
94
|
+
const {
|
|
95
|
+
colourBrandingMain,
|
|
96
|
+
featureDefinition
|
|
97
|
+
} = this.props;
|
|
98
|
+
const title = ((_listing$fields = listing.fields) === null || _listing$fields === void 0 ? void 0 : _listing$fields[values.mandatoryFields.title]) || "Untitled";
|
|
99
|
+
const summary = getSummaryFieldValue(listing, featureDefinition);
|
|
100
|
+
const imageField = (_listing$fields2 = listing.fields) === null || _listing$fields2 === void 0 ? void 0 : _listing$fields2[values.mandatoryFields.featureImage];
|
|
101
|
+
const imageSource = this.getImageSource(imageField);
|
|
102
|
+
return /*#__PURE__*/React.createElement(TouchableOpacity, {
|
|
103
|
+
key: listing.id,
|
|
104
|
+
style: styles.cardContainer,
|
|
105
|
+
onPress: () => this.onListingPress(listing)
|
|
106
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
107
|
+
style: styles.borderContainer
|
|
108
|
+
}, imageSource ? /*#__PURE__*/React.createElement(Image, {
|
|
109
|
+
source: imageSource,
|
|
110
|
+
style: styles.cardImage,
|
|
111
|
+
resizeMode: "cover"
|
|
112
|
+
}) : /*#__PURE__*/React.createElement(View, {
|
|
113
|
+
style: [styles.cardImage, styles.placeholderImage]
|
|
114
|
+
}, /*#__PURE__*/React.createElement(Icon, {
|
|
115
|
+
name: "image",
|
|
116
|
+
type: "font-awesome",
|
|
117
|
+
size: 24,
|
|
118
|
+
color: Colours.TEXT_LIGHT
|
|
119
|
+
})), /*#__PURE__*/React.createElement(Text, {
|
|
120
|
+
style: styles.cardTitle,
|
|
121
|
+
numberOfLines: 1
|
|
122
|
+
}, title), summary && /*#__PURE__*/React.createElement(Text, {
|
|
123
|
+
style: styles.cardSummary,
|
|
124
|
+
numberOfLines: 1
|
|
125
|
+
}, summary)));
|
|
126
|
+
});
|
|
127
|
+
this.state = {
|
|
128
|
+
loading: false
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
componentDidMount() {
|
|
132
|
+
this.refresh();
|
|
133
|
+
}
|
|
134
|
+
componentDidUpdate(prevProps) {
|
|
135
|
+
if (!prevProps.dataUpdated && this.props.dataUpdated) {
|
|
136
|
+
this.refresh();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
renderContent() {
|
|
140
|
+
const {
|
|
141
|
+
listings
|
|
142
|
+
} = this.props;
|
|
143
|
+
|
|
144
|
+
// Don't render widget if no listings are available (and not loading)
|
|
145
|
+
if (_.isEmpty(listings) && !this.state.loading) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
if (_.isEmpty(listings)) {
|
|
149
|
+
if (this.state.loading) {
|
|
150
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
151
|
+
style: styles.loadingPadding
|
|
152
|
+
}, /*#__PURE__*/React.createElement(Components.LoadingStateWidget, {
|
|
153
|
+
height: 180
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Show first 3 listings with peeking indicator
|
|
160
|
+
const listingsToShow = listings.slice(0, values.widget.maxItems);
|
|
161
|
+
return /*#__PURE__*/React.createElement(ScrollView, {
|
|
162
|
+
horizontal: true,
|
|
163
|
+
contentContainerStyle: {
|
|
164
|
+
paddingLeft: SPACING.XS + 2,
|
|
165
|
+
paddingRight: SPACING.SM
|
|
166
|
+
},
|
|
167
|
+
showsHorizontalScrollIndicator: false
|
|
168
|
+
}, listingsToShow.map(listing => this.renderListingCard(listing)), listings.length > values.widget.maxItems && /*#__PURE__*/React.createElement(TouchableOpacity, {
|
|
169
|
+
style: [styles.cardContainer, styles.viewMoreCard],
|
|
170
|
+
onPress: this.onPressAll
|
|
171
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
172
|
+
style: [styles.borderContainer, styles.viewMoreContainer]
|
|
173
|
+
}, /*#__PURE__*/React.createElement(Text, {
|
|
174
|
+
style: styles.viewMoreText
|
|
175
|
+
}, "View all"), /*#__PURE__*/React.createElement(Text, {
|
|
176
|
+
style: styles.viewMoreCount
|
|
177
|
+
}, listings.length, " items"))));
|
|
178
|
+
}
|
|
179
|
+
render() {
|
|
180
|
+
const {
|
|
181
|
+
colourBrandingMain
|
|
182
|
+
} = this.props;
|
|
183
|
+
const content = this.renderContent();
|
|
184
|
+
// Don't render widget section if content is null (no features available)
|
|
185
|
+
if (content === null) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
189
|
+
style: styles.sectionContainer
|
|
190
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
191
|
+
style: styles.sectionPadding
|
|
192
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
193
|
+
style: styles.sectionHeading
|
|
194
|
+
}, /*#__PURE__*/React.createElement(Text, {
|
|
195
|
+
style: styles.sectionTitle
|
|
196
|
+
}, this.getTitle()), /*#__PURE__*/React.createElement(Components.InlineButton, {
|
|
197
|
+
onPress: this.onPressAll,
|
|
198
|
+
color: colourBrandingMain,
|
|
199
|
+
touchableStyle: {
|
|
200
|
+
paddingTop: SPACING.XS + 2
|
|
201
|
+
},
|
|
202
|
+
textStyle: {
|
|
203
|
+
color: "#fff"
|
|
204
|
+
}
|
|
205
|
+
}, values.labels.viewAll))), content);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const styles = StyleSheet.create({
|
|
209
|
+
sectionContainer: {
|
|
210
|
+
backgroundColor: "#fff",
|
|
211
|
+
paddingTop: SPACING.MD
|
|
212
|
+
},
|
|
213
|
+
sectionPadding: {
|
|
214
|
+
paddingHorizontal: SPACING.MD,
|
|
215
|
+
paddingBottom: SPACING.XS + 2
|
|
216
|
+
},
|
|
217
|
+
loadingPadding: {
|
|
218
|
+
paddingHorizontal: SPACING.MD
|
|
219
|
+
},
|
|
220
|
+
sectionHeading: {
|
|
221
|
+
marginBottom: SPACING.XS,
|
|
222
|
+
flexDirection: "row",
|
|
223
|
+
alignContent: "flex-start",
|
|
224
|
+
justifyContent: "space-between"
|
|
225
|
+
},
|
|
226
|
+
sectionTitle: {
|
|
227
|
+
fontFamily: "sf-bold",
|
|
228
|
+
fontSize: 24,
|
|
229
|
+
color: "#000"
|
|
230
|
+
},
|
|
231
|
+
// Listing card styles
|
|
232
|
+
cardContainer: {
|
|
233
|
+
marginRight: SPACING.SM + 4,
|
|
234
|
+
width: values.widget.itemMaxWidth
|
|
235
|
+
},
|
|
236
|
+
borderContainer: {
|
|
237
|
+
borderRadius: SPACING.SM,
|
|
238
|
+
backgroundColor: "#fff",
|
|
239
|
+
shadowColor: "#000",
|
|
240
|
+
shadowOffset: {
|
|
241
|
+
width: 0,
|
|
242
|
+
height: 2
|
|
243
|
+
},
|
|
244
|
+
shadowOpacity: 0.1,
|
|
245
|
+
shadowRadius: 3.84,
|
|
246
|
+
elevation: 4,
|
|
247
|
+
padding: SPACING.SM,
|
|
248
|
+
minHeight: values.widget.itemMinWidth
|
|
249
|
+
},
|
|
250
|
+
cardImage: {
|
|
251
|
+
width: 88,
|
|
252
|
+
height: 88,
|
|
253
|
+
borderRadius: 44,
|
|
254
|
+
backgroundColor: "#f0f0f0",
|
|
255
|
+
alignSelf: "center",
|
|
256
|
+
marginBottom: SPACING.XS
|
|
257
|
+
},
|
|
258
|
+
placeholderImage: {
|
|
259
|
+
justifyContent: "center",
|
|
260
|
+
alignItems: "center",
|
|
261
|
+
backgroundColor: "#f0f0f0"
|
|
262
|
+
},
|
|
263
|
+
cardTitle: {
|
|
264
|
+
fontFamily: "sf-semibold",
|
|
265
|
+
fontSize: 14,
|
|
266
|
+
color: "#000",
|
|
267
|
+
textAlign: "center",
|
|
268
|
+
marginBottom: 4
|
|
269
|
+
},
|
|
270
|
+
cardSummary: {
|
|
271
|
+
fontFamily: "sf-regular",
|
|
272
|
+
fontSize: 12,
|
|
273
|
+
color: "#666",
|
|
274
|
+
textAlign: "center"
|
|
275
|
+
},
|
|
276
|
+
// View more card
|
|
277
|
+
viewMoreCard: {
|
|
278
|
+
justifyContent: "center"
|
|
279
|
+
},
|
|
280
|
+
viewMoreContainer: {
|
|
281
|
+
justifyContent: "center",
|
|
282
|
+
alignItems: "center",
|
|
283
|
+
minHeight: values.widget.itemMinWidth
|
|
284
|
+
},
|
|
285
|
+
viewMoreText: {
|
|
286
|
+
fontFamily: "sf-semibold",
|
|
287
|
+
fontSize: 14,
|
|
288
|
+
color: Colours.TEXT_DARK || "#000"
|
|
289
|
+
},
|
|
290
|
+
viewMoreCount: {
|
|
291
|
+
fontFamily: "sf-regular",
|
|
292
|
+
fontSize: 12,
|
|
293
|
+
color: "#666",
|
|
294
|
+
marginTop: 2
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
const mapStateToProps = state => {
|
|
298
|
+
var _state$strings;
|
|
299
|
+
const {
|
|
300
|
+
user,
|
|
301
|
+
notifications
|
|
302
|
+
} = state;
|
|
303
|
+
return {
|
|
304
|
+
colourBrandingMain: getMainBrandingColourFromState(state),
|
|
305
|
+
listings: selectListings(state),
|
|
306
|
+
featureDefinition: selectFeatureDefinition(state),
|
|
307
|
+
site: user.site,
|
|
308
|
+
dataUpdated: notifications.dataUpdated[values.notificationKey],
|
|
309
|
+
strings: ((_state$strings = state.strings) === null || _state$strings === void 0 ? void 0 : _state$strings.config) || {}
|
|
310
|
+
};
|
|
311
|
+
};
|
|
312
|
+
export default connect(mapStateToProps, null, null, {
|
|
313
|
+
forwardRef: true
|
|
314
|
+
})(WidgetSmall);
|
|
315
|
+
//# sourceMappingURL=WidgetSmall.js.map
|