diff --git a/src/components/BasePuzzleListPage.vue b/src/components/BasePuzzleListPage.vue index 61be91b..1fb1a62 100644 --- a/src/components/BasePuzzleListPage.vue +++ b/src/components/BasePuzzleListPage.vue @@ -82,6 +82,10 @@ export default Vue.extend({ quest: { type: Object, default: null + }, + collection: { + type: String, + default: null } }, data() { @@ -99,7 +103,6 @@ export default Vue.extend({ this.availableFilters = [ { value: 'notcleared', text: 'Uncleared' }, ]; - if (!this.$route.query.switch) this.availableFilters.push({ value: 'single', text: 'Single State' }); } else { this.availableFilters = [ { value: 'challenge', text: 'Challenges' }, @@ -140,24 +143,27 @@ export default Vue.extend({ cleared: puzzleList.cleared ? puzzleList.cleared.some(cleared => cleared.nid === puzzle.id) : false, })); + // When we are displaying a collection, the API does not have a filter for uncleared puzzles, so we do that here + const filters = `${this.$route.query.filters}`.split(','); + const filteredPuzzles = filters.includes("notcleared") ? puzzlesWithCleared.filter((puz) => !puz.cleared) : puzzlesWithCleared; + if (this.$route.query.progression) { // Sort such that puzzle A which specifies its next puzzle is puzzle B is sorted before puzzle A // The first puzzle is the one that has no other puzzle pointing to it const orderedPuzzles: (PuzzleItem & {cleared: boolean})[] = []; - let puzzle = puzzlesWithCleared.find( - candidatePuzzle => !puzzlesWithCleared.some(otherPuzzle => otherPuzzle['next-puzzle'] === candidatePuzzle.id) + let puzzle = filteredPuzzles.find( + candidatePuzzle => !filteredPuzzles.some(otherPuzzle => otherPuzzle['next-puzzle'] === candidatePuzzle.id) ); while (puzzle) { orderedPuzzles.push(puzzle); const nextPuzzle = puzzle['next-puzzle']; - puzzle = puzzlesWithCleared.find(candidatePuzzle => candidatePuzzle.id === nextPuzzle); + puzzle = filteredPuzzles.find(candidatePuzzle => candidatePuzzle.id === nextPuzzle); } // Add any additional puzzles not part of the next puzzle "chain" - orderedPuzzles.push(...puzzlesWithCleared.filter(candidatePuzzle => !orderedPuzzles.includes(candidatePuzzle))); + orderedPuzzles.push(...filteredPuzzles.filter(candidatePuzzle => !orderedPuzzles.includes(candidatePuzzle))); return orderedPuzzles; } else { - console.log('unordered'); - return puzzlesWithCleared; + return filteredPuzzles; } } else { return []; @@ -167,7 +173,7 @@ export default Vue.extend({ return this.$store.state.user.lab_access; }, morePuzzlesAvailable(): boolean { - return this.numberOfPuzzles < parseInt(this.$store.state.puzzle_list.num_puzzles); + return this.$store.state.puzzle_list.puzzles.length < parseInt(this.$store.state.puzzle_list.num_puzzles); }, firstQuest(): boolean { return !!this.$route.query.firstQuest; @@ -176,33 +182,37 @@ export default Vue.extend({ methods: { async fetchNewPuzzles() { // Get filters from query, then convert to API's expected parameters - // Will change with Eterna-Next API const query = this.$route.query; - const filters = `${query.filters}`.split(','); - const queryParams = new URLSearchParams({type: 'puzzles'}); - - if (filters.includes("challenge") && !filters.includes("player")) queryParams.append('puzzle_type', 'Challenge'); - else if (filters.includes("player") && !filters.includes("challenge")) queryParams.append('puzzle_type', 'PlayerPuzzle'); - else if (query.progression) queryParams.append('puzzle_type', 'Progression'); - else queryParams.append('puzzle_type', 'AllChallengesPuzzle') - - if (filters.includes("single")) queryParams.append('single', 'checked'); - if (query.switch) queryParams.append('switch', 'checked'); + if (this.collection) { + await this.$store.dispatch(Action.GET_COLLECTION, {id: this.collection}); + } else { + const queryParams = new URLSearchParams({type: 'puzzles'}); + + const filters = `${query.filters}`.split(','); - if(filters.includes("notcleared")) queryParams.append('notcleared', 'true'); + if (filters.includes("challenge") && !filters.includes("player")) queryParams.append('puzzle_type', 'Challenge'); + else if (filters.includes("player") && !filters.includes("challenge")) queryParams.append('puzzle_type', 'PlayerPuzzle'); + else if (query.progression) queryParams.append('puzzle_type', 'Progression'); + else queryParams.append('puzzle_type', 'AllChallengesPuzzle') + + if (filters.includes("single")) queryParams.append('single', 'checked'); + if (query.switch) queryParams.append('switch', 'checked'); + + if (filters.includes("notcleared")) queryParams.append('notcleared', 'true'); - if (this.$store.state.uid) queryParams.append('uid', this.$store.state.uid); + if (this.$store.state.uid) queryParams.append('uid', this.$store.state.uid); - if (query.tags) queryParams.append('tags', query.tags as string); + if (query.tags) queryParams.append('tags', query.tags as string); - if (query.search) queryParams.append('search', query.search as string); - - queryParams.append('sort', query.sort ? query.sort as string : 'date'); + if (query.search) queryParams.append('search', query.search as string); + + queryParams.append('sort', query.sort ? query.sort as string : 'date'); - if (!query.progression) queryParams.append('size', this.numberOfPuzzles.toString(10)); + if (!query.progression) queryParams.append('size', this.numberOfPuzzles.toString(10)); - await this.$store.dispatch(Action.GET_PUZZLES, queryParams.toString()); + await this.$store.dispatch(Action.GET_PUZZLES, queryParams.toString()); + } }, async fetchMorePuzzles() { this.numberOfPuzzles += 9; diff --git a/src/store/index.ts b/src/store/index.ts index 89331d9..e408496 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -46,9 +46,9 @@ export interface ClearedPuzzle { export interface PuzzleList { puzzles: PuzzleItem[]; cleared: ClearedPuzzle[]; + num_puzzles: number; } - export interface Puzzle { title: string; created: string; @@ -88,6 +88,24 @@ export interface Puzzle { // "max-votes": 0 } +export interface Collection { + nid: string; + desc: string; + title: string; + userpicture: string; + username: string; + puzzles: string; + quest: string; + achievement: string; + created: string; + image: string; +} + +export interface CollectionList { + collections: Collection[]; + num_collections: string; +} + export interface LabCardData { affiliation: string; cover_image?: string; @@ -211,6 +229,8 @@ export const Action = { GET_QUEST_ACHIEVEMENT_ROADMAP: 'GET_QUEST_ACHIEVEMENT_ROADMAP', GET_LABS: 'GET_LABS', GET_LAB: 'GET_LAB', + GET_QUESTS: 'GET_QUESTS', + GET_COLLECTION: 'GET_COLLECTION', GET_PUZZLES: 'GET_PUZZLES', GET_PUZZLE: 'GET_PUZZLE', GET_PROFILE: 'GET_PROFILE' @@ -234,6 +254,7 @@ export default function createStore(http: AxiosInstance) { current_lab: null, puzzle_list: null, current_puzzle: <(Puzzle & { cleared: boolean }) | null>null, + quests: null, }, getters: { isLoading({isLoadingCount}) { @@ -284,6 +305,9 @@ export default function createStore(http: AxiosInstance) { }, setUserData(state, user) { state.user = user + }, + setQuests(state, quests) { + state.quests = quests } }, actions: { @@ -382,6 +406,31 @@ export default function createStore(http: AxiosInstance) { commit('popIsLoading'); } }, + async [Action.GET_QUESTS]({ commit }) { + commit('pushIsLoading'); + try{ + const { data } = (await http.get('/get/?type=collections&quest=true&sort=title&size=30')).data; + commit('setQuests', data); + } + finally{ + commit('popIsLoading'); + } + }, + async [Action.GET_COLLECTION]({ commit }, { id }: { id: string}) { + commit('pushIsLoading'); + try{ + const { data: collectionData } = (await http.get(`/get/?type=collection&nid=${id}`)).data; + const { data: clearedData } = (await http.get(`/get/?type=puzzle&nid=${collectionData.puzzles[0].id}`)).data; + commit('setPuzzles', { + puzzles: collectionData.puzzles, + num_puzzles: collectionData.puzzles.length, + cleared: clearedData?.cleared ?? [], + }); + } + finally{ + commit('popIsLoading'); + } + }, async [Action.GET_PUZZLES]({ commit }, queryString: string){ // commit('pushIsLoading'); try{ diff --git a/src/views/Quest.vue b/src/views/Quest.vue index 7e7c945..620a179 100644 --- a/src/views/Quest.vue +++ b/src/views/Quest.vue @@ -1,5 +1,5 @@