Skip to content

Commit 3531564

Browse files
committed
avniproject/avni-client#1721 | Add video support for concepts
1 parent b93af96 commit 3531564

File tree

5 files changed

+116
-17
lines changed

5 files changed

+116
-17
lines changed

src/Concept.js

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import _ from "lodash";
44
import MultipleCodedValues from "./observation/MultipleCodedValues";
55
import SingleCodedValue from "./observation/SingleCodedValue";
66
import PrimitiveValue from "./observation/PrimitiveValue";
7-
import Duration from "./Duration";
87
import CompositeDuration from "./CompositeDuration";
98
import KeyValue from "./application/KeyValue";
109
import PhoneNumber from "./PhoneNumber";
1110
import Identifier from "./Identifier";
1211
import QuestionGroup from "./observation/QuestionGroup";
1312
import RepeatableQuestionGroup from "./observation/RepeatableQuestionGroup";
1413
import ConceptAnswer from "./ConceptAnswer";
14+
import ConceptMedia from "./ConceptMedia";
1515
import SchemaNames from "./SchemaNames";
1616

1717
export default class Concept extends BaseEntity {
@@ -35,8 +35,7 @@ export default class Concept extends BaseEntity {
3535
unit: {type: "string", optional: true},
3636
keyValues: {type: "list", objectType: SchemaNames.KeyValue},
3737
voided: {type: "bool", default: false},
38-
mediaUrl: {type: "string", optional: true},
39-
mediaType: {type: "string", optional: true},
38+
media: {type: "list", objectType: "ConceptMedia"},
4039
},
4140
};
4241

@@ -84,20 +83,39 @@ export default class Concept extends BaseEntity {
8483
this.that.unit = x;
8584
}
8685

87-
get mediaUrl() {
88-
return this.that.mediaUrl;
86+
getImageMedia() {
87+
return this.media ? this.media.filter(m => m.isImage()) : [];
8988
}
9089

91-
set mediaUrl(x) {
92-
this.that.mediaUrl = x;
90+
getVideoMedia() {
91+
return this.media ? this.media.filter(m => m.isVideo()) : [];
9392
}
9493

95-
get mediaType() {
96-
return this.that.mediaType;
94+
hasImage() {
95+
return this.getImageMedia().length > 0;
96+
}
97+
98+
hasVideo() {
99+
return this.getVideoMedia().length > 0;
100+
}
101+
102+
getImageUrl() {
103+
const imageMedia = this.getImageMedia();
104+
return imageMedia.length > 0 ? imageMedia[0].url : null;
97105
}
98106

99-
set mediaType(x) {
100-
this.that.mediaType = x;
107+
getVideoUrl() {
108+
const videoMedia = this.getVideoMedia();
109+
return videoMedia.length > 0 ? videoMedia[0].url : null;
110+
}
111+
112+
// For backward compatibility where existing code expects mediaUrl/mediaType
113+
get mediaUrl() {
114+
return this.getImageUrl();
115+
}
116+
117+
get mediaType() {
118+
return this.hasImage() ? 'Image' : this.hasVideo() ? 'Video' : null;
101119
}
102120

103121
get name() {
@@ -132,6 +150,14 @@ export default class Concept extends BaseEntity {
132150
this.that.keyValues = this.fromEntityList(x);
133151
}
134152

153+
get media() {
154+
return this.toEntityList("media", ConceptMedia);
155+
}
156+
157+
set media(x) {
158+
this.that.media = this.fromEntityList(x);
159+
}
160+
135161
static keys = {
136162
isWithinCatchment: 'isWithinCatchment',
137163
lowestAddressLevelTypeUUIDs: 'lowestAddressLevelTypeUUIDs',
@@ -186,8 +212,12 @@ export default class Concept extends BaseEntity {
186212
concept.unit = conceptResource.unit;
187213
concept.voided = conceptResource.voided || false; //This change should be independently deployable irrespective of server
188214
concept.keyValues = _.map(conceptResource.keyValues, KeyValue.fromResource);
189-
concept.mediaUrl = conceptResource.mediaUrl;
190-
concept.mediaType = conceptResource.mediaType;
215+
216+
// Handle media array format from server
217+
if (conceptResource.media) {
218+
concept.media = _.map(conceptResource.media, ConceptMedia.fromResource);
219+
}
220+
191221
return concept;
192222
}
193223

@@ -427,14 +457,15 @@ export default class Concept extends BaseEntity {
427457
}
428458

429459
hasAnswersWithMedia() {
430-
return _.some(this.answers, (answer) => answer.concept.hasMediaUrl() || answer.concept.hasMediaType());
460+
return _.some(this.answers, (answer) => answer.concept.hasMedia());
431461
}
432462

433463
hasMedia() {
434-
return this.hasMediaUrl() || this.hasMediaType() || this.hasAnswersWithMedia();
464+
return this.media && this.media.length > 0 || this.hasAnswersWithMedia();
435465
}
436466
}
437467

438468
export const MediaType = {
439-
Image: "Image"
469+
Image: "Image",
470+
Video: "Video"
440471
};

src/ConceptMedia.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import BaseEntity from "./BaseEntity";
2+
import General from "./utility/General";
3+
4+
export default class ConceptMedia extends BaseEntity {
5+
static schema = {
6+
name: "ConceptMedia",
7+
primaryKey: "uuid",
8+
properties: {
9+
uuid: "string",
10+
url: {type: "string", optional: true},
11+
type: {type: "string", optional: true},
12+
},
13+
};
14+
15+
constructor(that = null) {
16+
super(that);
17+
}
18+
19+
get url() {
20+
return this.that.url;
21+
}
22+
23+
set url(x) {
24+
this.that.url = x;
25+
}
26+
27+
get type() {
28+
return this.that.type;
29+
}
30+
31+
set type(x) {
32+
this.that.type = x;
33+
}
34+
35+
static fromResource(resource) {
36+
const conceptMedia = new ConceptMedia();
37+
conceptMedia.uuid = resource.uuid || General.randomUUID();
38+
conceptMedia.url = resource.url;
39+
conceptMedia.type = resource.type;
40+
return conceptMedia;
41+
}
42+
43+
isImage() {
44+
return this.type === 'Image';
45+
}
46+
47+
isVideo() {
48+
return this.type === 'Video';
49+
}
50+
}

src/Schema.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Settings from "./Settings";
22
import LocaleMapping from "./LocaleMapping";
33
import Concept from "./Concept";
44
import ConceptAnswer from "./ConceptAnswer";
5+
import ConceptMedia from "./ConceptMedia";
56
import Individual from "./Individual";
67
import Family from "./Family";
78
import AddressLevel, {LocationMapping} from "./AddressLevel";
@@ -97,6 +98,7 @@ const entities = [
9798
LocaleMapping,
9899
Settings,
99100
ConceptAnswer,
101+
ConceptMedia,
100102
Concept,
101103
EncounterType,
102104
Gender,
@@ -256,7 +258,7 @@ function createRealmConfig() {
256258
return doCompact;
257259
},
258260
//order is important, should be arranged according to the dependency
259-
schemaVersion: 203,
261+
schemaVersion: 204,
260262
onMigration: function (oldDB, newDB) {
261263
console.log("[AvniModels.Schema]", `Running migration with old schema version: ${oldDB.schemaVersion} and new schema version: ${newDB.schemaVersion}`);
262264
if (oldDB.schemaVersion === VersionWithEmbeddedMigrationProblem)
@@ -987,6 +989,19 @@ function createRealmConfig() {
987989
}
988990
});
989991
}
992+
if (oldDB.schemaVersion < 204) {
993+
_.forEach(newDB.objects(Concept.schema.name), (concept) => {
994+
if (!concept.media) {
995+
concept.media = [];
996+
}
997+
});
998+
// Reset EntitySyncStatus for Concept to refetch media URLs
999+
_.forEach(newDB.objects(EntitySyncStatus.schema.name), (ess) => {
1000+
if (ess.entityName === 'Concept') {
1001+
ess.loadedSince = EntitySyncStatus.REALLY_OLD_DATE;
1002+
}
1003+
});
1004+
}
9901005
},
9911006
};
9921007
}

src/SchemaNames.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class SchemaNames {
3939
static ChecklistItemStatus = "EmbeddedChecklistItemStatus";
4040
static Comment = "Comment";
4141
static Concept = "Concept";
42+
static ConceptMedia = "ConceptMedia";
4243
static EntityApprovalStatus = "EntityApprovalStatus";
4344
static Point = "Point";
4445
}

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import ChecklistItemStatus from "./ChecklistItemStatus";
99
import CompositeDuration from "./CompositeDuration";
1010
import Concept from "./Concept";
1111
import ConceptAnswer from "./ConceptAnswer";
12+
import ConceptMedia from "./ConceptMedia";
1213
import Duration from "./Duration";
1314
import Encounter from "./Encounter";
1415
import EncounterType from "./EncounterType";
@@ -142,6 +143,7 @@ export {
142143
CompositeDuration,
143144
Concept,
144145
ConceptAnswer,
146+
ConceptMedia,
145147
Duration,
146148
Encounter,
147149
EncounterType,

0 commit comments

Comments
 (0)