From 5f12be32a0b69d29c159f72affd92710cf8afccb Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Fri, 29 Aug 2025 19:41:20 +1000 Subject: [PATCH 1/4] refactor module to topics --- .../course_plans/course_plan_model.dart | 14 ++--- .../course_plans/course_plans_repo.dart | 63 +++++++++---------- .../models/course_plan/cms_course_plan.dart | 9 +-- .../course_plan/cms_course_plan_activity.dart | 10 +-- .../cms_course_plan_activity_media.dart | 2 + .../course_plan/cms_course_plan_media.dart | 1 + ...module.dart => cms_course_plan_topic.dart} | 21 ++++--- ...rt => cms_course_plan_topic_location.dart} | 19 +++--- 8 files changed, 73 insertions(+), 66 deletions(-) rename lib/pangea/payload_client/models/course_plan/{cms_course_plan_module.dart => cms_course_plan_topic.dart} (77%) rename lib/pangea/payload_client/models/course_plan/{cms_course_plan_module_location.dart => cms_course_plan_topic_location.dart} (73%) diff --git a/lib/pangea/course_plans/course_plan_model.dart b/lib/pangea/course_plans/course_plan_model.dart index 054b24133..23278c7a6 100644 --- a/lib/pangea/course_plans/course_plan_model.dart +++ b/lib/pangea/course_plans/course_plan_model.dart @@ -9,8 +9,8 @@ import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_p import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_plan_activity.dart'; import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_plan_activity_media.dart'; import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_plan_media.dart'; -import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_plan_module.dart'; -import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_plan_module_location.dart'; +import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_plan_topic.dart'; +import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_plan_topic_location.dart'; /// Represents a topic in the course planner response. class Topic { @@ -150,8 +150,8 @@ class CoursePlanModel { factory CoursePlanModel.fromCmsDocs( CmsCoursePlan cmsCoursePlan, List? cmsCoursePlanMedias, - List? cmsCoursePlanModules, - List? cmsCoursePlanModuleLocations, + List? cmsCoursePlanModules, + List? cmsCoursePlanModuleLocations, List? cmsCoursePlanActivities, List? cmsCoursePlanActivityMedias, ) { @@ -160,10 +160,10 @@ class CoursePlanModel { if (cmsCoursePlanModules != null) { for (final module in cmsCoursePlanModules) { // select locations of current module - List? moduleLocations; + List? moduleLocations; if (cmsCoursePlanModuleLocations != null) { for (final location in cmsCoursePlanModuleLocations) { - if (location.coursePlanModules.contains(module.id)) { + if (location.coursePlanTopics.contains(module.id)) { moduleLocations ??= []; moduleLocations.add(location); } @@ -174,7 +174,7 @@ class CoursePlanModel { List? moduleActivities; if (cmsCoursePlanActivities != null) { for (final activity in cmsCoursePlanActivities) { - if (activity.coursePlanModules.contains(module.id)) { + if (activity.coursePlanTopics.contains(module.id)) { moduleActivities ??= []; moduleActivities.add(activity); } diff --git a/lib/pangea/course_plans/course_plans_repo.dart b/lib/pangea/course_plans/course_plans_repo.dart index 4e2a997bd..f5bcb304b 100644 --- a/lib/pangea/course_plans/course_plans_repo.dart +++ b/lib/pangea/course_plans/course_plans_repo.dart @@ -1,5 +1,3 @@ -import 'package:get_storage/get_storage.dart'; - import 'package:fluffychat/pangea/common/config/environment.dart'; import 'package:fluffychat/pangea/course_plans/course_plan_model.dart'; import 'package:fluffychat/pangea/learning_settings/enums/language_level_type_enum.dart'; @@ -8,10 +6,11 @@ import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_p import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_plan_activity.dart'; import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_plan_activity_media.dart'; import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_plan_media.dart'; -import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_plan_module.dart'; -import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_plan_module_location.dart'; +import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_plan_topic.dart'; +import 'package:fluffychat/pangea/payload_client/models/course_plan/cms_course_plan_topic_location.dart'; import 'package:fluffychat/pangea/payload_client/payload_client.dart'; import 'package:fluffychat/widgets/matrix.dart'; +import 'package:get_storage/get_storage.dart'; class CourseFilter { final LanguageModel? targetLanguage; @@ -170,7 +169,7 @@ class CoursePlansRepo { } final result = await payload.find( - "course-plans", + CmsCoursePlan.slug, CmsCoursePlan.fromJson, page: 1, limit: 10, @@ -197,14 +196,14 @@ class CoursePlansRepo { CmsCoursePlan cmsCoursePlan, ) async { final medias = await _getMedia(cmsCoursePlan); - final modules = await _getModules(cmsCoursePlan); - final locations = await _getModuleLocations(modules ?? []); - final activities = await _getModuleActivities(modules ?? []); + final topics = await _getTopics(cmsCoursePlan); + final locations = await _getTopicLocations(topics ?? []); + final activities = await _getTopicActivities(topics ?? []); final activityMedias = await _getActivityMedia(activities ?? []); return CoursePlanModel.fromCmsDocs( cmsCoursePlan, medias, - modules, + topics, locations, activities, activityMedias, @@ -222,7 +221,7 @@ class CoursePlansRepo { }; final limit = docs.length; final cmsCoursePlanMediaResult = await payload.find( - "course-plan-media", + CmsCoursePlanMedia.slug, CmsCoursePlanMedia.fromJson, where: where, limit: limit, @@ -232,34 +231,34 @@ class CoursePlansRepo { return cmsCoursePlanMediaResult.docs; } - static Future?> _getModules( + static Future?> _getTopics( CmsCoursePlan cmsCoursePlan, ) async { - final docs = cmsCoursePlan.coursePlanModules?.docs; + final docs = cmsCoursePlan.coursePlanTopics?.docs; if (docs == null || docs.isEmpty) return null; final where = { "id": {"in": docs.join(",")}, }; final limit = docs.length; - final cmsCourseModulesResult = await payload.find( - "course-plan-modules", - CmsCoursePlanModule.fromJson, + final cmsCourseTopicsResult = await payload.find( + CmsCoursePlanTopic.slug, + CmsCoursePlanTopic.fromJson, where: where, limit: limit, page: 1, sort: "createdAt", ); - return cmsCourseModulesResult.docs; + return cmsCourseTopicsResult.docs; } - static Future?> _getModuleLocations( - List modules, + static Future?> _getTopicLocations( + List topics, ) async { final List locations = []; - for (final module in modules) { - if (module.coursePlanModuleLocations?.docs != null) { - locations.addAll(module.coursePlanModuleLocations!.docs!); + for (final top in topics) { + if (top.coursePlanTopicLocations?.docs != null) { + locations.addAll(top.coursePlanTopicLocations!.docs!); } } if (locations.isEmpty) return null; @@ -268,24 +267,24 @@ class CoursePlansRepo { "id": {"in": locations.join(",")}, }; final limit = locations.length; - final cmsCoursePlanModuleLocationsResult = await payload.find( - "course-plan-module-locations", - CmsCoursePlanModuleLocation.fromJson, + final cmsCoursePlanTopicLocationsResult = await payload.find( + CmsCoursePlanTopicLocation.slug, + CmsCoursePlanTopicLocation.fromJson, where: where, limit: limit, page: 1, sort: "createdAt", ); - return cmsCoursePlanModuleLocationsResult.docs; + return cmsCoursePlanTopicLocationsResult.docs; } - static Future?> _getModuleActivities( - List module, + static Future?> _getTopicActivities( + List topics, ) async { final List activities = []; - for (final mod in module) { - if (mod.coursePlanActivities?.docs != null) { - activities.addAll(mod.coursePlanActivities!.docs!); + for (final top in topics) { + if (top.coursePlanActivities?.docs != null) { + activities.addAll(top.coursePlanActivities!.docs!); } } if (activities.isEmpty) return null; @@ -295,7 +294,7 @@ class CoursePlansRepo { }; final limit = activities.length; final cmsCoursePlanActivitiesResult = await payload.find( - "course-plan-activities", + CmsCoursePlanActivity.slug, CmsCoursePlanActivity.fromJson, where: where, limit: limit, @@ -321,7 +320,7 @@ class CoursePlansRepo { }; final limit = mediaIds.length; final cmsCoursePlanActivityMediasResult = await payload.find( - "course-plan-activity-medias", + CmsCoursePlanActivityMedia.slug, CmsCoursePlanActivityMedia.fromJson, where: where, limit: limit, diff --git a/lib/pangea/payload_client/models/course_plan/cms_course_plan.dart b/lib/pangea/payload_client/models/course_plan/cms_course_plan.dart index c82bd414d..6835e1e41 100644 --- a/lib/pangea/payload_client/models/course_plan/cms_course_plan.dart +++ b/lib/pangea/payload_client/models/course_plan/cms_course_plan.dart @@ -3,6 +3,7 @@ import 'package:fluffychat/pangea/payload_client/polymorphic_relationship.dart'; /// Represents a course plan from the CMS API class CmsCoursePlan { + static const String slug = "course-plans"; final String id; final String title; final String description; @@ -10,7 +11,7 @@ class CmsCoursePlan { final String l1; // Language of instruction final String l2; // Target language final JoinField? coursePlanMedia; - final JoinField? coursePlanModules; + final JoinField? coursePlanTopics; final PolymorphicRelationship? createdBy; final PolymorphicRelationship? updatedBy; final String updatedAt; @@ -24,7 +25,7 @@ class CmsCoursePlan { required this.l1, required this.l2, this.coursePlanMedia, - this.coursePlanModules, + this.coursePlanTopics, this.createdBy, this.updatedBy, required this.updatedAt, @@ -40,7 +41,7 @@ class CmsCoursePlan { l1: json['l1'], l2: json['l2'], coursePlanMedia: JoinField.fromJson(json['coursePlanMedia']), - coursePlanModules: JoinField.fromJson(json['coursePlanModules']), + coursePlanTopics: JoinField.fromJson(json['coursePlanTopics']), createdBy: PolymorphicRelationship.fromJson(json['createdBy']), updatedBy: PolymorphicRelationship.fromJson(json['updatedBy']), updatedAt: json['updatedAt'], @@ -57,7 +58,7 @@ class CmsCoursePlan { 'l1': l1, 'l2': l2, 'coursePlanMedia': coursePlanMedia?.toJson(), - 'coursePlanModules': coursePlanModules?.toJson(), + 'coursePlanTopics': coursePlanTopics?.toJson(), 'createdBy': createdBy?.toJson(), 'updatedBy': updatedBy?.toJson(), 'updatedAt': updatedAt, diff --git a/lib/pangea/payload_client/models/course_plan/cms_course_plan_activity.dart b/lib/pangea/payload_client/models/course_plan/cms_course_plan_activity.dart index a34a2d238..412ce42ba 100644 --- a/lib/pangea/payload_client/models/course_plan/cms_course_plan_activity.dart +++ b/lib/pangea/payload_client/models/course_plan/cms_course_plan_activity.dart @@ -66,6 +66,8 @@ class CmsCoursePlanVocab { /// Represents a course plan activity from the CMS API class CmsCoursePlanActivity { + static const String slug = "course-plan-activities"; + final String id; final String title; final String description; @@ -77,7 +79,7 @@ class CmsCoursePlanActivity { final List roles; final List vocabs; final JoinField? coursePlanActivityMedia; - final List coursePlanModules; + final List coursePlanTopics; final PolymorphicRelationship? createdBy; final PolymorphicRelationship? updatedBy; final String updatedAt; @@ -95,7 +97,7 @@ class CmsCoursePlanActivity { required this.roles, required this.vocabs, required this.coursePlanActivityMedia, - required this.coursePlanModules, + required this.coursePlanTopics, this.createdBy, this.updatedBy, required this.updatedAt, @@ -129,7 +131,7 @@ class CmsCoursePlanActivity { .toList(), coursePlanActivityMedia: JoinField.fromJson(json['coursePlanActivityMedia']), - coursePlanModules: List.from(json['coursePlanModules']), + coursePlanTopics: List.from(json['coursePlanTopics']), createdBy: json['createdBy'] != null ? PolymorphicRelationship.fromJson(json['createdBy']) : null, @@ -154,7 +156,7 @@ class CmsCoursePlanActivity { 'roles': roles.map((role) => role.toJson()).toList(), 'vocabs': vocabs.map((vocab) => vocab.toJson()).toList(), 'coursePlanActivityMedia': coursePlanActivityMedia?.toJson(), - 'coursePlanModules': coursePlanModules, + 'coursePlanTopics': coursePlanTopics, 'createdBy': createdBy?.toJson(), 'updatedBy': updatedBy?.toJson(), 'updatedAt': updatedAt, diff --git a/lib/pangea/payload_client/models/course_plan/cms_course_plan_activity_media.dart b/lib/pangea/payload_client/models/course_plan/cms_course_plan_activity_media.dart index c54c4cd85..b1547840d 100644 --- a/lib/pangea/payload_client/models/course_plan/cms_course_plan_activity_media.dart +++ b/lib/pangea/payload_client/models/course_plan/cms_course_plan_activity_media.dart @@ -2,6 +2,8 @@ import 'package:fluffychat/pangea/payload_client/polymorphic_relationship.dart'; /// Represents course plan activity media from the CMS API class CmsCoursePlanActivityMedia { + static const String slug = "course-plan-activity-medias"; + final String id; final String? alt; final List coursePlanActivities; diff --git a/lib/pangea/payload_client/models/course_plan/cms_course_plan_media.dart b/lib/pangea/payload_client/models/course_plan/cms_course_plan_media.dart index 6765739d0..ae5b6b0ec 100644 --- a/lib/pangea/payload_client/models/course_plan/cms_course_plan_media.dart +++ b/lib/pangea/payload_client/models/course_plan/cms_course_plan_media.dart @@ -2,6 +2,7 @@ import 'package:fluffychat/pangea/payload_client/polymorphic_relationship.dart'; /// Represents course plan media from the CMS API class CmsCoursePlanMedia { + static const String slug = "course-plan-media"; final String id; final String? alt; final List coursePlans; diff --git a/lib/pangea/payload_client/models/course_plan/cms_course_plan_module.dart b/lib/pangea/payload_client/models/course_plan/cms_course_plan_topic.dart similarity index 77% rename from lib/pangea/payload_client/models/course_plan/cms_course_plan_module.dart rename to lib/pangea/payload_client/models/course_plan/cms_course_plan_topic.dart index f79542781..69186f03d 100644 --- a/lib/pangea/payload_client/models/course_plan/cms_course_plan_module.dart +++ b/lib/pangea/payload_client/models/course_plan/cms_course_plan_topic.dart @@ -1,25 +1,26 @@ import 'package:fluffychat/pangea/payload_client/join_field.dart'; import 'package:fluffychat/pangea/payload_client/polymorphic_relationship.dart'; -/// Represents a course plan module from the CMS API -class CmsCoursePlanModule { +/// Represents a course plan topic from the CMS API +class CmsCoursePlanTopic { + static const String slug = "course-plan-topics"; final String id; final String title; final String description; final JoinField? coursePlanActivities; - final JoinField? coursePlanModuleLocations; + final JoinField? coursePlanTopicLocations; final List coursePlans; final PolymorphicRelationship? createdBy; final PolymorphicRelationship? updatedBy; final String updatedAt; final String createdAt; - CmsCoursePlanModule({ + CmsCoursePlanTopic({ required this.id, required this.title, required this.description, required this.coursePlanActivities, - required this.coursePlanModuleLocations, + required this.coursePlanTopicLocations, required this.coursePlans, this.createdBy, this.updatedBy, @@ -27,16 +28,16 @@ class CmsCoursePlanModule { required this.createdAt, }); - factory CmsCoursePlanModule.fromJson(Map json) { - return CmsCoursePlanModule( + factory CmsCoursePlanTopic.fromJson(Map json) { + return CmsCoursePlanTopic( id: json['id'] as String, title: json['title'] as String, description: json['description'] as String, coursePlanActivities: JoinField.fromJson( json['coursePlanActivities'], ), - coursePlanModuleLocations: JoinField.fromJson( - json['coursePlanModuleLocations'], + coursePlanTopicLocations: JoinField.fromJson( + json['coursePlanTopicLocations'], ), coursePlans: List.from(json['coursePlans']), createdBy: json['createdBy'] != null @@ -56,7 +57,7 @@ class CmsCoursePlanModule { 'title': title, 'description': description, 'coursePlanActivities': coursePlanActivities?.toJson(), - 'coursePlanModuleLocations': coursePlanModuleLocations?.toJson(), + 'coursePlanTopicLocations': coursePlanTopicLocations?.toJson(), 'coursePlans': coursePlans, 'createdBy': createdBy?.toJson(), 'updatedBy': updatedBy?.toJson(), diff --git a/lib/pangea/payload_client/models/course_plan/cms_course_plan_module_location.dart b/lib/pangea/payload_client/models/course_plan/cms_course_plan_topic_location.dart similarity index 73% rename from lib/pangea/payload_client/models/course_plan/cms_course_plan_module_location.dart rename to lib/pangea/payload_client/models/course_plan/cms_course_plan_topic_location.dart index 77ca79c82..a4d92cd12 100644 --- a/lib/pangea/payload_client/models/course_plan/cms_course_plan_module_location.dart +++ b/lib/pangea/payload_client/models/course_plan/cms_course_plan_topic_location.dart @@ -1,36 +1,37 @@ import 'package:fluffychat/pangea/payload_client/polymorphic_relationship.dart'; -/// Represents a course plan module location from the CMS API -class CmsCoursePlanModuleLocation { +/// Represents a course plan topic location from the CMS API +class CmsCoursePlanTopicLocation { + static const String slug = "course-plan-topic-locations"; final String id; final String name; // [longitude, latitude] - minItems: 2, maxItems: 2 final List? coordinates; - final List coursePlanModules; + final List coursePlanTopics; final PolymorphicRelationship? createdBy; final PolymorphicRelationship? updatedBy; final String updatedAt; final String createdAt; - CmsCoursePlanModuleLocation({ + CmsCoursePlanTopicLocation({ required this.id, required this.name, this.coordinates, - required this.coursePlanModules, + required this.coursePlanTopics, this.createdBy, this.updatedBy, required this.updatedAt, required this.createdAt, }); - factory CmsCoursePlanModuleLocation.fromJson(Map json) { - return CmsCoursePlanModuleLocation( + factory CmsCoursePlanTopicLocation.fromJson(Map json) { + return CmsCoursePlanTopicLocation( id: json['id'] as String, name: json['name'] as String, coordinates: (json['coordinates'] as List?) ?.map((coord) => (coord as num).toDouble()) .toList(), - coursePlanModules: List.from(json['coursePlanModules']), + coursePlanTopics: List.from(json['coursePlanTopics']), createdBy: json['createdBy'] != null ? PolymorphicRelationship.fromJson(json['createdBy']) : null, @@ -47,7 +48,7 @@ class CmsCoursePlanModuleLocation { 'id': id, 'name': name, 'coordinates': coordinates, - 'coursePlanModules': coursePlanModules, + 'coursePlanTopics': coursePlanTopics, 'createdBy': createdBy?.toJson(), 'updatedBy': updatedBy?.toJson(), 'updatedAt': updatedAt, From d2ce1761d40863799ca30cad5cd45edd6a0b329f Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Fri, 29 Aug 2025 21:13:44 +1000 Subject: [PATCH 2/4] fix course plans query --- assets/.env | 3 +- .../course_plans/course_plan_model.dart | 46 +++++++++---------- .../course_plans/course_plans_repo.dart | 32 +++++++------ lib/pangea/payload_client/payload_client.dart | 41 +++++++++++++++-- 4 files changed, 81 insertions(+), 41 deletions(-) diff --git a/assets/.env b/assets/.env index 16a64f6e4..e334f398e 100644 --- a/assets/.env +++ b/assets/.env @@ -1,5 +1,6 @@ ENVIRONMENT = 'staging' -CHOREO_API = 'https://api.staging.pangea.chat' +# CHOREO_API = 'https://api.staging.pangea.chat' +CHOREO_API = 'http://localhost:3000' FRONTEND_URL = 'https://app.staging.pangea.chat' SYNAPSE_URL = 'matrix.staging.pangea.chat' diff --git a/lib/pangea/course_plans/course_plan_model.dart b/lib/pangea/course_plans/course_plan_model.dart index 23278c7a6..7fe723854 100644 --- a/lib/pangea/course_plans/course_plan_model.dart +++ b/lib/pangea/course_plans/course_plan_model.dart @@ -150,40 +150,40 @@ class CoursePlanModel { factory CoursePlanModel.fromCmsDocs( CmsCoursePlan cmsCoursePlan, List? cmsCoursePlanMedias, - List? cmsCoursePlanModules, - List? cmsCoursePlanModuleLocations, + List? cmsCoursePlanTopics, + List? cmsCoursePlanTopicLocations, List? cmsCoursePlanActivities, List? cmsCoursePlanActivityMedias, ) { // fetch topics List? topics; - if (cmsCoursePlanModules != null) { - for (final module in cmsCoursePlanModules) { - // select locations of current module - List? moduleLocations; - if (cmsCoursePlanModuleLocations != null) { - for (final location in cmsCoursePlanModuleLocations) { - if (location.coursePlanTopics.contains(module.id)) { - moduleLocations ??= []; - moduleLocations.add(location); + if (cmsCoursePlanTopics != null) { + for (final topic in cmsCoursePlanTopics) { + // select locations of current topic + List? topicLocations; + if (cmsCoursePlanTopicLocations != null) { + for (final location in cmsCoursePlanTopicLocations) { + if (location.coursePlanTopics.contains(topic.id)) { + topicLocations ??= []; + topicLocations.add(location); } } } - // select activities of current module - List? moduleActivities; + // select activities of current topic + List? topicActivities; if (cmsCoursePlanActivities != null) { for (final activity in cmsCoursePlanActivities) { - if (activity.coursePlanTopics.contains(module.id)) { - moduleActivities ??= []; - moduleActivities.add(activity); + if (activity.coursePlanTopics.contains(topic.id)) { + topicActivities ??= []; + topicActivities.add(activity); } } } List? activityPlans; - if (moduleActivities != null) { - for (final activity in moduleActivities) { + if (topicActivities != null) { + for (final activity in topicActivities) { // select media of current activity List? activityMedias; if (cmsCoursePlanActivityMedias != null) { @@ -238,11 +238,11 @@ class CoursePlanModel { topics ??= []; topics.add( Topic( - uuid: module.id, - title: module.title, - description: module.description, - location: moduleLocations != null && moduleLocations.isNotEmpty - ? moduleLocations.first.name + uuid: topic.id, + title: topic.title, + description: topic.description, + location: topicLocations != null && topicLocations.isNotEmpty + ? topicLocations.first.name : "Any", activities: activityPlans, ), diff --git a/lib/pangea/course_plans/course_plans_repo.dart b/lib/pangea/course_plans/course_plans_repo.dart index f5bcb304b..51bf3bfb1 100644 --- a/lib/pangea/course_plans/course_plans_repo.dart +++ b/lib/pangea/course_plans/course_plans_repo.dart @@ -195,19 +195,25 @@ class CoursePlansRepo { static Future _fromCmsCoursePlan( CmsCoursePlan cmsCoursePlan, ) async { - final medias = await _getMedia(cmsCoursePlan); - final topics = await _getTopics(cmsCoursePlan); - final locations = await _getTopicLocations(topics ?? []); - final activities = await _getTopicActivities(topics ?? []); - final activityMedias = await _getActivityMedia(activities ?? []); - return CoursePlanModel.fromCmsDocs( - cmsCoursePlan, - medias, - topics, - locations, - activities, - activityMedias, - ); + try { + final medias = await _getMedia(cmsCoursePlan); + final topics = await _getTopics(cmsCoursePlan); + final locations = await _getTopicLocations(topics ?? []); + final activities = await _getTopicActivities(topics ?? []); + final activityMedias = await _getActivityMedia(activities ?? []); + return CoursePlanModel.fromCmsDocs( + cmsCoursePlan, + medias, + topics, + locations, + activities, + activityMedias, + ); + } catch (e, stack) { + print(e); + print(stack); + rethrow; + } } static Future?> _getMedia( diff --git a/lib/pangea/payload_client/payload_client.dart b/lib/pangea/payload_client/payload_client.dart index 476ba7156..b0717b5e7 100644 --- a/lib/pangea/payload_client/payload_client.dart +++ b/lib/pangea/payload_client/payload_client.dart @@ -114,16 +114,15 @@ class PayloadClient { Map? where, String? sort, }) async { - final queryParams = {}; + final Map queryParams = {}; if (page != null) queryParams['page'] = page.toString(); if (limit != null) queryParams['limit'] = limit.toString(); - if (where != null) queryParams['where'] = jsonEncode(where); + if (where != null && where.isNotEmpty) queryParams['where'] = where; if (sort != null) queryParams['sort'] = sort; final endpoint = - '$basePath/$collection${queryParams.isNotEmpty ? '?${Uri(queryParameters: queryParams).query}' : ''}'; - + '$basePath/$collection${queryParams.isNotEmpty ? '?${queryStringify(queryParams)}' : ''}'; final response = await get(endpoint); final json = jsonDecode(response.body) as Map; @@ -178,4 +177,38 @@ class PayloadClient { final json = jsonDecode(response.body) as Map; return fromJson(json); } + + static String queryStringify( + Map params, { + bool encode = true, + }) { + final List parts = []; + + void build(String prefix, dynamic value) { + if (value == null) return; + + if (value is Map) { + value.forEach((k, v) { + build('$prefix[$k]', v); + }); + } else if (value is List) { + for (var i = 0; i < value.length; i++) { + build('$prefix[$i]', value[i]); + } + } else { + final String encodedKey = + encode ? Uri.encodeQueryComponent(prefix) : prefix; + final String encodedVal = encode + ? Uri.encodeQueryComponent(value.toString()) + : value.toString(); + parts.add('$encodedKey=$encodedVal'); + } + } + + params.forEach((key, value) { + build(key, value); + }); + + return parts.join('&'); + } } From 6f683b7559c9cda782d9b2dbc5bf5695d96ef8c6 Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Mon, 1 Sep 2025 11:49:03 +1000 Subject: [PATCH 3/4] fix choreo api env --- assets/.env | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/assets/.env b/assets/.env index e334f398e..16a64f6e4 100644 --- a/assets/.env +++ b/assets/.env @@ -1,6 +1,5 @@ ENVIRONMENT = 'staging' -# CHOREO_API = 'https://api.staging.pangea.chat' -CHOREO_API = 'http://localhost:3000' +CHOREO_API = 'https://api.staging.pangea.chat' FRONTEND_URL = 'https://app.staging.pangea.chat' SYNAPSE_URL = 'matrix.staging.pangea.chat' From 0e8a5cd9dcf61f517eea7c828812fd93bda9fffb Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Tue, 2 Sep 2025 00:47:33 +1000 Subject: [PATCH 4/4] fix media 404s --- .../models/course_plan/cms_course_plan_activity_media.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pangea/payload_client/models/course_plan/cms_course_plan_activity_media.dart b/lib/pangea/payload_client/models/course_plan/cms_course_plan_activity_media.dart index b1547840d..611a8ef74 100644 --- a/lib/pangea/payload_client/models/course_plan/cms_course_plan_activity_media.dart +++ b/lib/pangea/payload_client/models/course_plan/cms_course_plan_activity_media.dart @@ -2,7 +2,7 @@ import 'package:fluffychat/pangea/payload_client/polymorphic_relationship.dart'; /// Represents course plan activity media from the CMS API class CmsCoursePlanActivityMedia { - static const String slug = "course-plan-activity-medias"; + static const String slug = "course-plan-activity-media"; final String id; final String? alt;