@sprucelabs/spruce-feed-view-controllers 0.0.3 → 0.0.6

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,46 @@
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
+ constructor(options: ViewControllerOptions & FeedCardViewControllerOptions);
13
+ private CardVc;
14
+ private FormVc;
15
+ private handleChangeForm;
16
+ private handleSubmitForm;
17
+ private setMessage;
18
+ private sendMessage;
19
+ private removeFeedItem;
20
+ private addSentMessage;
21
+ private pushItem;
22
+ private getFeed;
13
23
  getIsLoaded(): boolean;
14
- load(predicates: FeedPredicate[]): Promise<void>;
24
+ load(options: {
25
+ predicates: FeedPredicate[];
26
+ authenticator: Authenticator;
27
+ }): Promise<void>;
15
28
  private refresh;
29
+ getShouldEnableChat(): boolean;
16
30
  private handleTryAgain;
17
- render(): SpruceSchemas.HeartwoodViewControllers.v2021_02_11.Card;
31
+ render(): import("@sprucelabs/heartwood-view-controllers").SpruceSchemas.HeartwoodViewControllers.v2021_02_11.Card;
18
32
  }
33
+ export declare type FeedCardViewControllerOptions = {
34
+ id?: string;
35
+ shouldEnableChat?: boolean;
36
+ };
37
+ declare const messageFormSchema: {
38
+ id: string;
39
+ fields: {
40
+ message: {
41
+ type: "text";
42
+ };
43
+ };
44
+ };
45
+ declare type MessageFormSchema = typeof messageFormSchema;
19
46
  export {};
@@ -7,34 +7,154 @@ 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
+ const { shouldEnableChat } = options;
19
+ this.shouldEnableChat = !!shouldEnableChat;
20
+ this.formVc = this.FormVc();
21
+ this.cardVc = this.CardVc(options);
22
+ }
23
+ CardVc(options) {
24
+ const { id, shouldEnableChat } = options;
25
+ const sections = [
26
+ {
27
+ id: 'feed',
28
+ feed: {
29
+ items: [],
30
+ },
31
+ },
32
+ ];
33
+ if (shouldEnableChat) {
34
+ sections.push({
35
+ form: this.formVc.render(),
36
+ });
37
+ }
38
+ return this.Controller('card', {
39
+ id,
19
40
  body: {
20
41
  isBusy: true,
21
- sections: [
22
- {
23
- feed: {
24
- items: [],
42
+ sections,
43
+ },
44
+ });
45
+ }
46
+ FormVc() {
47
+ return this.Controller('form', buildForm({
48
+ id: 'message',
49
+ schema: messageFormSchema,
50
+ isEnabled: false,
51
+ onChange: this.handleChangeForm.bind(this),
52
+ onSubmit: this.handleSubmitForm.bind(this),
53
+ sections: [
54
+ {
55
+ fields: [
56
+ {
57
+ name: 'message',
58
+ renderAs: 'textarea',
59
+ },
60
+ ],
61
+ },
62
+ ],
63
+ shouldShowCancelButton: false,
64
+ }));
65
+ }
66
+ handleChangeForm() {
67
+ var _a;
68
+ return __awaiter(this, void 0, void 0, function* () {
69
+ const message = (_a = this.formVc.getValue('message')) !== null && _a !== void 0 ? _a : '';
70
+ if (message.length > 0) {
71
+ this.formVc.enable();
72
+ }
73
+ else {
74
+ this.formVc.disable();
75
+ }
76
+ });
77
+ }
78
+ handleSubmitForm() {
79
+ return __awaiter(this, void 0, void 0, function* () {
80
+ const message = this.formVc.getValue('message');
81
+ yield this.setMessage(null);
82
+ yield this.sendMessage(message);
83
+ });
84
+ }
85
+ setMessage(value) {
86
+ return __awaiter(this, void 0, void 0, function* () {
87
+ yield this.formVc.setValue('message', value);
88
+ });
89
+ }
90
+ sendMessage(message) {
91
+ var _a;
92
+ return __awaiter(this, void 0, void 0, function* () {
93
+ const added = this.addSentMessage(message);
94
+ const client = yield this.connectToApi();
95
+ try {
96
+ yield client.emitAndFlattenResponses('send-message::v2020_12_25', {
97
+ payload: {
98
+ message: {
99
+ body: message,
100
+ classification: 'transactional',
25
101
  },
26
102
  },
27
- ],
28
- },
103
+ });
104
+ }
105
+ catch (err) {
106
+ this.removeFeedItem(added.id);
107
+ yield this.setMessage(added.message);
108
+ yield this.alert({
109
+ title: 'Failed to send message!',
110
+ message: err.message,
111
+ });
112
+ console.error((_a = err.stack) !== null && _a !== void 0 ? _a : err.message);
113
+ }
29
114
  });
30
115
  }
116
+ removeFeedItem(id) {
117
+ const feed = this.getFeed();
118
+ feed.items = feed.items.filter((i) => i.id !== id);
119
+ this.cardVc.updateSection('feed', { feed });
120
+ }
121
+ addSentMessage(message) {
122
+ const person = this.auth.getPerson();
123
+ const item = {
124
+ id: `${new Date().getTime()}-${this.sentMessageCount++}`,
125
+ isMe: true,
126
+ message: message,
127
+ fromCasualName: person.casualName,
128
+ dateCreated: new Date().getTime(),
129
+ avatar: person.avatar,
130
+ source: {
131
+ personId: person.id,
132
+ },
133
+ };
134
+ this.pushItem(item);
135
+ return item;
136
+ }
137
+ pushItem(item) {
138
+ const { items } = this.getFeed();
139
+ items.push(item);
140
+ this.cardVc.triggerRender();
141
+ }
142
+ getFeed() {
143
+ const { feed } = this.cardVc.getSection('feed');
144
+ return feed;
145
+ }
31
146
  getIsLoaded() {
32
147
  return this.isLoaded;
33
148
  }
34
- load(predicates) {
149
+ load(options) {
35
150
  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.`);
151
+ 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
152
  this.predicates = predicates;
153
+ this.auth = authenticator;
154
+ const client = yield this.connectToApi();
155
+ yield client.on('did-update-feed::v2020_12_25', ({ payload }) => {
156
+ this.pushItem(payload.item);
157
+ });
38
158
  yield this.refresh();
39
159
  });
40
160
  }
@@ -47,7 +167,7 @@ export default class FeedCardViewController extends AbstractViewController {
47
167
  predicates: this.predicates,
48
168
  },
49
169
  });
50
- this.cardVc.setSection(0, {
170
+ this.cardVc.setSection('feed', {
51
171
  feed: Object.assign(Object.assign({}, feed), { shouldEnableChat: true }),
52
172
  });
53
173
  }
@@ -68,6 +188,9 @@ export default class FeedCardViewController extends AbstractViewController {
68
188
  this.cardVc.setIsBusy(false);
69
189
  });
70
190
  }
191
+ getShouldEnableChat() {
192
+ return this.shouldEnableChat;
193
+ }
71
194
  handleTryAgain() {
72
195
  return __awaiter(this, void 0, void 0, function* () {
73
196
  this.cardVc.clearCriticalError();
@@ -79,3 +202,11 @@ export default class FeedCardViewController extends AbstractViewController {
79
202
  }
80
203
  }
81
204
  FeedCardViewController.id = 'feed-card';
205
+ const messageFormSchema = buildSchema({
206
+ id: 'message',
207
+ fields: {
208
+ message: {
209
+ type: 'text',
210
+ },
211
+ },
212
+ });
@@ -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,46 @@
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
+ constructor(options: ViewControllerOptions & FeedCardViewControllerOptions);
13
+ private CardVc;
14
+ private FormVc;
15
+ private handleChangeForm;
16
+ private handleSubmitForm;
17
+ private setMessage;
18
+ private sendMessage;
19
+ private removeFeedItem;
20
+ private addSentMessage;
21
+ private pushItem;
22
+ private getFeed;
13
23
  getIsLoaded(): boolean;
14
- load(predicates: FeedPredicate[]): Promise<void>;
24
+ load(options: {
25
+ predicates: FeedPredicate[];
26
+ authenticator: Authenticator;
27
+ }): Promise<void>;
15
28
  private refresh;
29
+ getShouldEnableChat(): boolean;
16
30
  private handleTryAgain;
17
- render(): SpruceSchemas.HeartwoodViewControllers.v2021_02_11.Card;
31
+ render(): import("@sprucelabs/heartwood-view-controllers").SpruceSchemas.HeartwoodViewControllers.v2021_02_11.Card;
18
32
  }
33
+ export declare type FeedCardViewControllerOptions = {
34
+ id?: string;
35
+ shouldEnableChat?: boolean;
36
+ };
37
+ declare const messageFormSchema: {
38
+ id: string;
39
+ fields: {
40
+ message: {
41
+ type: "text";
42
+ };
43
+ };
44
+ };
45
+ declare type MessageFormSchema = typeof messageFormSchema;
19
46
  export {};
@@ -7,26 +7,138 @@ 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
+ const { shouldEnableChat } = options;
12
+ this.shouldEnableChat = !!shouldEnableChat;
13
+ this.formVc = this.FormVc();
14
+ this.cardVc = this.CardVc(options);
15
+ }
16
+ CardVc(options) {
17
+ const { id, shouldEnableChat } = options;
18
+ const sections = [
19
+ {
20
+ id: 'feed',
21
+ feed: {
22
+ items: [],
23
+ },
24
+ },
25
+ ];
26
+ if (shouldEnableChat) {
27
+ sections.push({
28
+ form: this.formVc.render(),
29
+ });
30
+ }
31
+ return this.Controller('card', {
32
+ id,
12
33
  body: {
13
34
  isBusy: true,
14
- sections: [
15
- {
16
- feed: {
17
- items: [],
35
+ sections,
36
+ },
37
+ });
38
+ }
39
+ FormVc() {
40
+ return this.Controller('form', (0, heartwood_view_controllers_1.buildForm)({
41
+ id: 'message',
42
+ schema: messageFormSchema,
43
+ isEnabled: false,
44
+ onChange: this.handleChangeForm.bind(this),
45
+ onSubmit: this.handleSubmitForm.bind(this),
46
+ sections: [
47
+ {
48
+ fields: [
49
+ {
50
+ name: 'message',
51
+ renderAs: 'textarea',
18
52
  },
53
+ ],
54
+ },
55
+ ],
56
+ shouldShowCancelButton: false,
57
+ }));
58
+ }
59
+ async handleChangeForm() {
60
+ var _a;
61
+ const message = (_a = this.formVc.getValue('message')) !== null && _a !== void 0 ? _a : '';
62
+ if (message.length > 0) {
63
+ this.formVc.enable();
64
+ }
65
+ else {
66
+ this.formVc.disable();
67
+ }
68
+ }
69
+ async handleSubmitForm() {
70
+ const message = this.formVc.getValue('message');
71
+ await this.setMessage(null);
72
+ await this.sendMessage(message);
73
+ }
74
+ async setMessage(value) {
75
+ await this.formVc.setValue('message', value);
76
+ }
77
+ async sendMessage(message) {
78
+ var _a;
79
+ const added = this.addSentMessage(message);
80
+ const client = await this.connectToApi();
81
+ try {
82
+ await client.emitAndFlattenResponses('send-message::v2020_12_25', {
83
+ payload: {
84
+ message: {
85
+ body: message,
86
+ classification: 'transactional',
19
87
  },
20
- ],
88
+ },
89
+ });
90
+ }
91
+ catch (err) {
92
+ this.removeFeedItem(added.id);
93
+ await this.setMessage(added.message);
94
+ await this.alert({
95
+ title: 'Failed to send message!',
96
+ message: err.message,
97
+ });
98
+ console.error((_a = err.stack) !== null && _a !== void 0 ? _a : err.message);
99
+ }
100
+ }
101
+ removeFeedItem(id) {
102
+ const feed = this.getFeed();
103
+ feed.items = feed.items.filter((i) => i.id !== id);
104
+ this.cardVc.updateSection('feed', { feed });
105
+ }
106
+ addSentMessage(message) {
107
+ const person = this.auth.getPerson();
108
+ const item = {
109
+ id: `${new Date().getTime()}-${this.sentMessageCount++}`,
110
+ isMe: true,
111
+ message: message,
112
+ fromCasualName: person.casualName,
113
+ dateCreated: new Date().getTime(),
114
+ avatar: person.avatar,
115
+ source: {
116
+ personId: person.id,
21
117
  },
22
- });
118
+ };
119
+ this.pushItem(item);
120
+ return item;
121
+ }
122
+ pushItem(item) {
123
+ const { items } = this.getFeed();
124
+ items.push(item);
125
+ this.cardVc.triggerRender();
126
+ }
127
+ getFeed() {
128
+ const { feed } = this.cardVc.getSection('feed');
129
+ return feed;
23
130
  }
24
131
  getIsLoaded() {
25
132
  return this.isLoaded;
26
133
  }
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.`);
134
+ async load(options) {
135
+ 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
136
  this.predicates = predicates;
137
+ this.auth = authenticator;
138
+ const client = await this.connectToApi();
139
+ await client.on('did-update-feed::v2020_12_25', ({ payload }) => {
140
+ this.pushItem(payload.item);
141
+ });
30
142
  await this.refresh();
31
143
  }
32
144
  async refresh() {
@@ -37,7 +149,7 @@ class FeedCardViewController extends heartwood_view_controllers_1.AbstractViewCo
37
149
  predicates: this.predicates,
38
150
  },
39
151
  });
40
- this.cardVc.setSection(0, {
152
+ this.cardVc.setSection('feed', {
41
153
  feed: Object.assign(Object.assign({}, feed), { shouldEnableChat: true }),
42
154
  });
43
155
  }
@@ -57,6 +169,9 @@ class FeedCardViewController extends heartwood_view_controllers_1.AbstractViewCo
57
169
  this.isLoaded = true;
58
170
  this.cardVc.setIsBusy(false);
59
171
  }
172
+ getShouldEnableChat() {
173
+ return this.shouldEnableChat;
174
+ }
60
175
  async handleTryAgain() {
61
176
  this.cardVc.clearCriticalError();
62
177
  await this.refresh();
@@ -67,3 +182,11 @@ class FeedCardViewController extends heartwood_view_controllers_1.AbstractViewCo
67
182
  }
68
183
  exports.default = FeedCardViewController;
69
184
  FeedCardViewController.id = 'feed-card';
185
+ const messageFormSchema = (0, schema_1.buildSchema)({
186
+ id: 'message',
187
+ fields: {
188
+ message: {
189
+ type: 'text',
190
+ },
191
+ },
192
+ });
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.3",
4
+ "version": "0.0.6",
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": {