@sprucelabs/spruce-feed-view-controllers 0.0.4 → 0.0.7

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.
@@ -2,3 +2,5 @@ import { SpruceSchemas } from '@sprucelabs/spruce-core-schemas';
2
2
  export declare type FeedPredicate = SpruceSchemas.Mercury.v2020_12_25.FeedPredicate;
3
3
  export declare type FeedItem = SpruceSchemas.Spruce.v2020_07_22.FeedItem;
4
4
  export declare type Feed = SpruceSchemas.Spruce.v2020_07_22.Feed;
5
+ export declare type CardSection = SpruceSchemas.HeartwoodViewControllers.v2021_02_11.CardSection;
6
+ export declare type Card = SpruceSchemas.HeartwoodViewControllers.v2021_02_11.Card;
File without changes
@@ -1,19 +1,48 @@
1
- import { AbstractViewController, CardViewController, SpruceSchemas, ViewControllerOptions } from '@sprucelabs/heartwood-view-controllers';
2
- import { FeedPredicate } from '../types';
3
- declare type Card = SpruceSchemas.HeartwoodViewControllers.v2021_02_11.Card;
4
- export declare type FeedCardViewControllerOptions = ViewControllerOptions & {
5
- id?: string;
6
- };
1
+ import { AbstractViewController, Authenticator, CardViewController, FormViewController, ViewControllerOptions } from '@sprucelabs/heartwood-view-controllers';
2
+ import { Card, FeedPredicate } from '../feed.types';
7
3
  export default class FeedCardViewController extends AbstractViewController<Card> {
8
4
  static id: string;
9
5
  private isLoaded;
10
6
  protected cardVc: CardViewController;
11
7
  private predicates;
12
- constructor(options: FeedCardViewControllerOptions);
8
+ protected formVc: FormViewController<MessageFormSchema>;
9
+ private shouldEnableChat;
10
+ private auth;
11
+ private sentMessageCount;
12
+ private pendingAddedMessages;
13
+ constructor(options: ViewControllerOptions & FeedCardViewControllerOptions);
14
+ private CardVc;
15
+ private FormVc;
16
+ private handleChangeForm;
17
+ private handleSubmitForm;
18
+ private setMessage;
19
+ private handleDidUpdateFeed;
20
+ private sendMessage;
21
+ private removeItem;
22
+ private pushItem;
23
+ private addSentMessage;
24
+ private getFeed;
13
25
  getIsLoaded(): boolean;
14
- load(predicates: FeedPredicate[]): Promise<void>;
26
+ load(options: {
27
+ predicates: FeedPredicate[];
28
+ authenticator: Authenticator;
29
+ }): Promise<void>;
15
30
  private refresh;
31
+ getShouldEnableChat(): boolean;
16
32
  private handleTryAgain;
17
- render(): SpruceSchemas.HeartwoodViewControllers.v2021_02_11.Card;
33
+ render(): import("@sprucelabs/heartwood-view-controllers").SpruceSchemas.HeartwoodViewControllers.v2021_02_11.Card;
18
34
  }
35
+ export declare type FeedCardViewControllerOptions = {
36
+ id?: string;
37
+ shouldEnableChat?: boolean;
38
+ };
39
+ declare const messageFormSchema: {
40
+ id: string;
41
+ fields: {
42
+ message: {
43
+ type: "text";
44
+ };
45
+ };
46
+ };
47
+ declare type MessageFormSchema = typeof messageFormSchema;
19
48
  export {};
@@ -7,34 +7,166 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { AbstractViewController, } from '@sprucelabs/heartwood-view-controllers';
11
- import { assertOptions } from '@sprucelabs/schema';
10
+ import { AbstractViewController, buildForm, } from '@sprucelabs/heartwood-view-controllers';
11
+ import { assertOptions, buildSchema } from '@sprucelabs/schema';
12
12
  export default class FeedCardViewController extends AbstractViewController {
13
13
  constructor(options) {
14
14
  super(options);
15
15
  this.isLoaded = false;
16
16
  this.predicates = [];
17
- this.cardVc = this.Controller('card', {
18
- id: options.id,
17
+ this.sentMessageCount = 0;
18
+ this.pendingAddedMessages = [];
19
+ const { shouldEnableChat } = options;
20
+ this.shouldEnableChat = !!shouldEnableChat;
21
+ this.formVc = this.FormVc();
22
+ this.cardVc = this.CardVc(options);
23
+ }
24
+ CardVc(options) {
25
+ const { id, shouldEnableChat } = options;
26
+ const sections = [
27
+ {
28
+ id: 'feed',
29
+ feed: {
30
+ items: [],
31
+ },
32
+ },
33
+ ];
34
+ if (shouldEnableChat) {
35
+ sections.push({
36
+ form: this.formVc.render(),
37
+ });
38
+ }
39
+ return this.Controller('card', {
40
+ id,
19
41
  body: {
20
42
  isBusy: true,
21
- sections: [
22
- {
23
- feed: {
24
- items: [],
43
+ sections,
44
+ },
45
+ });
46
+ }
47
+ FormVc() {
48
+ return this.Controller('form', buildForm({
49
+ id: 'message',
50
+ schema: messageFormSchema,
51
+ isEnabled: false,
52
+ onChange: this.handleChangeForm.bind(this),
53
+ onSubmit: this.handleSubmitForm.bind(this),
54
+ sections: [
55
+ {
56
+ fields: [
57
+ {
58
+ name: 'message',
59
+ renderAs: 'textarea',
60
+ },
61
+ ],
62
+ },
63
+ ],
64
+ shouldShowCancelButton: false,
65
+ }));
66
+ }
67
+ handleChangeForm() {
68
+ var _a;
69
+ return __awaiter(this, void 0, void 0, function* () {
70
+ const message = (_a = this.formVc.getValue('message')) !== null && _a !== void 0 ? _a : '';
71
+ if (message.length > 0) {
72
+ this.formVc.enable();
73
+ }
74
+ else {
75
+ this.formVc.disable();
76
+ }
77
+ });
78
+ }
79
+ handleSubmitForm() {
80
+ return __awaiter(this, void 0, void 0, function* () {
81
+ const message = this.formVc.getValue('message');
82
+ yield this.setMessage(null);
83
+ yield this.sendMessage(message);
84
+ });
85
+ }
86
+ setMessage(value) {
87
+ return __awaiter(this, void 0, void 0, function* () {
88
+ yield this.formVc.setValue('message', value);
89
+ });
90
+ }
91
+ handleDidUpdateFeed(item) {
92
+ const idx = this.pendingAddedMessages.indexOf(item.message);
93
+ if (idx === -1) {
94
+ this.pushItem(item);
95
+ }
96
+ else {
97
+ this.pendingAddedMessages.splice(idx, 1);
98
+ }
99
+ }
100
+ sendMessage(message) {
101
+ var _a;
102
+ return __awaiter(this, void 0, void 0, function* () {
103
+ const added = this.addSentMessage(message);
104
+ const client = yield this.connectToApi();
105
+ try {
106
+ yield client.emitAndFlattenResponses('send-message::v2020_12_25', {
107
+ payload: {
108
+ message: {
109
+ body: message,
110
+ classification: 'transactional',
25
111
  },
26
112
  },
27
- ],
28
- },
113
+ });
114
+ this.pendingAddedMessages.push(message);
115
+ }
116
+ catch (err) {
117
+ this.removeItem(added.id);
118
+ yield this.setMessage(added.message);
119
+ yield this.alert({
120
+ title: 'Failed to send message!',
121
+ message: err.message,
122
+ });
123
+ console.error((_a = err.stack) !== null && _a !== void 0 ? _a : err.message);
124
+ }
29
125
  });
30
126
  }
127
+ removeItem(id) {
128
+ const feed = this.getFeed();
129
+ feed.items = feed.items.filter((i) => i.id !== id);
130
+ this.cardVc.updateSection('feed', { feed });
131
+ }
132
+ pushItem(item) {
133
+ const { items } = this.getFeed();
134
+ items.push(item);
135
+ this.cardVc.triggerRender();
136
+ }
137
+ addSentMessage(message) {
138
+ const person = this.auth.getPerson();
139
+ const item = {
140
+ id: `${new Date().getTime()}-${this.sentMessageCount++}`,
141
+ isMe: true,
142
+ message: message,
143
+ fromCasualName: person.casualName,
144
+ dateCreated: new Date().getTime(),
145
+ avatar: person.avatar,
146
+ source: {
147
+ personId: person.id,
148
+ },
149
+ };
150
+ this.pushItem(item);
151
+ return item;
152
+ }
153
+ getFeed() {
154
+ const { feed } = this.cardVc.getSection('feed');
155
+ return feed;
156
+ }
31
157
  getIsLoaded() {
32
158
  return this.isLoaded;
33
159
  }
34
- load(predicates) {
160
+ load(options) {
35
161
  return __awaiter(this, void 0, void 0, function* () {
36
- assertOptions({ predicates }, ['predicates'], `You have to pass the search predicates to load the feed. They are in the form of { source: {...}, target: {...} }[]. If you wanna find anything to AND from a person, you gotta pass personId to both source AND target.`);
162
+ const { predicates, authenticator } = assertOptions(options, ['predicates', 'authenticator'], `You have to pass the search predicates and the authenticator to load the feed. They are in the form of { source: {...}, target: {...} }[]. If you wanna find anything to AND from a person, you gotta pass personId to both source AND target.`);
37
163
  this.predicates = predicates;
164
+ this.auth = authenticator;
165
+ const client = yield this.connectToApi();
166
+ yield client.on('did-update-feed::v2020_12_25', ({ payload }) => {
167
+ const { item } = payload;
168
+ this.handleDidUpdateFeed(item);
169
+ });
38
170
  yield this.refresh();
39
171
  });
40
172
  }
@@ -47,7 +179,7 @@ export default class FeedCardViewController extends AbstractViewController {
47
179
  predicates: this.predicates,
48
180
  },
49
181
  });
50
- this.cardVc.setSection(0, {
182
+ this.cardVc.setSection('feed', {
51
183
  feed: Object.assign(Object.assign({}, feed), { shouldEnableChat: true }),
52
184
  });
53
185
  }
@@ -68,6 +200,9 @@ export default class FeedCardViewController extends AbstractViewController {
68
200
  this.cardVc.setIsBusy(false);
69
201
  });
70
202
  }
203
+ getShouldEnableChat() {
204
+ return this.shouldEnableChat;
205
+ }
71
206
  handleTryAgain() {
72
207
  return __awaiter(this, void 0, void 0, function* () {
73
208
  this.cardVc.clearCriticalError();
@@ -79,3 +214,11 @@ export default class FeedCardViewController extends AbstractViewController {
79
214
  }
80
215
  }
81
216
  FeedCardViewController.id = 'feed-card';
217
+ const messageFormSchema = buildSchema({
218
+ id: 'message',
219
+ fields: {
220
+ message: {
221
+ type: 'text',
222
+ },
223
+ },
224
+ });
@@ -2,3 +2,5 @@ import { SpruceSchemas } from '@sprucelabs/spruce-core-schemas';
2
2
  export declare type FeedPredicate = SpruceSchemas.Mercury.v2020_12_25.FeedPredicate;
3
3
  export declare type FeedItem = SpruceSchemas.Spruce.v2020_07_22.FeedItem;
4
4
  export declare type Feed = SpruceSchemas.Spruce.v2020_07_22.Feed;
5
+ export declare type CardSection = SpruceSchemas.HeartwoodViewControllers.v2021_02_11.CardSection;
6
+ export declare type Card = SpruceSchemas.HeartwoodViewControllers.v2021_02_11.Card;
File without changes
@@ -1,19 +1,48 @@
1
- import { AbstractViewController, CardViewController, SpruceSchemas, ViewControllerOptions } from '@sprucelabs/heartwood-view-controllers';
2
- import { FeedPredicate } from '../types';
3
- declare type Card = SpruceSchemas.HeartwoodViewControllers.v2021_02_11.Card;
4
- export declare type FeedCardViewControllerOptions = ViewControllerOptions & {
5
- id?: string;
6
- };
1
+ import { AbstractViewController, Authenticator, CardViewController, FormViewController, ViewControllerOptions } from '@sprucelabs/heartwood-view-controllers';
2
+ import { Card, FeedPredicate } from '../feed.types';
7
3
  export default class FeedCardViewController extends AbstractViewController<Card> {
8
4
  static id: string;
9
5
  private isLoaded;
10
6
  protected cardVc: CardViewController;
11
7
  private predicates;
12
- constructor(options: FeedCardViewControllerOptions);
8
+ protected formVc: FormViewController<MessageFormSchema>;
9
+ private shouldEnableChat;
10
+ private auth;
11
+ private sentMessageCount;
12
+ private pendingAddedMessages;
13
+ constructor(options: ViewControllerOptions & FeedCardViewControllerOptions);
14
+ private CardVc;
15
+ private FormVc;
16
+ private handleChangeForm;
17
+ private handleSubmitForm;
18
+ private setMessage;
19
+ private handleDidUpdateFeed;
20
+ private sendMessage;
21
+ private removeItem;
22
+ private pushItem;
23
+ private addSentMessage;
24
+ private getFeed;
13
25
  getIsLoaded(): boolean;
14
- load(predicates: FeedPredicate[]): Promise<void>;
26
+ load(options: {
27
+ predicates: FeedPredicate[];
28
+ authenticator: Authenticator;
29
+ }): Promise<void>;
15
30
  private refresh;
31
+ getShouldEnableChat(): boolean;
16
32
  private handleTryAgain;
17
- render(): SpruceSchemas.HeartwoodViewControllers.v2021_02_11.Card;
33
+ render(): import("@sprucelabs/heartwood-view-controllers").SpruceSchemas.HeartwoodViewControllers.v2021_02_11.Card;
18
34
  }
35
+ export declare type FeedCardViewControllerOptions = {
36
+ id?: string;
37
+ shouldEnableChat?: boolean;
38
+ };
39
+ declare const messageFormSchema: {
40
+ id: string;
41
+ fields: {
42
+ message: {
43
+ type: "text";
44
+ };
45
+ };
46
+ };
47
+ declare type MessageFormSchema = typeof messageFormSchema;
19
48
  export {};
@@ -7,26 +7,150 @@ class FeedCardViewController extends heartwood_view_controllers_1.AbstractViewCo
7
7
  super(options);
8
8
  this.isLoaded = false;
9
9
  this.predicates = [];
10
- this.cardVc = this.Controller('card', {
11
- id: options.id,
10
+ this.sentMessageCount = 0;
11
+ this.pendingAddedMessages = [];
12
+ const { shouldEnableChat } = options;
13
+ this.shouldEnableChat = !!shouldEnableChat;
14
+ this.formVc = this.FormVc();
15
+ this.cardVc = this.CardVc(options);
16
+ }
17
+ CardVc(options) {
18
+ const { id, shouldEnableChat } = options;
19
+ const sections = [
20
+ {
21
+ id: 'feed',
22
+ feed: {
23
+ items: [],
24
+ },
25
+ },
26
+ ];
27
+ if (shouldEnableChat) {
28
+ sections.push({
29
+ form: this.formVc.render(),
30
+ });
31
+ }
32
+ return this.Controller('card', {
33
+ id,
12
34
  body: {
13
35
  isBusy: true,
14
- sections: [
15
- {
16
- feed: {
17
- items: [],
36
+ sections,
37
+ },
38
+ });
39
+ }
40
+ FormVc() {
41
+ return this.Controller('form', (0, heartwood_view_controllers_1.buildForm)({
42
+ id: 'message',
43
+ schema: messageFormSchema,
44
+ isEnabled: false,
45
+ onChange: this.handleChangeForm.bind(this),
46
+ onSubmit: this.handleSubmitForm.bind(this),
47
+ sections: [
48
+ {
49
+ fields: [
50
+ {
51
+ name: 'message',
52
+ renderAs: 'textarea',
18
53
  },
54
+ ],
55
+ },
56
+ ],
57
+ shouldShowCancelButton: false,
58
+ }));
59
+ }
60
+ async handleChangeForm() {
61
+ var _a;
62
+ const message = (_a = this.formVc.getValue('message')) !== null && _a !== void 0 ? _a : '';
63
+ if (message.length > 0) {
64
+ this.formVc.enable();
65
+ }
66
+ else {
67
+ this.formVc.disable();
68
+ }
69
+ }
70
+ async handleSubmitForm() {
71
+ const message = this.formVc.getValue('message');
72
+ await this.setMessage(null);
73
+ await this.sendMessage(message);
74
+ }
75
+ async setMessage(value) {
76
+ await this.formVc.setValue('message', value);
77
+ }
78
+ handleDidUpdateFeed(item) {
79
+ const idx = this.pendingAddedMessages.indexOf(item.message);
80
+ if (idx === -1) {
81
+ this.pushItem(item);
82
+ }
83
+ else {
84
+ this.pendingAddedMessages.splice(idx, 1);
85
+ }
86
+ }
87
+ async sendMessage(message) {
88
+ var _a;
89
+ const added = this.addSentMessage(message);
90
+ const client = await this.connectToApi();
91
+ try {
92
+ await client.emitAndFlattenResponses('send-message::v2020_12_25', {
93
+ payload: {
94
+ message: {
95
+ body: message,
96
+ classification: 'transactional',
19
97
  },
20
- ],
98
+ },
99
+ });
100
+ this.pendingAddedMessages.push(message);
101
+ }
102
+ catch (err) {
103
+ this.removeItem(added.id);
104
+ await this.setMessage(added.message);
105
+ await this.alert({
106
+ title: 'Failed to send message!',
107
+ message: err.message,
108
+ });
109
+ console.error((_a = err.stack) !== null && _a !== void 0 ? _a : err.message);
110
+ }
111
+ }
112
+ removeItem(id) {
113
+ const feed = this.getFeed();
114
+ feed.items = feed.items.filter((i) => i.id !== id);
115
+ this.cardVc.updateSection('feed', { feed });
116
+ }
117
+ pushItem(item) {
118
+ const { items } = this.getFeed();
119
+ items.push(item);
120
+ this.cardVc.triggerRender();
121
+ }
122
+ addSentMessage(message) {
123
+ const person = this.auth.getPerson();
124
+ const item = {
125
+ id: `${new Date().getTime()}-${this.sentMessageCount++}`,
126
+ isMe: true,
127
+ message: message,
128
+ fromCasualName: person.casualName,
129
+ dateCreated: new Date().getTime(),
130
+ avatar: person.avatar,
131
+ source: {
132
+ personId: person.id,
21
133
  },
22
- });
134
+ };
135
+ this.pushItem(item);
136
+ return item;
137
+ }
138
+ getFeed() {
139
+ const { feed } = this.cardVc.getSection('feed');
140
+ return feed;
23
141
  }
24
142
  getIsLoaded() {
25
143
  return this.isLoaded;
26
144
  }
27
- async load(predicates) {
28
- (0, schema_1.assertOptions)({ predicates }, ['predicates'], `You have to pass the search predicates to load the feed. They are in the form of { source: {...}, target: {...} }[]. If you wanna find anything to AND from a person, you gotta pass personId to both source AND target.`);
145
+ async load(options) {
146
+ const { predicates, authenticator } = (0, schema_1.assertOptions)(options, ['predicates', 'authenticator'], `You have to pass the search predicates and the authenticator to load the feed. They are in the form of { source: {...}, target: {...} }[]. If you wanna find anything to AND from a person, you gotta pass personId to both source AND target.`);
29
147
  this.predicates = predicates;
148
+ this.auth = authenticator;
149
+ const client = await this.connectToApi();
150
+ await client.on('did-update-feed::v2020_12_25', ({ payload }) => {
151
+ const { item } = payload;
152
+ this.handleDidUpdateFeed(item);
153
+ });
30
154
  await this.refresh();
31
155
  }
32
156
  async refresh() {
@@ -37,7 +161,7 @@ class FeedCardViewController extends heartwood_view_controllers_1.AbstractViewCo
37
161
  predicates: this.predicates,
38
162
  },
39
163
  });
40
- this.cardVc.setSection(0, {
164
+ this.cardVc.setSection('feed', {
41
165
  feed: Object.assign(Object.assign({}, feed), { shouldEnableChat: true }),
42
166
  });
43
167
  }
@@ -57,6 +181,9 @@ class FeedCardViewController extends heartwood_view_controllers_1.AbstractViewCo
57
181
  this.isLoaded = true;
58
182
  this.cardVc.setIsBusy(false);
59
183
  }
184
+ getShouldEnableChat() {
185
+ return this.shouldEnableChat;
186
+ }
60
187
  async handleTryAgain() {
61
188
  this.cardVc.clearCriticalError();
62
189
  await this.refresh();
@@ -67,3 +194,11 @@ class FeedCardViewController extends heartwood_view_controllers_1.AbstractViewCo
67
194
  }
68
195
  exports.default = FeedCardViewController;
69
196
  FeedCardViewController.id = 'feed-card';
197
+ const messageFormSchema = (0, schema_1.buildSchema)({
198
+ id: 'message',
199
+ fields: {
200
+ message: {
201
+ type: 'text',
202
+ },
203
+ },
204
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sprucelabs/spruce-feed-view-controllers",
3
3
  "description": "Spruce feed view controllers",
4
- "version": "0.0.4",
4
+ "version": "0.0.7",
5
5
  "skill": {
6
6
  "namespace": "feed"
7
7
  },
@@ -26,10 +26,10 @@
26
26
  "build/types-module.d.ts",
27
27
  "build/esm/types-module.js",
28
28
  "build/esm/types-module.d.ts",
29
- "build/types.js",
30
- "build/types.d.ts",
31
- "build/esm/types.js",
32
- "build/esm/types.d.ts"
29
+ "build/feed.types.js",
30
+ "build/feed.types.d.ts",
31
+ "build/esm/feed.types.js",
32
+ "build/esm/feed.types.d.ts"
33
33
  ],
34
34
  "keywords": [],
35
35
  "scripts": {