disco_app 0.8.9 → 0.9.0
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.
- checksums.yaml +4 -4
- data/app/assets/images/disco_app/icons.svg +0 -0
- data/app/assets/javascripts/disco_app/components/{filterable_shop_list.js.jsx → custom/filterable_shop_list.js.jsx} +1 -1
- data/app/assets/javascripts/disco_app/components/custom/inline-radio-options.es6.jsx +59 -0
- data/app/assets/javascripts/disco_app/components/custom/rules-editor.es6.jsx +360 -0
- data/app/assets/javascripts/disco_app/components/{shop_list.js.jsx → custom/shop_list.js.jsx} +9 -11
- data/app/assets/javascripts/disco_app/components/custom/shop_row.js.jsx +43 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/cards/card-section.es6.jsx +30 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/cards/card.es6.jsx +9 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/cards/cart-section-title.es6.jsx +7 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/base_form.es6.jsx +72 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/base_input.es6.jsx +20 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/button.es6.jsx +13 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-radio.es6.jsx +30 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-select.es6.jsx +39 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-text.es6.jsx +59 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-textarea.es6.jsx +48 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/icons/icon-chevron.es6.jsx +33 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/icons/next-icon.es6.jsx +18 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/input_select.es6.jsx +21 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-annotated-section.es6.jsx +29 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-empty-state.es6.jsx +35 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-footer-help.es6.jsx +13 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-page-actions.es6.jsx +39 -0
- data/app/assets/javascripts/disco_app/components.js +1 -4
- data/app/assets/javascripts/disco_app/disco_app.js +3 -0
- data/app/assets/javascripts/disco_app/ui-kit.js +1 -0
- data/app/assets/stylesheets/disco_app/admin/_header.scss +66 -0
- data/app/assets/stylesheets/disco_app/admin/_layout.scss +40 -0
- data/app/assets/stylesheets/disco_app/admin/_nav.scss +172 -0
- data/app/assets/stylesheets/disco_app/admin.scss +11 -0
- data/app/assets/stylesheets/disco_app/disco_app.scss +12 -12
- data/app/assets/stylesheets/disco_app/{disco/mixins → mixins}/_flexbox.scss +6 -0
- data/app/assets/stylesheets/disco_app/ui-kit/_ui-empty-state.scss +94 -0
- data/app/assets/stylesheets/disco_app/ui-kit/_ui-footer-help.scss +25 -0
- data/app/assets/stylesheets/disco_app/ui-kit/_ui-icons.scss +28 -0
- data/app/assets/stylesheets/disco_app/ui-kit/_ui-kit.scss +5086 -0
- data/app/assets/stylesheets/disco_app/ui-kit/_ui-layout.scss +10 -0
- data/app/assets/stylesheets/disco_app/ui-kit/_ui-page-actions.scss +21 -0
- data/app/assets/stylesheets/disco_app/{disco/_tabs.scss → ui-kit/_ui-tabs.scss} +3 -1
- data/app/assets/stylesheets/disco_app/ui-kit/_ui-type.scss +13 -0
- data/app/controllers/disco_app/admin/concerns/plans_controller.rb +8 -5
- data/app/controllers/disco_app/admin/concerns/subscriptions_controller.rb +32 -0
- data/app/controllers/disco_app/admin/subscriptions_controller.rb +3 -0
- data/app/helpers/disco_app/application_helper.rb +22 -0
- data/app/models/disco_app/concerns/plan.rb +2 -2
- data/app/models/disco_app/concerns/shop.rb +0 -4
- data/app/models/disco_app/concerns/subscription.rb +12 -0
- data/app/resources/disco_app/admin/resources/concerns/shop_resource.rb +40 -3
- data/app/views/disco_app/admin/plans/_form.html.erb +18 -21
- data/app/views/disco_app/admin/plans/_plan_code_fields.html.erb +15 -0
- data/app/views/disco_app/admin/plans/index.html.erb +2 -0
- data/app/views/disco_app/admin/shops/index.html.erb +2 -1
- data/app/views/disco_app/admin/subscriptions/edit.html.erb +33 -0
- data/app/views/disco_app/shared/_icons.html.erb +3 -0
- data/app/views/layouts/admin/_nav_items.erb +20 -0
- data/app/views/layouts/admin.html.erb +53 -9
- data/app/views/layouts/embedded_app.html.erb +2 -0
- data/app/views/layouts/embedded_app_modal.html.erb +11 -0
- data/config/routes.rb +4 -2
- data/lib/disco_app/engine.rb +2 -1
- data/lib/disco_app/version.rb +1 -1
- data/lib/generators/disco_app/disco_app_generator.rb +35 -2
- data/lib/generators/disco_app/templates/assets/javascripts/components.js +3 -0
- data/lib/generators/disco_app/templates/config/database.yml.tt +20 -0
- data/lib/tasks/database.rake +8 -0
- data/test/controllers/disco_app/charges_controller_test.rb +9 -2
- data/test/fixtures/api/widget_store/charges/create_recurring_application_charge_request.json +1 -1
- data/test/fixtures/api/widget_store/charges/create_second_recurring_application_charge_request.json +1 -1
- data/test/fixtures/disco_app/subscriptions.yml +1 -0
- data/test/models/disco_app/subscription_test.rb +19 -0
- data/test/services/disco_app/charges_service_test.rb +9 -2
- data/test/test_helper.rb +3 -0
- metadata +80 -21
- data/app/assets/javascripts/disco_app/components/shop_row.js.jsx +0 -27
- data/app/assets/stylesheets/disco_app/bootstrap/_custom.scss +0 -54
- data/app/assets/stylesheets/disco_app/bootstrap/_variables.scss +0 -872
- data/app/assets/stylesheets/disco_app/disco/_buttons.scss +0 -31
- data/app/assets/stylesheets/disco_app/disco/_cards.scss +0 -52
- data/app/assets/stylesheets/disco_app/disco/_forms.scss +0 -23
- data/app/assets/stylesheets/disco_app/disco/_grid.scss +0 -58
- data/app/assets/stylesheets/disco_app/disco/_sections.scss +0 -61
- data/app/assets/stylesheets/disco_app/disco/_tables.scss +0 -57
- data/app/assets/stylesheets/disco_app/disco/_type.scss +0 -39
- data/app/views/layouts/admin/_navbar.html.erb +0 -25
- data/lib/generators/disco_app/adminify/adminify_generator.rb +0 -35
- data/lib/generators/disco_app/reactify/reactify_generator.rb +0 -45
- /data/app/assets/javascripts/disco_app/components/{shop_filter_tab.js.jsx → custom/shop_filter_tab.js.jsx} +0 -0
- /data/app/assets/javascripts/disco_app/components/{shop_filter_tabs.js.jsx → custom/shop_filter_tabs.js.jsx} +0 -0
- /data/app/assets/javascripts/disco_app/components/{shopify_admin_link.js.jsx → custom/shopify_admin_link.js.jsx} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d734e517357675c9fec94abcfe6fd509c04f6f31c9bdcc8a762c3971f11589d3
|
|
4
|
+
data.tar.gz: 5d2dd2d731d021adc3fbdc5e37af68df9f2c013083ad10980dd5ed2707842e8b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 57d5072e2eb9d1b6b12ab45aeeb77b253e3fdf8aad36d993ec9799f8fa61de4ae1c9212e5b25c49304f54d6892d594b7befad0f1851fc6578f52e09c82d47e55
|
|
7
|
+
data.tar.gz: 02b898b139e5d707dd30680559f3abf459c51ca6c652f626449af2721b449997ab9871b0f933ae38c61e925fdecd45cf7db467ee58f7f0418fb5075178c6e693
|
|
File without changes
|
|
@@ -52,7 +52,7 @@ var FilterableShopList = React.createClass({
|
|
|
52
52
|
return (
|
|
53
53
|
<div className="next-card">
|
|
54
54
|
<ShopFilterTabs filterTabs={this.props.filterTabs} filter={this.state.filter} onFilterReplace={this.onFilterReplace} />
|
|
55
|
-
<ShopList shopsUrl={this.props.shopsUrl} editShopUrl={this.props.editShopUrl} filter={this.state.filter} />
|
|
55
|
+
<ShopList shopsUrl={this.props.shopsUrl} editShopUrl={this.props.editShopUrl} editSubscriptionUrl={this.props.editSubscriptionUrl} filter={this.state.filter} />
|
|
56
56
|
</div>
|
|
57
57
|
);
|
|
58
58
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
class InlineRadioOptions extends React.Component {
|
|
2
|
+
|
|
3
|
+
constructor(props) {
|
|
4
|
+
super(props);
|
|
5
|
+
this.state = {
|
|
6
|
+
value: props.value
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
onChange(value) {
|
|
11
|
+
this.setState({
|
|
12
|
+
value: value
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
render() {
|
|
17
|
+
const { name, label, options } = this.props;
|
|
18
|
+
|
|
19
|
+
const optionElements = options.map((option, optionIndex) => {
|
|
20
|
+
return (
|
|
21
|
+
<InputRadio
|
|
22
|
+
key={option.value}
|
|
23
|
+
name={name}
|
|
24
|
+
value={option.value}
|
|
25
|
+
label={option.label}
|
|
26
|
+
inline={true}
|
|
27
|
+
isLast={optionIndex === (options.length - 1)}
|
|
28
|
+
checked={option.value === this.state.value}
|
|
29
|
+
onChange={this.onChange.bind(this)}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<CardSection wrappable={true}>
|
|
36
|
+
<div className="wrappable__item wrappable__item--no-flex">
|
|
37
|
+
<span>{label}</span>
|
|
38
|
+
</div>
|
|
39
|
+
<div className="wrappable__item">
|
|
40
|
+
{optionElements}
|
|
41
|
+
</div>
|
|
42
|
+
</CardSection>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
InlineRadioOptions.propTypes = {
|
|
49
|
+
name: React.PropTypes.string,
|
|
50
|
+
options: React.PropTypes.arrayOf(
|
|
51
|
+
React.PropTypes.shape({
|
|
52
|
+
label: React.PropTypes.string.isRequired,
|
|
53
|
+
value: React.PropTypes.oneOfType([
|
|
54
|
+
React.PropTypes.string,
|
|
55
|
+
React.PropTypes.bool
|
|
56
|
+
]).isRequired
|
|
57
|
+
})
|
|
58
|
+
).isRequired
|
|
59
|
+
};
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defines a generic RulesEditor class. This class can't be used directly, but
|
|
3
|
+
* should be inherited, with the inheriting class defining a list of column
|
|
4
|
+
* types and correponding relations and condition data types, like so:
|
|
5
|
+
*
|
|
6
|
+
* class MyRulesEditor extends RulesEditor {};
|
|
7
|
+
* MyRulesEditor.defaultProps = {
|
|
8
|
+
* columns: {
|
|
9
|
+
* title: {
|
|
10
|
+
* label: 'Product title',
|
|
11
|
+
* column: 'title',
|
|
12
|
+
* relations: {
|
|
13
|
+
* is_equal_to: {
|
|
14
|
+
* label: 'is equal to',
|
|
15
|
+
* relation: 'is_equal_to',
|
|
16
|
+
* type: 'text'
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
class RulesEditor extends React.Component {
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Initialise the Rules Editor, and set the initial state.
|
|
26
|
+
* @param props
|
|
27
|
+
*/
|
|
28
|
+
constructor(props) {
|
|
29
|
+
super(props);
|
|
30
|
+
this.state = {
|
|
31
|
+
rules: props.rules.map((rule, i) => {
|
|
32
|
+
return {
|
|
33
|
+
column: Object.keys(this.props.columns).filter((columnKey) => {
|
|
34
|
+
return this.props.columns[columnKey].column == rule.column;
|
|
35
|
+
})[0],
|
|
36
|
+
relation: rule.relation,
|
|
37
|
+
condition: rule.condition
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
componentDidMount() {
|
|
44
|
+
if(this.state.rules.length === 0 && this.props.blankOk === false) {
|
|
45
|
+
this.onAddRule();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Add a new rule, with an immutable state change.
|
|
51
|
+
*/
|
|
52
|
+
onAddRule() {
|
|
53
|
+
const column = Object.keys(this.props.columns)[0];
|
|
54
|
+
const relation = this.getNextRelation(column);
|
|
55
|
+
const condition = this.getNextCondition(column, relation);
|
|
56
|
+
|
|
57
|
+
this.setState({
|
|
58
|
+
rules: this.state.rules.concat([{
|
|
59
|
+
column,
|
|
60
|
+
relation,
|
|
61
|
+
condition
|
|
62
|
+
}])
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Remove a rule, with an immutable state change.
|
|
68
|
+
*/
|
|
69
|
+
onRemoveRule(index) {
|
|
70
|
+
this.setState({
|
|
71
|
+
rules: [
|
|
72
|
+
...this.state.rules.slice(0, index),
|
|
73
|
+
...this.state.rules.slice(index + 1)
|
|
74
|
+
]
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Handle a change in a rule's column attribute.
|
|
80
|
+
*
|
|
81
|
+
* @param index
|
|
82
|
+
* @param column
|
|
83
|
+
*/
|
|
84
|
+
onRuleColumnChange(index, column) {
|
|
85
|
+
const relation = this.getNextRelation(column, this.state.rules[index]);
|
|
86
|
+
const condition = this.getNextCondition(column, relation, this.state.rules[index]);
|
|
87
|
+
|
|
88
|
+
this.updateRule(index, {
|
|
89
|
+
column,
|
|
90
|
+
relation,
|
|
91
|
+
condition
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Handle a change in a rule's relation attribute.
|
|
97
|
+
*
|
|
98
|
+
* @param index
|
|
99
|
+
* @param relation
|
|
100
|
+
*/
|
|
101
|
+
onRuleRelationChange(index, relation) {
|
|
102
|
+
const condition = this.getNextCondition(this.state.rules[index].column, relation, this.state.rules[index]);
|
|
103
|
+
|
|
104
|
+
this.updateRule(index, {
|
|
105
|
+
relation,
|
|
106
|
+
condition
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Handle a change in a rule's condition attribute.
|
|
112
|
+
*
|
|
113
|
+
* @param index
|
|
114
|
+
* @param condition
|
|
115
|
+
*/
|
|
116
|
+
onRuleConditionChange(index, condition) {
|
|
117
|
+
this.updateRule(index, {
|
|
118
|
+
condition
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Given the column we're changing to and the current rule, return the next
|
|
124
|
+
* relation value.
|
|
125
|
+
*
|
|
126
|
+
* @param nextColumn
|
|
127
|
+
* @param currentRule
|
|
128
|
+
*/
|
|
129
|
+
getNextRelation(nextColumn, currentRule) {
|
|
130
|
+
// If the new column provides for the same relation, keep it.
|
|
131
|
+
if(currentRule && (this.props.columns[nextColumn].relations[currentRule.relation] !== undefined)) {
|
|
132
|
+
return currentRule.relation;
|
|
133
|
+
}
|
|
134
|
+
// Otherwise, return the first relation for the new column.
|
|
135
|
+
return Object.keys(this.props.columns[nextColumn].relations)[0];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Given the column and relation we're changing to and the current condition,
|
|
140
|
+
* return the value that the condition should be changed to.
|
|
141
|
+
*
|
|
142
|
+
* @param nextColumn
|
|
143
|
+
* @param nextRelation
|
|
144
|
+
* @param currentRule
|
|
145
|
+
*/
|
|
146
|
+
getNextCondition(nextColumn, nextRelation, currentRule) {
|
|
147
|
+
// If the new relation provides for the same condition type, keep it.
|
|
148
|
+
if(currentRule) {
|
|
149
|
+
const currentConditionType = this.props.columns[currentRule.column].relations[currentRule.relation].type;
|
|
150
|
+
const nextConditionType = this.props.columns[nextColumn].relations[nextRelation].type;
|
|
151
|
+
|
|
152
|
+
if(currentConditionType === nextConditionType) {
|
|
153
|
+
return currentRule.condition;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Otherwise, reset the condition to an empty string.
|
|
158
|
+
return '';
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Handle the updating of a rule in our array in an immutable manner.
|
|
163
|
+
*
|
|
164
|
+
* @param index
|
|
165
|
+
* @param updates
|
|
166
|
+
*/
|
|
167
|
+
updateRule(index, updates) {
|
|
168
|
+
this.setState({
|
|
169
|
+
rules: [
|
|
170
|
+
...this.state.rules.slice(0, index),
|
|
171
|
+
Object.assign({}, this.state.rules[index], updates),
|
|
172
|
+
...this.state.rules.slice(index + 1)
|
|
173
|
+
]
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Render the Rules Editor.
|
|
179
|
+
*/
|
|
180
|
+
render() {
|
|
181
|
+
const { name } = this.props;
|
|
182
|
+
const { rules } = this.state;
|
|
183
|
+
|
|
184
|
+
const ruleElements = rules.map((rule, i) => {
|
|
185
|
+
return <RulesEditorRule
|
|
186
|
+
key={i}
|
|
187
|
+
rule={rule}
|
|
188
|
+
columns={this.props.columns}
|
|
189
|
+
onRemove={this.onRemoveRule.bind(this, i)}
|
|
190
|
+
onColumnChange={this.onRuleColumnChange.bind(this, i)}
|
|
191
|
+
onRelationChange={this.onRuleRelationChange.bind(this, i)}
|
|
192
|
+
onConditionChange={this.onRuleConditionChange.bind(this, i)}
|
|
193
|
+
ruleCount={rules.length}
|
|
194
|
+
blankOk = {this.props.blankOk}
|
|
195
|
+
/>
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Convert the current rules JSON into a format using the correct column
|
|
199
|
+
// format used by our more advanced key checker.
|
|
200
|
+
const rulesJSON = JSON.stringify(this.state.rules.map((rule, i) => {
|
|
201
|
+
return {
|
|
202
|
+
column: this.props.columns[rule.column].column,
|
|
203
|
+
relation: rule.relation,
|
|
204
|
+
condition: rule.condition
|
|
205
|
+
}
|
|
206
|
+
}));
|
|
207
|
+
|
|
208
|
+
return(
|
|
209
|
+
<CardSection>
|
|
210
|
+
<div className="next-grid next-grid--no-outside-padding">
|
|
211
|
+
<div style={{ width: '100%'}}>
|
|
212
|
+
{ruleElements}
|
|
213
|
+
</div>
|
|
214
|
+
</div>
|
|
215
|
+
<Button onClick={this.onAddRule.bind(this)}>
|
|
216
|
+
Add another condition
|
|
217
|
+
</Button>
|
|
218
|
+
<input type="hidden" name={name} value={rulesJSON} />
|
|
219
|
+
</CardSection>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
static buildRelationsObj(relations) {
|
|
224
|
+
var relationsObj = {};
|
|
225
|
+
|
|
226
|
+
relations.forEach(function (relation) {
|
|
227
|
+
return relationsObj[relation.relation] = relation;
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
return relationsObj;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
RulesEditor.EQUALS_STRING = {
|
|
237
|
+
label: 'is equal to',
|
|
238
|
+
relation: 'is_equal_to',
|
|
239
|
+
type: 'text'
|
|
240
|
+
};
|
|
241
|
+
RulesEditor.EQUALS_COUNTRY_CODE = {
|
|
242
|
+
label: 'is equal to',
|
|
243
|
+
relation: 'is_equal_to',
|
|
244
|
+
type: 'country_code'
|
|
245
|
+
};
|
|
246
|
+
RulesEditor.CONTAINS_STRING = {
|
|
247
|
+
label: 'contains',
|
|
248
|
+
relation: 'contains_string',
|
|
249
|
+
type: 'text'
|
|
250
|
+
};
|
|
251
|
+
RulesEditor.EQUALS_TAG = {
|
|
252
|
+
label: 'is equal to',
|
|
253
|
+
relation: 'find_in_set',
|
|
254
|
+
type: 'tag'
|
|
255
|
+
};
|
|
256
|
+
RulesEditor.GREATER_THAN = {
|
|
257
|
+
label: 'is greater than',
|
|
258
|
+
relation: 'is_greater_than',
|
|
259
|
+
type: 'numeric'
|
|
260
|
+
};
|
|
261
|
+
RulesEditor.LESS_THAN = {
|
|
262
|
+
label: 'is less than',
|
|
263
|
+
relation: 'is_less_than',
|
|
264
|
+
type: 'numeric'
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const RulesEditorRule = ({ rule, columns, onRemove, onColumnChange, onRelationChange, onConditionChange, ruleCount, blankOk }) => {
|
|
268
|
+
const { column, relation, condition } = rule;
|
|
269
|
+
|
|
270
|
+
const currentColumn = columns[column];
|
|
271
|
+
const currentRelation = currentColumn.relations[relation];
|
|
272
|
+
|
|
273
|
+
let conditionEditor = null;
|
|
274
|
+
switch(currentRelation.type) {
|
|
275
|
+
case 'text':
|
|
276
|
+
case 'numeric':
|
|
277
|
+
case 'tag':
|
|
278
|
+
conditionEditor = <RulesEditorConditionInputText condition={condition} onChange={onConditionChange} />;
|
|
279
|
+
break;
|
|
280
|
+
case 'country_code':
|
|
281
|
+
conditionEditor = <RulesEditorConditionInputCountryCode condition={condition} onChange={onConditionChange} />;
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
let deleteIconCell = null;
|
|
286
|
+
if(ruleCount > 1 || blankOk === true) {
|
|
287
|
+
deleteIconCell = (
|
|
288
|
+
<div className="sl">
|
|
289
|
+
<button type="button" className="btn btn--icon" onClick={onRemove}>
|
|
290
|
+
<i className="ico ico-14-svg ico-delete" />
|
|
291
|
+
</button>
|
|
292
|
+
</div>
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return (
|
|
297
|
+
<div>
|
|
298
|
+
<div className="next-grid next-grid--no-padding next-grid--compact">
|
|
299
|
+
<div className="next-grid__cell">
|
|
300
|
+
<div className="next-grid next-grid--compact next-grid--no-outside-padding">
|
|
301
|
+
<div className="next-grid__cell">
|
|
302
|
+
<RulesEditorColumnSelect currentColumnName={column} columns={columns} onChange={onColumnChange} />
|
|
303
|
+
</div>
|
|
304
|
+
<div className="next-grid__cell">
|
|
305
|
+
<RulesEditorRelationSelect currentRelationName={relation} relations={currentColumn.relations} onChange={onRelationChange} />
|
|
306
|
+
</div>
|
|
307
|
+
<div className="next-grid__cell">
|
|
308
|
+
{conditionEditor}
|
|
309
|
+
</div>
|
|
310
|
+
</div>
|
|
311
|
+
</div>
|
|
312
|
+
{deleteIconCell}
|
|
313
|
+
</div>
|
|
314
|
+
<hr className="next-card__section__separator" />
|
|
315
|
+
</div>
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
const RulesEditorColumnSelect = ({ currentColumnName, columns, onChange }) => {
|
|
321
|
+
const options = Object.keys(columns).map((columnName) => {
|
|
322
|
+
return { label: columns[columnName].label, value: columnName }
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
return <InputSelect options={options} value={currentColumnName} onChange={onChange} label="Field" labelHidden={true} />;
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const RulesEditorRelationSelect = ({ currentRelationName, relations, onChange }) => {
|
|
329
|
+
const options = Object.keys(relations).map((relationName) => {
|
|
330
|
+
return { label: relations[relationName].label, value: relationName }
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
return <InputSelect options={options} value={currentRelationName} onChange={onChange} label="Relation" labelHidden={true} />;
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const RulesEditorConditionInputText = ({ condition, onChange }) => {
|
|
337
|
+
|
|
338
|
+
const handleChange = (e) => {
|
|
339
|
+
onChange && onChange(e);
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
return (
|
|
343
|
+
<InputText value={condition} onChange={handleChange} label="Value" labelHidden={true} />
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
const RulesEditorConditionInputCountryCode = ({ condition, onChange }) => {
|
|
349
|
+
|
|
350
|
+
const handleChange = (e) => {
|
|
351
|
+
onChange && onChange(e);
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
const countryOptions = [{"label":"Australia","value":"AU"},{"label":"Canada","value":"CA"},{"label":"United Kingdom","value":"GB"},{"label":"United States","value":"US"},{"label":"Afghanistan","value":"AF"},{"label":"Åland Islands","value":"AX"},{"label":"Albania","value":"AL"},{"label":"Algeria","value":"DZ"},{"label":"Andorra","value":"AD"},{"label":"Angola","value":"AO"},{"label":"Anguilla","value":"AI"},{"label":"Antigua & Barbuda","value":"AG"},{"label":"Argentina","value":"AR"},{"label":"Armenia","value":"AM"},{"label":"Aruba","value":"AW"},{"label":"Australia","value":"AU"},{"label":"Austria","value":"AT"},{"label":"Azerbaijan","value":"AZ"},{"label":"Bahamas","value":"BS"},{"label":"Bahrain","value":"BH"},{"label":"Bangladesh","value":"BD"},{"label":"Barbados","value":"BB"},{"label":"Belarus","value":"BY"},{"label":"Belgium","value":"BE"},{"label":"Belize","value":"BZ"},{"label":"Benin","value":"BJ"},{"label":"Bermuda","value":"BM"},{"label":"Bhutan","value":"BT"},{"label":"Bolivia","value":"BO"},{"label":"Bosnia & Herzegovina","value":"BA"},{"label":"Botswana","value":"BW"},{"label":"Bouvet Island","value":"BV"},{"label":"Brazil","value":"BR"},{"label":"British Indian Ocean Territory","value":"IO"},{"label":"British Virgin Islands","value":"VG"},{"label":"Brunei","value":"BN"},{"label":"Bulgaria","value":"BG"},{"label":"Burkina Faso","value":"BF"},{"label":"Burundi","value":"BI"},{"label":"Cambodia","value":"KH"},{"label":"Cameroon","value":"CM"},{"label":"Canada","value":"CA"},{"label":"Cape Verde","value":"CV"},{"label":"Cayman Islands","value":"KY"},{"label":"Central African Republic","value":"CF"},{"label":"Chad","value":"TD"},{"label":"Chile","value":"CL"},{"label":"China","value":"CN"},{"label":"Christmas Island","value":"CX"},{"label":"Cocos (Keeling) Islands","value":"CC"},{"label":"Colombia","value":"CO"},{"label":"Comoros","value":"KM"},{"label":"Congo - Brazzaville","value":"CG"},{"label":"Congo - Kinshasa","value":"CD"},{"label":"Cook Islands","value":"CK"},{"label":"Costa Rica","value":"CR"},{"label":"Croatia","value":"HR"},{"label":"Cuba","value":"CU"},{"label":"Curaçao","value":"CW"},{"label":"Cyprus","value":"CY"},{"label":"Czech Republic","value":"CZ"},{"label":"Côte d’Ivoire","value":"CI"},{"label":"Denmark","value":"DK"},{"label":"Djibouti","value":"DJ"},{"label":"Dominica","value":"DM"},{"label":"Dominican Republic","value":"DO"},{"label":"Ecuador","value":"EC"},{"label":"Egypt","value":"EG"},{"label":"El Salvador","value":"SV"},{"label":"Equatorial Guinea","value":"GQ"},{"label":"Eritrea","value":"ER"},{"label":"Estonia","value":"EE"},{"label":"Ethiopia","value":"ET"},{"label":"Falkland Islands","value":"FK"},{"label":"Faroe Islands","value":"FO"},{"label":"Fiji","value":"FJ"},{"label":"Finland","value":"FI"},{"label":"France","value":"FR"},{"label":"French Guiana","value":"GF"},{"label":"French Polynesia","value":"PF"},{"label":"French Southern Territories","value":"TF"},{"label":"Gabon","value":"GA"},{"label":"Gambia","value":"GM"},{"label":"Georgia","value":"GE"},{"label":"Germany","value":"DE"},{"label":"Ghana","value":"GH"},{"label":"Gibraltar","value":"GI"},{"label":"Greece","value":"GR"},{"label":"Greenland","value":"GL"},{"label":"Grenada","value":"GD"},{"label":"Guadeloupe","value":"GP"},{"label":"Guatemala","value":"GT"},{"label":"Guernsey","value":"GG"},{"label":"Guinea","value":"GN"},{"label":"Guinea-Bissau","value":"GW"},{"label":"Guyana","value":"GY"},{"label":"Haiti","value":"HT"},{"label":"Heard & McDonald Islands","value":"HM"},{"label":"Honduras","value":"HN"},{"label":"Hong Kong SAR China","value":"HK"},{"label":"Hungary","value":"HU"},{"label":"Iceland","value":"IS"},{"label":"India","value":"IN"},{"label":"Indonesia","value":"ID"},{"label":"Iran","value":"IR"},{"label":"Iraq","value":"IQ"},{"label":"Ireland","value":"IE"},{"label":"Isle of Man","value":"IM"},{"label":"Israel","value":"IL"},{"label":"Italy","value":"IT"},{"label":"Jamaica","value":"JM"},{"label":"Japan","value":"JP"},{"label":"Jersey","value":"JE"},{"label":"Jordan","value":"JO"},{"label":"Kazakhstan","value":"KZ"},{"label":"Kenya","value":"KE"},{"label":"Kiribati","value":"KI"},{"label":"Kosovo","value":"KV"},{"label":"Kuwait","value":"KW"},{"label":"Kyrgyzstan","value":"KG"},{"label":"Laos","value":"LA"},{"label":"Latvia","value":"LV"},{"label":"Lebanon","value":"LB"},{"label":"Lesotho","value":"LS"},{"label":"Liberia","value":"LR"},{"label":"Libya","value":"LY"},{"label":"Liechtenstein","value":"LI"},{"label":"Lithuania","value":"LT"},{"label":"Luxembourg","value":"LU"},{"label":"Macau SAR China","value":"MO"},{"label":"Macedonia","value":"MK"},{"label":"Madagascar","value":"MG"},{"label":"Malawi","value":"MW"},{"label":"Malaysia","value":"MY"},{"label":"Maldives","value":"MV"},{"label":"Mali","value":"ML"},{"label":"Malta","value":"MT"},{"label":"Martinique","value":"MQ"},{"label":"Mauritania","value":"MR"},{"label":"Mauritius","value":"MU"},{"label":"Mayotte","value":"YT"},{"label":"Mexico","value":"MX"},{"label":"Moldova","value":"MD"},{"label":"Monaco","value":"MC"},{"label":"Mongolia","value":"MN"},{"label":"Montenegro","value":"ME"},{"label":"Montserrat","value":"MS"},{"label":"Morocco","value":"MA"},{"label":"Mozambique","value":"MZ"},{"label":"Myanmar (Burma)","value":"MM"},{"label":"Namibia","value":"NA"},{"label":"Nauru","value":"NR"},{"label":"Nepal","value":"NP"},{"label":"Netherlands","value":"NL"},{"label":"Netherlands Antilles","value":"AN"},{"label":"New Caledonia","value":"NC"},{"label":"New Zealand","value":"NZ"},{"label":"Nicaragua","value":"NI"},{"label":"Niger","value":"NE"},{"label":"Nigeria","value":"NG"},{"label":"Niue","value":"NU"},{"label":"Norfolk Island","value":"NF"},{"label":"North Korea","value":"KP"},{"label":"Norway","value":"NO"},{"label":"Oman","value":"OM"},{"label":"Pakistan","value":"PK"},{"label":"Palestinian Territories","value":"PS"},{"label":"Panama","value":"PA"},{"label":"Papua New Guinea","value":"PG"},{"label":"Paraguay","value":"PY"},{"label":"Peru","value":"PE"},{"label":"Philippines","value":"PH"},{"label":"Pitcairn Islands","value":"PN"},{"label":"Poland","value":"PL"},{"label":"Portugal","value":"PT"},{"label":"Qatar","value":"QA"},{"label":"Réunion","value":"RE"},{"label":"Romania","value":"RO"},{"label":"Russia","value":"RU"},{"label":"Rwanda","value":"RW"},{"label":"Samoa","value":"WS"},{"label":"San Marino","value":"SM"},{"label":"São Tomé & Príncipe","value":"ST"},{"label":"Saudi Arabia","value":"SA"},{"label":"Senegal","value":"SN"},{"label":"Serbia","value":"RS"},{"label":"Seychelles","value":"SC"},{"label":"Sierra Leone","value":"SL"},{"label":"Singapore","value":"SG"},{"label":"Sint Maarten","value":"SX"},{"label":"Slovakia","value":"SK"},{"label":"Slovenia","value":"SI"},{"label":"Solomon Islands","value":"SB"},{"label":"Somalia","value":"SO"},{"label":"South Africa","value":"ZA"},{"label":"South Georgia & South Sandwich Islands","value":"GS"},{"label":"South Korea","value":"KR"},{"label":"Spain","value":"ES"},{"label":"Sri Lanka","value":"LK"},{"label":"St. Barthélemy","value":"BL"},{"label":"St. Helena","value":"SH"},{"label":"St. Kitts & Nevis","value":"KN"},{"label":"St. Lucia","value":"LC"},{"label":"St. Martin","value":"MF"},{"label":"St. Pierre & Miquelon","value":"PM"},{"label":"St. Vincent & Grenadines","value":"VC"},{"label":"Sudan","value":"SD"},{"label":"Suriname","value":"SR"},{"label":"Svalbard & Jan Mayen","value":"SJ"},{"label":"Swaziland","value":"SZ"},{"label":"Sweden","value":"SE"},{"label":"Switzerland","value":"CH"},{"label":"Syria","value":"SY"},{"label":"Taiwan","value":"TW"},{"label":"Tajikistan","value":"TJ"},{"label":"Tanzania","value":"TZ"},{"label":"Thailand","value":"TH"},{"label":"Timor-Leste","value":"TL"},{"label":"Togo","value":"TG"},{"label":"Tokelau","value":"TK"},{"label":"Tonga","value":"TO"},{"label":"Trinidad & Tobago","value":"TT"},{"label":"Tunisia","value":"TN"},{"label":"Turkey","value":"TR"},{"label":"Turkmenistan","value":"TM"},{"label":"Turks & Caicos Islands","value":"TC"},{"label":"Tuvalu","value":"TV"},{"label":"U.S. Outlying Islands","value":"UM"},{"label":"Uganda","value":"UG"},{"label":"Ukraine","value":"UA"},{"label":"United Arab Emirates","value":"AE"},{"label":"United Kingdom","value":"GB"},{"label":"United States","value":"US"},{"label":"Uruguay","value":"UY"},{"label":"Uzbekistan","value":"UZ"},{"label":"Vanuatu","value":"VU"},{"label":"Vatican City","value":"VA"},{"label":"Venezuela","value":"VE"},{"label":"Vietnam","value":"VN"},{"label":"Wallis & Futuna","value":"WF"},{"label":"Western Sahara","value":"EH"},{"label":"Yemen","value":"YE"},{"label":"Zambia","value":"ZM"},{"label":"Zimbabwe","value":"ZW"}];
|
|
355
|
+
|
|
356
|
+
return (
|
|
357
|
+
<InputSelect options={countryOptions} value={condition} onChange={handleChange} label="Value" labelHidden={true} />
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
};
|
data/app/assets/javascripts/disco_app/components/{shop_list.js.jsx → custom/shop_list.js.jsx}
RENAMED
|
@@ -24,7 +24,7 @@ var ShopList = React.createClass({
|
|
|
24
24
|
|
|
25
25
|
componentDidUpdate: function (prevProps, prevState) {
|
|
26
26
|
if(prevProps.filter != this.props.filter) {
|
|
27
|
-
|
|
27
|
+
this.onShopsChanged();
|
|
28
28
|
}
|
|
29
29
|
if(prevState.page != this.state.page) {
|
|
30
30
|
this.getShops();
|
|
@@ -35,6 +35,7 @@ var ShopList = React.createClass({
|
|
|
35
35
|
this.setState({page: this.state.page + increment});
|
|
36
36
|
},
|
|
37
37
|
|
|
38
|
+
/* get shops with a different filter */
|
|
38
39
|
onShopsChanged: function() {
|
|
39
40
|
this.setState({page: 1});
|
|
40
41
|
this.getShops();
|
|
@@ -66,7 +67,7 @@ var ShopList = React.createClass({
|
|
|
66
67
|
var shopRows = this.state.shops.map(function(shop, index) {
|
|
67
68
|
if ((index >= ((this.state.page - 1) * this.props.pageSize)) && (index < this.state.page * this.props.pageSize)) {
|
|
68
69
|
return (
|
|
69
|
-
<ShopRow shop={shop} editShopUrl={this.props.editShopUrl} key={shop.id} />
|
|
70
|
+
<ShopRow shop={shop} editShopUrl={this.props.editShopUrl} editSubscriptionUrl={this.props.editSubscriptionUrl} key={shop.id} />
|
|
70
71
|
)
|
|
71
72
|
} else {
|
|
72
73
|
return null;
|
|
@@ -79,16 +80,13 @@ var ShopList = React.createClass({
|
|
|
79
80
|
<table className="table-hover expanded">
|
|
80
81
|
<thead>
|
|
81
82
|
<tr>
|
|
82
|
-
<th>
|
|
83
|
-
<th>Shopify Domain</th>
|
|
83
|
+
<th>Shop</th>
|
|
84
84
|
<th>Status</th>
|
|
85
|
-
<th>
|
|
86
|
-
<th>
|
|
87
|
-
<th>
|
|
88
|
-
<th>
|
|
89
|
-
<th>
|
|
90
|
-
<th>Created</th>
|
|
91
|
-
<th>Installed Duration</th>
|
|
85
|
+
<th>Country</th>
|
|
86
|
+
<th>Shopify Plan</th>
|
|
87
|
+
<th>Subscription</th>
|
|
88
|
+
<th>Source</th>
|
|
89
|
+
<th>Installed for</th>
|
|
92
90
|
</tr>
|
|
93
91
|
</thead>
|
|
94
92
|
<tbody>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
var ShopRow = (props) => {
|
|
2
|
+
|
|
3
|
+
var shop = props.shop,
|
|
4
|
+
editShopUrl = props.editShopUrl.replace(':id', shop.id),
|
|
5
|
+
domainName = shop.attributes['domain'],
|
|
6
|
+
countryName = shop.attributes['country-name'],
|
|
7
|
+
currency = shop.attributes['currency'],
|
|
8
|
+
planName = shop.attributes['plan-display-name'],
|
|
9
|
+
editSubscriptionUrl = props.editSubscriptionUrl
|
|
10
|
+
.replace(':shop_id', shop.id)
|
|
11
|
+
.replace(':id', shop.attributes['current-subscription-id']),
|
|
12
|
+
subscriptionPlan = shop.attributes['current-subscription-display-plan'],
|
|
13
|
+
subscriptionAmount = shop.attributes['current-subscription-display-amount'],
|
|
14
|
+
subscriptionSource = shop.attributes['current-subscription-source'],
|
|
15
|
+
installedDuration = shop.attributes['installed-duration'];
|
|
16
|
+
|
|
17
|
+
var subscriptionContent = null;
|
|
18
|
+
if(shop.attributes['current-subscription-id']) {
|
|
19
|
+
subscriptionContent = <a href={editSubscriptionUrl}>{subscriptionPlan} ({subscriptionAmount})</a>;
|
|
20
|
+
} else {
|
|
21
|
+
subscriptionContent = <span>{subscriptionPlan} ({subscriptionAmount})</span>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var planCodeContent = null;
|
|
25
|
+
if(shop.attributes['current-subscription-display-plan-code']) {
|
|
26
|
+
planCodeContent = <span><br />{shop.attributes['current-subscription-display-plan-code']}</span>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<tr>
|
|
31
|
+
<td>
|
|
32
|
+
<a href={editShopUrl}>{domainName}</a><br />
|
|
33
|
+
<a href={'mailto:' + shop.attributes.email}>{shop.attributes.email}</a>
|
|
34
|
+
</td>
|
|
35
|
+
<td>{shop.attributes.status}</td>
|
|
36
|
+
<td>{countryName}</td>
|
|
37
|
+
<td>{planName}</td>
|
|
38
|
+
<td>{subscriptionContent}{planCodeContent}</td>
|
|
39
|
+
<td>{subscriptionSource}</td>
|
|
40
|
+
<td>{installedDuration}</td>
|
|
41
|
+
</tr>
|
|
42
|
+
)
|
|
43
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const CardSection = ({ title, children, wrappable, borderless }) => {
|
|
2
|
+
|
|
3
|
+
const className = classNames({
|
|
4
|
+
'next-card__section': true,
|
|
5
|
+
'wrappable': wrappable,
|
|
6
|
+
'wrappable--half-spacing': wrappable,
|
|
7
|
+
'next-card__section--no-border': borderless,
|
|
8
|
+
'next-card__section--no-top-spacing': borderless
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const showTitle = () => {
|
|
12
|
+
if (title) {
|
|
13
|
+
return <CardSectionTitle title={title}/>;
|
|
14
|
+
} else {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div className={className}>
|
|
21
|
+
{showTitle()}
|
|
22
|
+
{children}
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
CardSection.propTypes = {
|
|
28
|
+
title: React.PropTypes.string,
|
|
29
|
+
children: React.PropTypes.node
|
|
30
|
+
};
|