Integrate language into module filter

This commit is contained in:
Ramon Wenger 2023-08-24 19:49:09 +02:00
parent 81b2b41979
commit c2b8bc1762
9 changed files with 301 additions and 231 deletions

View File

@ -16,6 +16,7 @@ const documents = {
"\n query LanguageQuery {\n me {\n language @client\n }\n }\n ": types.LanguageQueryDocument,
"\n mutation SetLanguage($language: String!) {\n setLanguage(language: $language) @client {\n language\n }\n }\n ": types.SetLanguageDocument,
"\n query ReadOnlyQuery {\n me {\n readOnly\n selectedClass {\n readOnly\n }\n }\n }\n ": types.ReadOnlyQueryDocument,
"\n query ModuleFilterQuery {\n moduleLevels {\n name\n id\n filterAttributeType\n }\n moduleCategories {\n name\n id\n filterAttributeType\n }\n me {\n language @client\n }\n }\n ": types.ModuleFilterQueryDocument,
"\n query ModuleTitleQuery($slug: String) {\n module(slug: $slug) {\n title\n }\n }\n ": types.ModuleTitleQueryDocument,
"\n fragment SnapshotListItem on SnapshotNode {\n shared\n }\n": types.SnapshotListItemFragmentDoc,
"\n fragment SnapshotTitle on SnapshotNode {\n title\n }\n": types.SnapshotTitleFragmentDoc,
@ -52,6 +53,10 @@ export function graphql(source: "\n mutation SetLanguage($language: String!)
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query ReadOnlyQuery {\n me {\n readOnly\n selectedClass {\n readOnly\n }\n }\n }\n "): (typeof documents)["\n query ReadOnlyQuery {\n me {\n readOnly\n selectedClass {\n readOnly\n }\n }\n }\n "];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query ModuleFilterQuery {\n moduleLevels {\n name\n id\n filterAttributeType\n }\n moduleCategories {\n name\n id\n filterAttributeType\n }\n me {\n language @client\n }\n }\n "): (typeof documents)["\n query ModuleFilterQuery {\n moduleLevels {\n name\n id\n filterAttributeType\n }\n moduleCategories {\n name\n id\n filterAttributeType\n }\n me {\n language @client\n }\n }\n "];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/

View File

@ -688,6 +688,34 @@ export type ModuleBookmarkNode = {
user: PrivateUserNode;
};
export enum ModuleCategoryFilterAttributeType {
All = 'ALL',
Exact = 'EXACT'
}
export type ModuleCategoryNode = Node & {
__typename?: 'ModuleCategoryNode';
filterAttributeType: ModuleCategoryFilterAttributeType;
id: Scalars['ID']['output'];
moduleSet: ModuleNodeConnection;
name: Scalars['String']['output'];
};
export type ModuleCategoryNodeModuleSetArgs = {
after?: InputMaybe<Scalars['String']['input']>;
before?: InputMaybe<Scalars['String']['input']>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
offset?: InputMaybe<Scalars['Int']['input']>;
slug?: InputMaybe<Scalars['String']['input']>;
slug_Icontains?: InputMaybe<Scalars['String']['input']>;
slug_In?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>>;
title?: InputMaybe<Scalars['String']['input']>;
title_Icontains?: InputMaybe<Scalars['String']['input']>;
title_In?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>>;
};
export type ModuleConnection = {
__typename?: 'ModuleConnection';
edges: Array<Maybe<ModuleEdge>>;
@ -708,16 +736,47 @@ export type ModuleInterface = {
topic?: Maybe<TopicNode>;
};
export enum ModuleLevelFilterAttributeType {
All = 'ALL',
Exact = 'EXACT'
}
export type ModuleLevelNode = Node & {
__typename?: 'ModuleLevelNode';
filterAttributeType: ModuleLevelFilterAttributeType;
id: Scalars['ID']['output'];
moduleSet: ModuleNodeConnection;
name: Scalars['String']['output'];
};
export type ModuleLevelNodeModuleSetArgs = {
after?: InputMaybe<Scalars['String']['input']>;
before?: InputMaybe<Scalars['String']['input']>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
offset?: InputMaybe<Scalars['Int']['input']>;
slug?: InputMaybe<Scalars['String']['input']>;
slug_Icontains?: InputMaybe<Scalars['String']['input']>;
slug_In?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>>;
title?: InputMaybe<Scalars['String']['input']>;
title_Icontains?: InputMaybe<Scalars['String']['input']>;
title_In?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>>;
};
export type ModuleNode = ModuleInterface & {
__typename?: 'ModuleNode';
assignments?: Maybe<Array<Maybe<AssignmentNode>>>;
bookmark?: Maybe<ModuleBookmarkNode>;
category?: Maybe<ModuleCategoryNode>;
chapters?: Maybe<Array<Maybe<ChapterNode>>>;
heroImage: Scalars['String']['output'];
heroSource: Scalars['String']['output'];
id: Scalars['ID']['output'];
inEditMode: Scalars['Boolean']['output'];
intro: Scalars['String']['output'];
language?: Maybe<Scalars['String']['output']>;
level?: Maybe<ModuleLevelNode>;
metaTitle: Scalars['String']['output'];
myAnswers?: Maybe<AnswerNodeConnection>;
myChapterBookmarks?: Maybe<ChapterBookmarkNodeConnection>;
@ -836,6 +895,7 @@ export type Mutation = {
updateContentBookmark?: Maybe<UpdateContentBookmarkPayload>;
updateInstrumentBookmark?: Maybe<UpdateInstrumentBookmarkPayload>;
updateLastModule?: Maybe<UpdateLastModulePayload>;
updateLastModuleLevel?: Maybe<UpdateLastModuleLevelPayload>;
updateLastTopic?: Maybe<UpdateLastTopicPayload>;
updateModuleBookmark?: Maybe<UpdateModuleBookmarkPayload>;
updateNote?: Maybe<UpdateNotePayload>;
@ -1048,6 +1108,11 @@ export type MutationUpdateLastModuleArgs = {
};
export type MutationUpdateLastModuleLevelArgs = {
input: UpdateLastModuleLevelInput;
};
export type MutationUpdateLastTopicArgs = {
input: UpdateLastTopicInput;
};
@ -1263,6 +1328,7 @@ export type PrivateUserNode = Node & {
isTeacher?: Maybe<Scalars['Boolean']['output']>;
language?: Maybe<Scalars['String']['output']>;
lastModule?: Maybe<ModuleNode>;
lastModuleLevel?: Maybe<ModuleLevelNode>;
lastName: Scalars['String']['output'];
lastTopic?: Maybe<TopicNode>;
oldClasses?: Maybe<Array<Maybe<SchoolClassNode>>>;
@ -1352,6 +1418,10 @@ export type Query = {
instruments?: Maybe<Array<Maybe<InstrumentNode>>>;
me?: Maybe<PrivateUserNode>;
module?: Maybe<ModuleNode>;
moduleCategories?: Maybe<Array<Maybe<ModuleCategoryNode>>>;
moduleCategory?: Maybe<ModuleCategoryNode>;
moduleLevel?: Maybe<ModuleLevelNode>;
moduleLevels?: Maybe<Array<Maybe<ModuleLevelNode>>>;
moduleRoom?: Maybe<RoomNode>;
modules?: Maybe<ModuleConnection>;
myActivity?: Maybe<ModuleNodeConnection>;
@ -1433,6 +1503,16 @@ export type QueryModuleArgs = {
};
export type QueryModuleCategoryArgs = {
id: Scalars['ID']['input'];
};
export type QueryModuleLevelArgs = {
id: Scalars['ID']['input'];
};
export type QueryModuleRoomArgs = {
classId?: InputMaybe<Scalars['ID']['input']>;
slug?: InputMaybe<Scalars['String']['input']>;
@ -2002,6 +2082,17 @@ export type UpdateLastModuleInput = {
id?: InputMaybe<Scalars['ID']['input']>;
};
export type UpdateLastModuleLevelInput = {
clientMutationId?: InputMaybe<Scalars['String']['input']>;
id?: InputMaybe<Scalars['ID']['input']>;
};
export type UpdateLastModuleLevelPayload = {
__typename?: 'UpdateLastModuleLevelPayload';
clientMutationId?: Maybe<Scalars['String']['output']>;
user?: Maybe<PrivateUserNode>;
};
export type UpdateLastModulePayload = {
__typename?: 'UpdateLastModulePayload';
clientMutationId?: Maybe<Scalars['String']['output']>;
@ -2293,6 +2384,11 @@ export type ReadOnlyQueryQueryVariables = Exact<{ [key: string]: never; }>;
export type ReadOnlyQueryQuery = { __typename?: 'Query', me?: { __typename?: 'PrivateUserNode', readOnly?: boolean | null, selectedClass?: { __typename?: 'SchoolClassNode', readOnly?: boolean | null } | null } | null };
export type ModuleFilterQueryQueryVariables = Exact<{ [key: string]: never; }>;
export type ModuleFilterQueryQuery = { __typename?: 'Query', moduleLevels?: Array<{ __typename?: 'ModuleLevelNode', name: string, id: string, filterAttributeType: ModuleLevelFilterAttributeType } | null> | null, moduleCategories?: Array<{ __typename?: 'ModuleCategoryNode', name: string, id: string, filterAttributeType: ModuleCategoryFilterAttributeType } | null> | null, me?: { __typename?: 'PrivateUserNode', language?: string | null } | null };
export type ModuleTitleQueryQueryVariables = Exact<{
slug?: InputMaybe<Scalars['String']['input']>;
}>;
@ -2347,6 +2443,7 @@ export const SnapshotTitleFragmentDoc = {"kind":"Document","definitions":[{"kind
export const LanguageQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"LanguageQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"client"}}]}]}}]}}]} as unknown as DocumentNode<LanguageQueryQuery, LanguageQueryQueryVariables>;
export const SetLanguageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SetLanguage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"language"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setLanguage"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"language"},"value":{"kind":"Variable","name":{"kind":"Name","value":"language"}}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"client"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}}]}}]}}]} as unknown as DocumentNode<SetLanguageMutation, SetLanguageMutationVariables>;
export const ReadOnlyQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ReadOnlyQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"readOnly"}},{"kind":"Field","name":{"kind":"Name","value":"selectedClass"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"readOnly"}}]}}]}}]}}]} as unknown as DocumentNode<ReadOnlyQueryQuery, ReadOnlyQueryQueryVariables>;
export const ModuleFilterQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ModuleFilterQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"moduleLevels"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"filterAttributeType"}}]}},{"kind":"Field","name":{"kind":"Name","value":"moduleCategories"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"filterAttributeType"}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"client"}}]}]}}]}}]} as unknown as DocumentNode<ModuleFilterQueryQuery, ModuleFilterQueryQueryVariables>;
export const ModuleTitleQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ModuleTitleQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"slug"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"module"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"slug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode<ModuleTitleQueryQuery, ModuleTitleQueryQueryVariables>;
export const ModuleEditModeQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ModuleEditModeQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"slug"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"module"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"slug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"inEditMode"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"client"}}]},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]} as unknown as DocumentNode<ModuleEditModeQueryQuery, ModuleEditModeQueryQueryVariables>;
export const ChapterQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ChapterQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chapter"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"path"}}]}}]}}]} as unknown as DocumentNode<ChapterQueryQuery, ChapterQueryQueryVariables>;

View File

@ -1,24 +1,10 @@
<template>
<div class="language-switcher">
<span>{{ language }} {{ language === 'de' }}</span>
<a
class="language-switcher__language"
:class="{ 'language-switcher__language--active': language === 'de' }"
@click="changeLanguage('de')"
>de</a
>
<a
class="language-switcher__language"
:class="{ 'language-switcher__language--active': language === 'en' }"
@click="changeLanguage('en')"
>en</a
>
<a
class="language-switcher__language"
:class="{ 'language-switcher__language--active': language === 'fr' }"
@click="changeLanguage('fr')"
>fr</a
>
<pill-radio-buttons
:items="languages"
:selected-item="language"
@update:selected-item="changeLanguage"
/>
</div>
</template>
@ -26,6 +12,7 @@
import { graphql } from '@/__generated__';
import { useMutation, useQuery } from '@vue/apollo-composable';
import { computed } from '@vue/reactivity';
import PillRadioButtons from '@/components/ui/PillRadioButtons.vue';
const { result } = useQuery(
graphql(`
@ -37,7 +24,8 @@ const { result } = useQuery(
`)
);
const language = computed(() => result.value?.me.language || '');
const languages = ['de', 'en', 'fr'];
const language = computed(() => result.value?.me.language || 'de');
const { mutate: changeLanguageMutation } = useMutation(
graphql(`
mutation SetLanguage($language: String!) {
@ -53,22 +41,5 @@ const changeLanguage = (lang: string) => changeLanguageMutation({ language: lang
<style scoped lang="postcss">
.language-switcher {
border-radius: 30px;
border: 1px solid black;
display: inline-flex;
&__language {
text-transform: uppercase;
padding: 10px 20px;
border-right: 1px solid black;
&:last-child {
border-right: 0;
}
&--active {
color: red;
}
}
}
</style>

View File

@ -6,20 +6,16 @@
:selected-item="selectedLevel"
:items="moduleLevels"
@update:selectedItem="updateLevel"
></Dropdown>
/>
<Dropdown
class="module-filter__dropdown"
:selected-item="selectedCategory"
:items="moduleCategories"
@update:selectedItem="newItem => selectedCategory = newItem"
></Dropdown>
<pill-radio-buttons
:selectableItems="languageOptions"
:defaultSelectedItem="initialLanguage"
class="module-filter__language-selection"
@update:selectedItem="item => selectedLanguage = item"/>
@update:selectedItem="(newItem) => (selectedCategory = newItem)"
/>
<language-switcher />
</div>
<div class="topic__modules">
<module-teaser
@ -28,172 +24,166 @@
:key="module.slug"
/>
</div>
</div>
</template>
<script setup lang="ts">
import {computed, ref} from "vue";
import ModuleTeaser from "@/components/modules/ModuleTeaser.vue";
import {useQuery, useMutation} from "@vue/apollo-composable";
import Dropdown from "@/components/ui/Dropdown.vue";
import PillRadioButtons from "@/components/ui/PillRadioButtons.vue";
import gql from "graphql-tag";
import { computed, ref } from 'vue';
import ModuleTeaser from '@/components/modules/ModuleTeaser.vue';
import { useQuery, useMutation } from '@vue/apollo-composable';
import Dropdown from '@/components/ui/Dropdown.vue';
import LanguageSwitcher from '@/components/LanguageSwitcher.vue';
import { graphql } from '@/__generated__';
const props = defineProps<{
modules: Object[];
me: any;
}>();
const props = defineProps<{
modules: Object[];
me: any;
}>();
const initialCategory = {
name: 'Alle Lernfelder',
id: null,
filterAttributeType: 'ALL',
};
const languageOptions: Array<{ id: number, label: string }> = ref([
{id: 1, label: 'De'},
{id: 2, label: 'Fr'},
{id: 3, label: 'En'}
])
const initialLanguage = languageOptions.value[0]
const selectedLanguage = ref(initialLanguage)
const initialLevel = {
name: 'Alle Lehrjahre',
id: null,
filterAttributeType: 'ALL',
};
const initialCategory = {
name: 'Alle Lernfelder',
id: null,
filterAttributeType: 'ALL'
};
const initialLevel = {
name: 'Alle Lehrjahre',
id: null,
filterAttributeType: 'ALL'
};
const {result: moduleFilterResult} = useQuery(gql`
query ModuleFilterQuery{
const { result: moduleFilterResult } = useQuery(
graphql(`
query ModuleFilterQuery {
moduleLevels {
name
id
filterAttributeType
}
moduleCategories {
moduleCategories {
name
id
filterAttributeType
}
me {
language @client
}
}
`);
`)
);
const selectedLevel = ref(initialLevel);
const selectedCategory = ref(initialCategory);
const selectedLevel = ref(initialLevel);
const selectedCategory = ref(initialCategory);
selectedLevel.value = loadDefaultLevel(props.me);
selectedLevel.value = loadDefaultLevel(props.me);
const moduleLevels = computed(() => moduleFilterResult.value?.moduleLevels || []);
const moduleCategories = computed(() => moduleFilterResult.value?.moduleCategories || []);
const filteredModules = computed(() => props.modules?.filter(module => filterModule(module,
selectedLevel.value, selectedCategory.value, selectedLanguage.value)) || []);
const moduleLevels = computed(() => moduleFilterResult.value?.moduleLevels || []);
const moduleCategories = computed(() => moduleFilterResult.value?.moduleCategories || []);
const language = computed(() => moduleFilterResult.value?.me.language || 'de');
const filteredModules = computed(
() =>
props.modules?.filter((module) =>
filterModule(module, selectedLevel.value, selectedCategory.value, language.value)
) || []
);
function loadDefaultLevel(me) {
return me?.lastModuleLevel || initialLevel;
}
function loadDefaultLevel(me) {
return me?.lastModuleLevel || initialLevel;
}
function filterModule(module: Object, selectedLevel, selectedCategory, selectedLanguage) {
let filterExpression = true;
function filterModule(module: Object, selectedLevel, selectedCategory, selectedLanguage) {
let filterExpression = true;
filterExpression =
filterByLevel(module, selectedLevel) &&
filterByCategory(module, selectedCategory) &&
filterByLanguage(module, selectedLanguage);
return filterExpression;
}
filterExpression = filterByLevel(module, selectedLevel) &&
filterByCategory(module, selectedCategory) &&
filterByLanguage(module, selectedLanguage);
return filterExpression;
}
const updateLevel = (level) => {
selectedLevel.value = level;
updateLastModuleLevelUser(level);
};
const updateLevel = (level) => {
selectedLevel.value = level;
updateLastModuleLevelUser(level);
}
const filterByLevel = (module, level) => {
return level.filterAttributeType === 'ALL' || module.level?.id === level.id;
};
const filterByLevel = (module, level) => {
return level.filterAttributeType === 'ALL' || module.level?.id === level.id
}
const filterByCategory = (module, category) => {
return category.filterAttributeType === 'ALL' || module.category?.id === category.id;
};
const filterByCategory = (module, category) => {
return category.filterAttributeType === 'ALL' || module.category?.id === category.id
}
const filterByLanguage = (module: Object, language: Object) => {
// TODO: implement filter by language here.
return module.language === language;
};
const filterByLanguage = (module: Object, language: Object) => {
// TODO: implement filter by language here.
console.log("selectedLanguage", selectedLanguage.value, language);
console.log("module.languages", module);
return true
}
const { mutate: updateLastModuleLevel } = useMutation(
graphql(`
mutation ($input: UpdateLastModuleLevelInput!) {
updateLastModuleLevel(input: $input) {
clientMutationId
user {
username
lastModuleLevel {
name
id
}
}
}
}
`)
);
const {mutate: updateLastModuleLevel} = useMutation(gql `
mutation ($input: UpdateLastModuleLevelInput!){
updateLastModuleLevel(input: $input) {
clientMutationId
user {
username
lastModuleLevel {
name
id
}
}
}
}`);
const updateLastModuleLevelUser = (moduleLevel: Object) => {
updateLastModuleLevel({
input: {
id: moduleLevel.id,
},
});
}
const updateLastModuleLevelUser = (moduleLevel: Object) => {
updateLastModuleLevel({
input: {
id: moduleLevel.id,
},
});
};
</script>
<style scoped lang="scss">
@import 'styles/helpers';
@import 'styles/helpers';
.module-filter {
// TODO: how do I correcty set the with of the whole thig including the grid for the modules?
// TODO: Farbe des Arrows für Dropdowns muss platfrom habhängig sein MS-775
.module-filter {
// TODO: how do I correcty set the with of the whole thig including the grid for the modules?
// TODO: Farbe des Arrows für Dropdowns muss platfrom habhängig sein MS-775
width: 75%;
width: 75%;
&__filterselection {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
&__dropdown {
margin-right: $medium-spacing;
width: 300px;
}
&__language-selection {
margin-left: auto;
}
&__filterselection {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.topic {
&__modules {
margin-top: 40px;
display: flex;
flex-wrap: wrap;
@supports (display: grid) {
display: grid;
}
grid-column-gap: $large-spacing;
grid-row-gap: $large-spacing;
@include desktop {
grid-template-columns: repeat(3, minmax(auto, 380px));
}
}
&__dropdown {
margin-right: $medium-spacing;
width: 300px;
}
&__language-selection {
margin-left: auto;
}
}
.topic {
&__modules {
margin-top: 40px;
display: flex;
flex-wrap: wrap;
@supports (display: grid) {
display: grid;
}
grid-column-gap: $large-spacing;
grid-row-gap: $large-spacing;
@include desktop {
grid-template-columns: repeat(3, minmax(auto, 380px));
}
}
}
</style>

View File

@ -8,9 +8,7 @@
class="module-teaser__image"
/>
<div class="module-teaser__body">
<h3 class="module-teaser__meta-title">
{{ metaTitle }}
</h3>
<h3 class="module-teaser__meta-title">{{ metaTitle }}</h3>
<h3 class="module-teaser__title">
{{ title }}
</h3>

View File

@ -2,68 +2,60 @@
<div class="pill-radio">
<button
:class="['pill-radio__button', { 'pill-radio__button--active': item === selectedItem }]"
v-for="item in props.selectableItems"
:key="item.id"
v-for="item in props.items"
:key="item"
@click="updateSelectedItem(item)"
>
{{ item.label }}
{{ item }}
</button>
</div>
</template>
<script setup lang="ts">
import {ref} from 'vue';
const emit = defineEmits(['update:selectedItem']);
const emit = defineEmits(['update:selectedItem']);
const props = defineProps<{
selectableItems: Object;
defaultSelectedItem: Object;
}>();
const selectedItem = ref(props.defaultSelectedItem)
function updateSelectedItem(item: object) {
emit('update:selectedItem', item);
selectedItem.value = item
}
const props = defineProps<{
items: string[];
selectedItem: string;
}>();
function updateSelectedItem(item: string) {
emit('update:selectedItem', item);
}
</script>
<style scoped lang="scss">
@import 'styles/helpers';
@import 'styles/helpers';
.pill-radio {
display: flex;
overflow: hidden;
height: 40px;
.pill-radio {
display: flex;
overflow: hidden;
height: 40px;
&__button {
flex: 1;
cursor: pointer;
background-color: $color-silver-light;
&__button {
flex: 1;
cursor: pointer;
background-color: $color-silver-light;
outline: none;
padding-left: 1rem;
padding-right: 1rem;
border: none;
outline: none;
padding-left: 1rem;
padding-right: 1rem;
border: none;
&--active {
background-color: white;
border: solid $color-silver 1px;
}
}
&__button:first-child {
border-top-left-radius: $round-border-radius;
border-bottom-left-radius: $round-border-radius;
}
&__button:last-child {
border-top-right-radius: $round-border-radius;
border-bottom-right-radius: $round-border-radius;
&--active {
background-color: white;
border: solid $color-silver 1px;
}
}
&__button:first-child {
border-top-left-radius: $round-border-radius;
border-bottom-left-radius: $round-border-radius;
}
&__button:last-child {
border-top-right-radius: $round-border-radius;
border-bottom-right-radius: $round-border-radius;
}
}
</style>

View File

@ -6,9 +6,9 @@ from graphene_django.filter import DjangoFilterConnectionField
from books.models import Topic, Module
from books.schema.nodes import ModuleNode
class NotFoundFailure:
reason = 'Not Found'
class NotFoundFailure:
reason = "Not Found"
class NotFound(graphene.ObjectType):
@ -22,11 +22,17 @@ class TopicNode(DjangoObjectType):
class Meta:
model = Topic
only_fields = [
'slug', 'title', 'teaser', 'description', 'vimeo_id', 'order', 'instructions'
"slug",
"title",
"teaser",
"description",
"vimeo_id",
"order",
"instructions",
]
filter_fields = {
'slug': ['exact', 'icontains', 'in'],
'title': ['exact', 'icontains', 'in'],
"slug": ["exact", "icontains", "in"],
"title": ["exact", "icontains", "in"],
}
interfaces = (relay.Node,)
@ -34,7 +40,11 @@ class TopicNode(DjangoObjectType):
return self.id
def resolve_modules(self, *args, **kwargs):
return Module.get_by_parent(self)
translations = self.get_translations()
ids = list(self.get_child_ids())
for translation in translations:
ids += list(translation.get_child_ids())
return Module.objects.filter(id__in=ids).live()
class TopicOr404Node(graphene.Union):

View File

@ -60,6 +60,8 @@ INSTALLED_APPS = [
"wagtail.documents",
"wagtail.images",
"wagtail.search",
"wagtail.locales",
"wagtail.contrib.simple_translation",
"wagtail.admin",
"wagtail",
"wagtail.api.v2",
@ -185,6 +187,7 @@ LANGUAGE_CODE = "de"
TIME_ZONE = "UTC"
USE_I18N = True
WAGTAIL_I18N_ENABLED = True
USE_L10N = True
@ -193,6 +196,7 @@ USE_TZ = True
LANGUAGES = [
("de", _("German")),
("en", _("English")),
("fr", _("French")),
]
LOCALE_PATHS = [os.path.join(BASE_DIR, "locale")]

View File

@ -236,7 +236,7 @@ interface ChapterInterface {
title: String
}
type ChapterNode implements Node, ChapterInterface {
type ChapterNode implements Node & ChapterInterface {
title: String
slug: String!
description: String
@ -306,7 +306,7 @@ interface ContentBlockInterface {
type: String
}
type ContentBlockNode implements Node, ContentBlockInterface {
type ContentBlockNode implements Node & ContentBlockInterface {
title: String
slug: String!
hiddenFor: [SchoolClassNode]
@ -630,6 +630,7 @@ type ModuleCategoryNode implements Node {
id: ID!
name: String!
filterAttributeType: ModuleCategoryFilterAttributeType!
moduleSet(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, slug_Icontains: String, slug_In: [String], title: String, title_Icontains: String, title_In: [String]): ModuleNodeConnection!
}
type ModuleConnection {
@ -659,6 +660,7 @@ type ModuleLevelNode implements Node {
id: ID!
name: String!
filterAttributeType: ModuleLevelFilterAttributeType!
moduleSet(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, slug_Icontains: String, slug_In: [String], title: String, title_Icontains: String, title_In: [String]): ModuleNodeConnection!
}
type ModuleNode implements ModuleInterface {
@ -684,6 +686,7 @@ 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]
language: String
}
type ModuleNodeConnection {
@ -1043,7 +1046,7 @@ type SnapshotChangesNode {
newContentBlocks: Int!
}
type SnapshotChapterNode implements Node, ChapterInterface {
type SnapshotChapterNode implements Node & ChapterInterface {
id: ID!
description: String
title: String
@ -1052,7 +1055,7 @@ type SnapshotChapterNode implements Node, ChapterInterface {
titleHidden: Boolean
}
type SnapshotContentBlockNode implements Node, ContentBlockInterface {
type SnapshotContentBlockNode implements Node & ContentBlockInterface {
id: ID!
title: String
contents: GenericStreamFieldType