Skip to content

Commit

Permalink
feat(tasks): support for biweekly tasks
Browse files Browse the repository at this point in the history
  • Loading branch information
Supamiu committed Sep 15, 2023
1 parent 6e16a8c commit 10a7025
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 43 deletions.
2 changes: 1 addition & 1 deletion apps/client/src/app/core/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export const tasks = [
shared: true,
partySize: 8
}),
createTask(`Brelshaza Gate 4`, 1520, TaskFrequency.WEEKLY, TaskScope.CHARACTER, 1, 9999, "legion_raid.png", {
createTask(`Brelshaza Gate 4`, 1520, TaskFrequency.BIWEEKLY, TaskScope.CHARACTER, 1, 9999, "legion_raid.png", {
shared: true,
partySize: 8
}),
Expand Down
20 changes: 17 additions & 3 deletions apps/client/src/app/core/time.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Injectable } from '@angular/core';
import { Injectable } from "@angular/core";
import { distinctUntilChanged, map, timer } from "rxjs";
import { subDays } from "date-fns";
import { addWeeks, getWeek, subDays } from "date-fns";

@Injectable({
providedIn: 'root'
providedIn: "root"
})
export class TimeService {

Expand Down Expand Up @@ -52,4 +52,18 @@ export class TimeService {
}),
distinctUntilChanged()
);

public lastBiWeeklyReset$ = this.lastWeeklyReset$.pipe(
map((timestamp) => {
const reset = new Date(timestamp);
// BiWeekly reset happens every odd week #
const week = getWeek(reset);
if (week % 2 === 1) {
return timestamp;
} else {
return addWeeks(reset, -1).getTime();
}
}),
distinctUntilChanged()
);
}
2 changes: 1 addition & 1 deletion apps/client/src/app/model/lostark-task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { TaskFrequency } from "./task-frequency";
import { TaskScope } from "./task-scope";
import { DataModel } from "../core/database/data-model";

export const TASKS_VERSION = 43;
export const TASKS_VERSION = 45;

export interface LostarkTask extends DataModel {
authorId?: string;
Expand Down
3 changes: 2 additions & 1 deletion apps/client/src/app/model/task-frequency.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export enum TaskFrequency {
DAILY,
WEEKLY,
ONE_TIME
ONE_TIME,
BIWEEKLY
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<div class="countdowns-container">
<nz-countdown *ngIf="nextDailyReset$ | async as reset" [nzValue]="reset" nzTitle="Next daily reset: "></nz-countdown>
<nz-countdown *ngIf="nextWeeklyReset$ | async as reset" [nzValue]="reset" nzTitle="Next weekly reset: "></nz-countdown>
<nz-countdown *ngIf="nextBiWeeklyReset$ | async as reset" [nzValue]="reset" nzTitle="Next bi-weekly reset: "></nz-countdown>
</div>
</nz-page-header-extra>
</nz-page-header>
Expand Down Expand Up @@ -96,8 +97,12 @@
*ngTemplateOutlet="rowsDisplay;context:{$implicit: display.data.dailyRoster, title: 'Daily Roster', key:'dailyRoster' }"></ng-container>
<ng-container
*ngTemplateOutlet="rowsDisplay;context:{$implicit: display.data.weeklyCharacter, title: 'Weekly Character', key:'weeklyCharacter' }"></ng-container>
<ng-container
*ngTemplateOutlet="rowsDisplay;context:{$implicit: display.data.biWeeklyCharacter, title: 'Biweekly Character', key:'biWeeklyCharacter' }"></ng-container>
<ng-container
*ngTemplateOutlet="rowsDisplay;context:{$implicit: display.data.weeklyRoster, title: 'Weekly Roster', key:'weeklyRoster' }"></ng-container>
<ng-container
*ngTemplateOutlet="rowsDisplay;context:{$implicit: display.data.biWeeklyRoster, title: 'Biweekly Roster', key:'biWeeklyRoster' }"></ng-container>

<ng-template #rowsDisplay let-entry let-title="title" let-key="key">
<ng-container *ngIf="entry.data.length > 0">
Expand All @@ -106,7 +111,7 @@
<td [attr.colspan]="display.roster.length+1" class="section-span"
[class.completed]="entry.done"
[class.daily]="entry.data[0].task.frequency === TaskFrequency.DAILY"
[class.weekly]="entry.data[0].task.frequency === TaskFrequency.WEEKLY">
[class.weekly]="entry.data[0].task.frequency === TaskFrequency.WEEKLY || entry.data[0].task.frequency === TaskFrequency.BIWEEKLY">
<div class="section-span-toggle">
<nz-switch [nzCheckedChildren]="checked"
[nzUnCheckedChildren]="unchecked"
Expand All @@ -123,7 +128,7 @@
<ng-container *ngIf="categoriesDisplay[key]">
<tr *ngFor="let row of entry.data; trackBy: trackByEntry; even as even"
[class.even]="even"
[class.completed]="row.allDone || ( !row.available && row.task.scope === TaskScope.ROSTER )"
[class.completed]="row.allDone || (!row.available && row.task.scope === TaskScope.ROSTER )"
[class.daily]="row.task.frequency === TaskFrequency.DAILY"
[class.one-time]="row.task.frequency === TaskFrequency.ONE_TIME"
[class.weekly]="row.task.frequency === TaskFrequency.WEEKLY">
Expand All @@ -140,13 +145,13 @@
nzBlock
nzType="primary"
[disabled]="row.completion[0] >= row.task.amount"
(click)="markAsDone(completion, energy, roster[0], row.task, roster, true, display.dailyReset, display.weeklyReset, $event)">
(click)="markAsDone(completion, energy, roster[0], row.task, roster, true, display.dailyReset, display.weeklyReset, display.biWeeklyReset, $event)">
{{row.completion[0]}}/{{row.task.amount}}
</button>
</div>
<div *ngIf="row.completion[0] > 0" class="reset-button">
<button nz-button nzSize="small" *ngIf="row.completion[0] >= row.task.amount"
(click)="markAsDone(completion, energy, roster[0], row.task, roster, false, display.dailyReset, display.weeklyReset)">
(click)="markAsDone(completion, energy, roster[0], row.task, roster, false, display.dailyReset, display.weeklyReset, display.biWeeklyReset)">
<i nz-icon nzType="reload" nzTheme="outline"></i>
</button>
</div>
Expand All @@ -168,13 +173,13 @@
nzSize="small"
nzType="primary"
[disabled]="col >= row.task.amount"
(click)="markAsDone(completion, energy, roster[i], row.task, roster, true, display.dailyReset, display.weeklyReset, $event)">
(click)="markAsDone(completion, energy, roster[0], row.task, roster, true, display.dailyReset, display.weeklyReset, display.biWeeklyReset, $event)">
{{col}}/{{row.task.amount}}
</button>
</div>
<div *ngIf="col > 0" class="reset-button">
<button nz-button nzSize="small" *ngIf="col > 0"
(click)="markAsDone(completion, energy, roster[i], row.task, roster, false, display.dailyReset, display.weeklyReset)">
(click)="markAsDone(completion, energy, roster[0], row.task, roster, false, display.dailyReset, display.weeklyReset, display.biWeeklyReset)">
<i nz-icon nzType="reload" nzTheme="outline"></i>
</button>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, HostListener } from "@angular/core";
import { BehaviorSubject, combineLatest, map, Observable, pluck, startWith } from "rxjs";
import { BehaviorSubject, combineLatest, map, Observable, pluck, startWith, tap } from "rxjs";
import { LostarkTask } from "../../../model/lostark-task";
import { TaskFrequency } from "../../../model/task-frequency";
import { TaskScope } from "../../../model/task-scope";
Expand All @@ -17,9 +17,10 @@ import { Roster } from "../../../model/roster";
import { LocalStorageBehaviorSubject } from "../../../core/local-storage-behavior-subject";
import { Character } from "../../../model/character/character";
import { tickets } from "../../../data/tickets";
import { addWeeks, getWeek } from "date-fns";

export interface TaskCharacter extends Character{
done?: boolean
export interface TaskCharacter extends Character {
done?: boolean;
}

@Component({
Expand All @@ -33,14 +34,16 @@ export class ChecklistComponent {
public TaskScope = TaskScope;

public rawRoster$ = this.rosterService.roster$;
public forceShowHiddenCharacter: boolean = false;
public forceShowHiddenCharacter = false;

public categoriesDisplay$ = new LocalStorageBehaviorSubject<{
dailyCharacter: boolean,
weeklyCharacter: boolean,
biWeeklyCharacter: boolean,
dailyRoster: boolean,
weeklyRoster: boolean
}>("checklist:displayed", { dailyCharacter: true, weeklyCharacter: true, dailyRoster: true, weeklyRoster: true });
weeklyRoster: boolean,
biWeeklyRoster: boolean,
}>("checklist:displayed", { dailyCharacter: true, weeklyCharacter: true, biWeeklyCharacter: true, dailyRoster: true, weeklyRoster: true, biWeeklyRoster: true });

public roster$: Observable<Character[]> = this.rawRoster$.pipe(
pluck("characters")
Expand Down Expand Up @@ -68,6 +71,7 @@ export class ChecklistComponent {

public lastDailyReset$ = this.timeService.lastDailyReset$;
public lastWeeklyReset$ = this.timeService.lastWeeklyReset$;
public lastBiWeeklyReset$ = this.timeService.lastBiWeeklyReset$;

public nextDailyReset$ = this.lastDailyReset$.pipe(
map(reset => reset + 86400000)
Expand All @@ -77,6 +81,14 @@ export class ChecklistComponent {
map(reset => reset + 86400000 * 7)
);

public nextBiWeeklyReset$ = this.lastBiWeeklyReset$.pipe(
map(reset => {
const date = new Date(reset);
// If we're on an odd week, it means that reset is in two weeks, else it's next week
return addWeeks(reset, getWeek(date) % 2 === 1 ? 2 : 1).getTime();
})
);

public tasks$: Observable<LostarkTask[]> = combineLatest([
this.rawRoster$,
this.tasksService.tasks$
Expand All @@ -89,37 +101,29 @@ export class ChecklistComponent {
})
);

public getCharactersList(characters: TaskCharacter[]): TaskCharacter[] {
if(this.forceShowHiddenCharacter){
return characters;
}
return characters.filter((character) => {
return !character.isHide && true
});
}

public tableDisplay$ = combineLatest([
this.rawRoster$,
this.tasks$,
this.completion$,
this.lastDailyReset$,
this.lastWeeklyReset$,
this.lastBiWeeklyReset$,
this.settings.settings$.pipe(
map( settings => ({
map(settings => ({
lazytracking: settings.lazytracking,
hiddenOnCompletion: settings.hiddenOnCompletion
}))
),
this.energy$
]).pipe(
map(([roster, tasks, completion, dailyReset, weeklyReset, settings, energy]) => {
map(([roster, tasks, completion, dailyReset, weeklyReset, biWeeklyReset, settings, energy]) => {
const data = tasks
.map(task => {
const lazyTracking = settings.lazytracking;
const available = isTaskAvailable(task)
const available = isTaskAvailable(task);
const editDisabled = task.canEditDaysFilter === false;
const visible = available || editDisabled; // We always display tasks that can't be edited with "Not available today" flag
const forceDone = ( !available && visible ); // If task is not available but is visible, we marked it as done
const forceDone = (!available && visible); // If task is not available but is visible, we marked it as done

const completionData = roster.characters.map(character => {
return {
Expand Down Expand Up @@ -149,15 +153,19 @@ export class ChecklistComponent {
completionData,
allDone,
visible,
available,
available
};
})
.filter(({ visible, allDone }) => {
if ( allDone && settings.hiddenOnCompletion ) return false; // If task is done and we hide done tasks, we don't display it
return visible || roster.showAllTasks
if (allDone && settings.hiddenOnCompletion) return false; // If task is done and we hide done tasks, we don't display it
return visible || roster.showAllTasks;
})
.reduce((acc, row) => {
const frequencyKey = row.task.frequency === TaskFrequency.DAILY ? "daily" : "weekly";
const frequencyKey = {
[TaskFrequency.DAILY]: "daily",
[TaskFrequency.WEEKLY]: "weekly",
[TaskFrequency.BIWEEKLY]: "biWeekly"
}[row.task.frequency];
const scopeKey = row.task.scope === TaskScope.CHARACTER ? "Character" : "Roster";
const data = [
...acc[`${frequencyKey}${scopeKey}`].data,
Expand All @@ -170,7 +178,14 @@ export class ChecklistComponent {
done: data.every(t => t.allDone)
}
};
}, { dailyCharacter: { data: [], done: false }, weeklyCharacter: { data: [], done: false }, dailyRoster: { data: [], done: false }, weeklyRoster: { data: [], done: false } });
}, {
dailyCharacter: { data: [], done: false },
weeklyCharacter: { data: [], done: false },
biWeeklyCharacter: { data: [], done: false },
dailyRoster: { data: [], done: false },
weeklyRoster: { data: [], done: false },
biWeeklyRoster: { data: [], done: false }
});

return {
roster: roster.characters.map((c, i) => {
Expand All @@ -186,15 +201,12 @@ export class ChecklistComponent {
}),
dailyReset,
weeklyReset,
biWeeklyReset,
data
};
})
);

public isEmpty$ = this.roster$.pipe(
map(roster => roster.length === 0)
);

private windowResize$ = new BehaviorSubject<void>(void 0);

public scrolling$ = combineLatest([this.roster$, this.windowResize$]).pipe(
Expand All @@ -216,6 +228,15 @@ export class ChecklistComponent {
this.setTableHeight();
}

public getCharactersList(characters: TaskCharacter[]): TaskCharacter[] {
if (this.forceShowHiddenCharacter) {
return characters;
}
return characters.filter((character) => {
return !character.isHide && true;
});
}

@HostListener("window:resize")
setTableHeight(): void {
this.windowResize$.next();
Expand All @@ -230,7 +251,7 @@ export class ChecklistComponent {
this.ticketsTrackingOpened = opened;
}

public markAsDone(completion: Completion, energy: Energy, character: Character, task: LostarkTask, roster: Character[], done: boolean, dailyReset: number, weeklyReset: number, clickEvent?: MouseEvent): void {
public markAsDone(completion: Completion, energy: Energy, character: Character, task: LostarkTask, roster: Character[], done: boolean, dailyReset: number, weeklyReset: number, biWeeklyReset: number, clickEvent?: MouseEvent): void {
let reset = Infinity;
switch (task.frequency) {
case TaskFrequency.DAILY:
Expand All @@ -239,6 +260,9 @@ export class ChecklistComponent {
case TaskFrequency.WEEKLY:
reset = weeklyReset;
break;
case TaskFrequency.BIWEEKLY:
reset = biWeeklyReset;
break;
}
if (done) {
const setAllDone = clickEvent?.ctrlKey;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,11 @@ export class PartyPlannerComponent {
};
})
.reduce((acc, row) => {
const frequencyKey = row.task.frequency === TaskFrequency.DAILY ? "daily" : "weekly";
const frequencyKey = {
[TaskFrequency.DAILY]: "daily",
[TaskFrequency.WEEKLY]: "weekly",
[TaskFrequency.BIWEEKLY]: "biWeekly"
}[row.task.frequency];
const scopeKey = row.task.scope === TaskScope.CHARACTER ? "Character" : "Roster";
return {
...acc,
Expand All @@ -211,7 +215,7 @@ export class PartyPlannerComponent {
row
]
};
}, { dailyCharacter: [], weeklyCharacter: [], dailyRoster: [], weeklyRoster: [], ticketsData });
}, { dailyCharacter: [], weeklyCharacter: [], biWeeklyCharacter: [], dailyRoster: [], weeklyRoster: [], biWeeklyRoster: [], ticketsData });
})
);
})
Expand Down

0 comments on commit 10a7025

Please sign in to comment.