@sprucelabs/spruce-feed-view-controllers 0.0.5 → 0.0.8

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,167 @@ 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
+ console.log({ idx });
94
+ if (idx === -1) {
95
+ this.pushItem(item);
96
+ }
97
+ else {
98
+ this.pendingAddedMessages.splice(idx, 1);
99
+ }
100
+ }
101
+ sendMessage(message) {
102
+ var _a;
103
+ return __awaiter(this, void 0, void 0, function* () {
104
+ const added = this.addSentMessage(message);
105
+ const client = yield this.connectToApi();
106
+ try {
107
+ yield client.emitAndFlattenResponses('send-message::v2020_12_25', {
108
+ payload: {
109
+ message: {
110
+ body: message,
111
+ classification: 'transactional',
25
112
  },
26
113
  },
27
- ],
28
- },
114
+ });
115
+ this.pendingAddedMessages.push(message);
116
+ }
117
+ catch (err) {
118
+ this.removeItem(added.id);
119
+ yield this.setMessage(added.message);
120
+ yield this.alert({
121
+ title: 'Failed to send message!',
122
+ message: err.message,
123
+ });
124
+ console.error((_a = err.stack) !== null && _a !== void 0 ? _a : err.message);
125
+ }
29
126
  });
30
127
  }
128
+ removeItem(id) {
129
+ const feed = this.getFeed();
130
+ feed.items = feed.items.filter((i) => i.id !== id);
131
+ this.cardVc.updateSection('feed', { feed });
132
+ }
133
+ pushItem(item) {
134
+ const { items } = this.getFeed();
135
+ items.push(item);
136
+ this.cardVc.triggerRender();
137
+ }
138
+ addSentMessage(message) {
139
+ const person = this.auth.getPerson();
140
+ const item = {
141
+ id: `${new Date().getTime()}-${this.sentMessageCount++}`,
142
+ isMe: true,
143
+ message: message,
144
+ fromCasualName: person.casualName,
145
+ dateCreated: new Date().getTime(),
146
+ avatar: person.avatar,
147
+ source: {
148
+ personId: person.id,
149
+ },
150
+ };
151
+ this.pushItem(item);
152
+ return item;
153
+ }
154
+ getFeed() {
155
+ const { feed } = this.cardVc.getSection('feed');
156
+ return feed;
157
+ }
31
158
  getIsLoaded() {
32
159
  return this.isLoaded;
33
160
  }
34
- load(predicates) {
161
+ load(options) {
35
162
  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.`);
163
+ 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
164
  this.predicates = predicates;
165
+ this.auth = authenticator;
166
+ const client = yield this.connectToApi();
167
+ yield client.on('did-update-feed::v2020_12_25', ({ payload }) => {
168
+ const { item } = payload;
169
+ this.handleDidUpdateFeed(item);
170
+ });
38
171
  yield this.refresh();
39
172
  });
40
173
  }
@@ -47,7 +180,7 @@ export default class FeedCardViewController extends AbstractViewController {
47
180
  predicates: this.predicates,
48
181
  },
49
182
  });
50
- this.cardVc.setSection(0, {
183
+ this.cardVc.setSection('feed', {
51
184
  feed: Object.assign(Object.assign({}, feed), { shouldEnableChat: true }),
52
185
  });
53
186
  }
@@ -68,6 +201,9 @@ export default class FeedCardViewController extends AbstractViewController {
68
201
  this.cardVc.setIsBusy(false);
69
202
  });
70
203
  }
204
+ getShouldEnableChat() {
205
+ return this.shouldEnableChat;
206
+ }
71
207
  handleTryAgain() {
72
208
  return __awaiter(this, void 0, void 0, function* () {
73
209
  this.cardVc.clearCriticalError();
@@ -79,3 +215,11 @@ export default class FeedCardViewController extends AbstractViewController {
79
215
  }
80
216
  }
81
217
  FeedCardViewController.id = 'feed-card';
218
+ const messageFormSchema = buildSchema({
219
+ id: 'message',
220
+ fields: {
221
+ message: {
222
+ type: 'text',
223
+ },
224
+ },
225
+ });
@@ -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,151 @@ 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
+ console.log({ idx });
81
+ if (idx === -1) {
82
+ this.pushItem(item);
83
+ }
84
+ else {
85
+ this.pendingAddedMessages.splice(idx, 1);
86
+ }
87
+ }
88
+ async sendMessage(message) {
89
+ var _a;
90
+ const added = this.addSentMessage(message);
91
+ const client = await this.connectToApi();
92
+ try {
93
+ await client.emitAndFlattenResponses('send-message::v2020_12_25', {
94
+ payload: {
95
+ message: {
96
+ body: message,
97
+ classification: 'transactional',
19
98
  },
20
- ],
99
+ },
100
+ });
101
+ this.pendingAddedMessages.push(message);
102
+ }
103
+ catch (err) {
104
+ this.removeItem(added.id);
105
+ await this.setMessage(added.message);
106
+ await this.alert({
107
+ title: 'Failed to send message!',
108
+ message: err.message,
109
+ });
110
+ console.error((_a = err.stack) !== null && _a !== void 0 ? _a : err.message);
111
+ }
112
+ }
113
+ removeItem(id) {
114
+ const feed = this.getFeed();
115
+ feed.items = feed.items.filter((i) => i.id !== id);
116
+ this.cardVc.updateSection('feed', { feed });
117
+ }
118
+ pushItem(item) {
119
+ const { items } = this.getFeed();
120
+ items.push(item);
121
+ this.cardVc.triggerRender();
122
+ }
123
+ addSentMessage(message) {
124
+ const person = this.auth.getPerson();
125
+ const item = {
126
+ id: `${new Date().getTime()}-${this.sentMessageCount++}`,
127
+ isMe: true,
128
+ message: message,
129
+ fromCasualName: person.casualName,
130
+ dateCreated: new Date().getTime(),
131
+ avatar: person.avatar,
132
+ source: {
133
+ personId: person.id,
21
134
  },
22
- });
135
+ };
136
+ this.pushItem(item);
137
+ return item;
138
+ }
139
+ getFeed() {
140
+ const { feed } = this.cardVc.getSection('feed');
141
+ return feed;
23
142
  }
24
143
  getIsLoaded() {
25
144
  return this.isLoaded;
26
145
  }
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.`);
146
+ async load(options) {
147
+ 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
148
  this.predicates = predicates;
149
+ this.auth = authenticator;
150
+ const client = await this.connectToApi();
151
+ await client.on('did-update-feed::v2020_12_25', ({ payload }) => {
152
+ const { item } = payload;
153
+ this.handleDidUpdateFeed(item);
154
+ });
30
155
  await this.refresh();
31
156
  }
32
157
  async refresh() {
@@ -37,7 +162,7 @@ class FeedCardViewController extends heartwood_view_controllers_1.AbstractViewCo
37
162
  predicates: this.predicates,
38
163
  },
39
164
  });
40
- this.cardVc.setSection(0, {
165
+ this.cardVc.setSection('feed', {
41
166
  feed: Object.assign(Object.assign({}, feed), { shouldEnableChat: true }),
42
167
  });
43
168
  }
@@ -57,6 +182,9 @@ class FeedCardViewController extends heartwood_view_controllers_1.AbstractViewCo
57
182
  this.isLoaded = true;
58
183
  this.cardVc.setIsBusy(false);
59
184
  }
185
+ getShouldEnableChat() {
186
+ return this.shouldEnableChat;
187
+ }
60
188
  async handleTryAgain() {
61
189
  this.cardVc.clearCriticalError();
62
190
  await this.refresh();
@@ -67,3 +195,11 @@ class FeedCardViewController extends heartwood_view_controllers_1.AbstractViewCo
67
195
  }
68
196
  exports.default = FeedCardViewController;
69
197
  FeedCardViewController.id = 'feed-card';
198
+ const messageFormSchema = (0, schema_1.buildSchema)({
199
+ id: 'message',
200
+ fields: {
201
+ message: {
202
+ type: 'text',
203
+ },
204
+ },
205
+ });
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.5",
4
+ "version": "0.0.8",
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": {