diff --git a/client/src/components/modules/ModuleFilter.vue b/client/src/components/modules/ModuleFilter.vue index cceefa1a..70ada7b3 100644 --- a/client/src/components/modules/ModuleFilter.vue +++ b/client/src/components/modules/ModuleFilter.vue @@ -63,6 +63,7 @@ moduleLevels { name id + filterAttributeType } } `); @@ -70,19 +71,23 @@ const nullLevel = { name: '---', id: null, + filterAttributeType: 'ALL' }; + + const nullCategory = { + name: '---', + id: null, + filterAttributeType: 'ALL' + }; + let defaultLevel = loadDefaultLevel(props.me); let selectedLevel = ref(defaultLevel); const levelOptions = computed(() => { - return [nullLevel, ...moduleLevelsResult.value?.moduleLevels || []]; + return [...moduleLevelsResult.value?.moduleLevels || []]; }); - const nullCategory = { - name: '---', - id: null, - }; const selectedCategory = ref(nullCategory); @@ -91,12 +96,20 @@ moduleCategories { name id + filterAttributeType } } `); const categoryOptions = computed(() => { - return [nullCategory, ...moduleCategoryResult.value?.moduleCategories || []]; + if (moduleCategoryResult.value){ + const moduleCategories = moduleCategoryResult.value?.moduleCategories; + + // TODO: Fix this, computed must not have a sideeffect + selectedCategory.value = moduleCategories.find((category) => category.filterAttributeType === 'ALL'); + return moduleCategories + } + return [...moduleCategoryResult.value?.moduleCategories || []]; }); @@ -118,14 +131,14 @@ } // filter by Lehrjahr (moduleLevel) - if (selectedLevel.value.name !== '---') { + if (selectedLevel.value.filterAttributeType !== 'ALL') { filteredModules = filteredModules.filter((module) => { return module.level?.id == selectedLevel.value.id; }); } //filter by Lernfeld (Category) - if (selectedCategory.value.name !== '---') { + if (selectedCategory.value.filterAttributeType !== 'ALL') { filteredModules = filteredModules.filter((module) => { return module.category?.id == selectedCategory.value.id; }); diff --git a/server/books/models/module.py b/server/books/models/module.py index d732df28..8aaeac95 100644 --- a/server/books/models/module.py +++ b/server/books/models/module.py @@ -9,8 +9,18 @@ from core.wagtail_utils import StrictHierarchyPage, get_default_settings from users.models import SchoolClass from django.utils.text import slugify +FILTER_ATTRIBUTE_TYPE = ( + ('all', 'All'), + ('exact', 'Exact') +) + class ModuleLevel(models.Model): name = models.CharField(max_length=255, unique=True) + filter_attribute_type = models.CharField( + max_length=16, + choices=FILTER_ATTRIBUTE_TYPE, + default='exact' + ) def __str__(self): return self.name @@ -31,6 +41,11 @@ class ModuleCategory(models.Model): ordering = ("name",) name = models.CharField(max_length=255) + filter_attribute_type = models.CharField( + max_length=16, + choices=FILTER_ATTRIBUTE_TYPE, + default='exact' + ) def __str__(self): return f"{self.name}" diff --git a/server/books/schema/nodes/module_category.py b/server/books/schema/nodes/module_category.py index add10b08..134d03ef 100644 --- a/server/books/schema/nodes/module_category.py +++ b/server/books/schema/nodes/module_category.py @@ -12,4 +12,5 @@ class ModuleCategoryNode(DjangoObjectType): only_fields = [ "id", "name", + "filter_attribute_type", ] diff --git a/server/books/schema/nodes/module_level.py b/server/books/schema/nodes/module_level.py index 165d8e83..ed6c8108 100644 --- a/server/books/schema/nodes/module_level.py +++ b/server/books/schema/nodes/module_level.py @@ -12,4 +12,6 @@ class ModuleLevelNode(DjangoObjectType): only_fields = [ "id", "name", + "filter_attribute_type", + ] diff --git a/server/schema.graphql b/server/schema.graphql index 27d5ca92..79bc871c 100644 --- a/server/schema.graphql +++ b/server/schema.graphql @@ -621,9 +621,15 @@ type ModuleBookmarkNode { module: ModuleNode! } +enum ModuleCategoryFilterAttributeType { + ALL + EXACT +} + type ModuleCategoryNode implements Node { id: ID! name: String! + filterAttributeType: ModuleCategoryFilterAttributeType! } type ModuleConnection { @@ -644,10 +650,23 @@ interface ModuleInterface { topic: TopicNode } +enum ModuleLevelFilterAttributeType { + ALL + EXACT +} + +type ModuleLevelNode implements Node { + id: ID! + name: String! + filterAttributeType: ModuleLevelFilterAttributeType! +} + type ModuleNode implements ModuleInterface { title: String! slug: String! metaTitle: String! + level: ModuleLevelNode + category: ModuleCategoryNode heroImage: String! heroSource: String! teaser: String! @@ -665,8 +684,6 @@ type ModuleNode implements ModuleInterface { myContentBookmarks(offset: Int, before: String, after: String, first: Int, last: Int): ContentBlockBookmarkNodeConnection myChapterBookmarks(offset: Int, before: String, after: String, first: Int, last: Int): ChapterBookmarkNodeConnection snapshots: [SnapshotNode] - categoryName: String - categoryTypeName: String } type ModuleNodeConnection { @@ -742,6 +759,7 @@ type Mutation { updateSolutionVisibility(input: UpdateSolutionVisibilityInput!): UpdateSolutionVisibilityPayload updateLastModule(input: UpdateLastModuleInput!): UpdateLastModulePayload updateLastTopic(input: UpdateLastTopicInput!): UpdateLastTopicPayload + updateLastModuleLevel(input: UpdateLastModuleLevelInput!): UpdateLastModuleLevelPayload updateChapterVisibility(input: UpdateChapterVisibilityInput!): UpdateChapterVisibilityPayload syncModuleVisibility(input: SyncModuleVisibilityInput!): SyncModuleVisibilityPayload createSnapshot(input: CreateSnapshotInput!): CreateSnapshotPayload @@ -854,6 +872,7 @@ type PrivateUserNode implements Node { avatarUrl: String! username: String! lastModule: ModuleNode + lastModuleLevel: ModuleLevelNode lastTopic: TopicNode email: String! onboardingVisited: Boolean! @@ -935,6 +954,8 @@ type Query { topics(before: String, after: String, first: Int, last: Int): TopicConnection modules(before: String, after: String, first: Int, last: Int): ModuleConnection chapters(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, title: String): ChapterNodeConnection + moduleLevel(id: ID!): ModuleLevelNode + moduleLevels: [ModuleLevelNode] moduleCategory(id: ID!): ModuleCategoryNode moduleCategories: [ModuleCategoryNode] objectiveGroup(id: ID!): ObjectiveGroupNode @@ -1315,6 +1336,16 @@ input UpdateLastModuleInput { clientMutationId: String } +input UpdateLastModuleLevelInput { + id: ID + clientMutationId: String +} + +type UpdateLastModuleLevelPayload { + user: PrivateUserNode + clientMutationId: String +} + type UpdateLastModulePayload { lastModule: ModuleNode clientMutationId: String