mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-18 17:05:48 +00:00
refactor(simple-counter): move habit management from config page to habits page
Add delete button to habit settings dialog with confirmation. Add collapsible disabled habits section to the habits page with enable, edit, and delete actions. Remove simple counter section from global config page and delete the unused SimpleCounterCfgComponent.
This commit is contained in:
parent
84062bde2b
commit
41027f3099
12 changed files with 174 additions and 31 deletions
|
|
@ -1,5 +1,4 @@
|
|||
import { FileImexComponent } from '../../imex/file-imex/file-imex.component';
|
||||
import { SimpleCounterCfgComponent } from '../simple-counter/simple-counter-cfg/simple-counter-cfg.component';
|
||||
import { CustomCfgSection } from './global-config.model';
|
||||
import { ClickUpAdditionalCfgComponent } from '../issue/providers/clickup/clickup-view-components/clickup-cfg/clickup-additional-cfg.component';
|
||||
import { ClipboardImagesCfgComponent } from './clipboard-images-cfg/clipboard-images-cfg.component';
|
||||
|
|
@ -12,9 +11,6 @@ export const customConfigFormSectionComponent = (
|
|||
case 'FILE_IMPORT_EXPORT':
|
||||
return FileImexComponent;
|
||||
|
||||
case 'SIMPLE_COUNTER_CFG':
|
||||
return SimpleCounterCfgComponent;
|
||||
|
||||
case 'CLICKUP_CFG':
|
||||
return ClickUpAdditionalCfgComponent;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import { FormlyFieldConfig } from '@ngx-formly/core';
|
|||
export const SIMPLE_COUNTER_FORM: ConfigFormSection<SimpleCounterConfig> = {
|
||||
title: T.F.SIMPLE_COUNTER.FORM.TITLE,
|
||||
key: 'EMPTY',
|
||||
customSection: 'SIMPLE_COUNTER_CFG',
|
||||
help: T.F.SIMPLE_COUNTER.FORM.HELP,
|
||||
items: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import { TAKE_A_BREAK_FORM_CFG } from './form-cfgs/take-a-break-form.const';
|
|||
import { IMEX_FORM } from './form-cfgs/imex-form.const';
|
||||
import { LANGUAGE_SELECTION_FORM_FORM } from './form-cfgs/language-selection-form.const';
|
||||
import { EVALUATION_SETTINGS_FORM_CFG } from './form-cfgs/evaluation-settings-form.const';
|
||||
import { SIMPLE_COUNTER_FORM } from './form-cfgs/simple-counter-form.const';
|
||||
import { TIME_TRACKING_FORM_CFG } from './form-cfgs/time-tracking-form.const';
|
||||
import { IS_ELECTRON } from '../../app.constants';
|
||||
import { IS_ANDROID_WEB_VIEW } from '../../util/is-android-web-view';
|
||||
|
|
@ -57,7 +56,6 @@ export const GLOBAL_PRODUCTIVITY_FORM_CONFIG: ConfigFormConfig = [
|
|||
FOCUS_MODE_FORM_CFG,
|
||||
TAKE_A_BREAK_FORM_CFG,
|
||||
EVALUATION_SETTINGS_FORM_CFG,
|
||||
SIMPLE_COUNTER_FORM,
|
||||
...(!window.ea?.isSnap() && !!window.speechSynthesis ? [VOICE_REMINDER_FORM] : []),
|
||||
].filter(filterGlobalConfigForm);
|
||||
|
||||
|
|
|
|||
|
|
@ -280,7 +280,6 @@ export interface LimitedFormlyFieldConfig<FormModel> extends Omit<
|
|||
export type CustomCfgSection =
|
||||
| 'FILE_IMPORT_EXPORT'
|
||||
| 'JIRA_CFG'
|
||||
| 'SIMPLE_COUNTER_CFG'
|
||||
| 'OPENPROJECT_CFG'
|
||||
| 'CLICKUP_CFG'
|
||||
| 'CLIPBOARD_IMAGES_CFG';
|
||||
|
|
|
|||
|
|
@ -13,7 +13,19 @@
|
|||
</formly-form>
|
||||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions align="end">
|
||||
<mat-dialog-actions>
|
||||
@if (dialogData.simpleCounter.id) {
|
||||
<button
|
||||
mat-button
|
||||
color="warn"
|
||||
type="button"
|
||||
(click)="delete()"
|
||||
>
|
||||
<mat-icon>delete</mat-icon>
|
||||
{{ T.G.DELETE | translate }}
|
||||
</button>
|
||||
}
|
||||
<span style="flex: 1"></span>
|
||||
<button
|
||||
mat-button
|
||||
type="button"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
||||
import {
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialog,
|
||||
MatDialogActions,
|
||||
MatDialogContent,
|
||||
MatDialogRef,
|
||||
|
|
@ -22,6 +23,7 @@ import { MatIcon } from '@angular/material/icon';
|
|||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { EMPTY_SIMPLE_COUNTER } from '../simple-counter.const';
|
||||
import { SimpleCounterService } from '../simple-counter.service';
|
||||
import { DialogConfirmComponent } from '../../../ui/dialog-confirm/dialog-confirm.component';
|
||||
|
||||
@Component({
|
||||
selector: 'dialog-simple-counter-edit-settings',
|
||||
|
|
@ -44,6 +46,7 @@ export class DialogSimpleCounterEditSettingsComponent {
|
|||
MatDialogRef<DialogSimpleCounterEditSettingsComponent>,
|
||||
);
|
||||
private readonly _simpleCounterService = inject(SimpleCounterService);
|
||||
private readonly _matDialog = inject(MatDialog);
|
||||
readonly dialogData = inject<{ simpleCounter: SimpleCounterCopy }>(MAT_DIALOG_DATA);
|
||||
|
||||
readonly T = T;
|
||||
|
|
@ -87,6 +90,26 @@ export class DialogSimpleCounterEditSettingsComponent {
|
|||
this._dialogRef.close();
|
||||
}
|
||||
|
||||
delete(): void {
|
||||
const id = this.dialogData.simpleCounter.id;
|
||||
if (!id) return;
|
||||
this._matDialog
|
||||
.open(DialogConfirmComponent, {
|
||||
restoreFocus: true,
|
||||
data: {
|
||||
message: T.F.SIMPLE_COUNTER.D_CONFIRM_REMOVE.MSG,
|
||||
okTxt: T.F.SIMPLE_COUNTER.D_CONFIRM_REMOVE.OK,
|
||||
},
|
||||
})
|
||||
.afterClosed()
|
||||
.subscribe((confirmed: boolean) => {
|
||||
if (confirmed) {
|
||||
this._simpleCounterService.deleteSimpleCounter(id);
|
||||
this._dialogRef.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
isDirty(): boolean {
|
||||
return (
|
||||
JSON.stringify(this._normalizeSettings(this._initialModel)) !==
|
||||
|
|
|
|||
|
|
@ -27,13 +27,6 @@
|
|||
>
|
||||
{{ T.F.SIMPLE_COUNTER.HABIT_TRACKER.TODAY | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="openManageHabits()"
|
||||
[matTooltip]="T.F.SIMPLE_COUNTER.HABIT_TRACKER.MANAGE_HABITS | translate"
|
||||
>
|
||||
<mat-icon>settings</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -140,4 +133,59 @@
|
|||
}}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@if (disabledSimpleCounters().length > 0) {
|
||||
<div class="disabled-section">
|
||||
<button
|
||||
class="disabled-section-header"
|
||||
(click)="showDisabled.set(!showDisabled())"
|
||||
>
|
||||
<mat-icon>{{ showDisabled() ? 'expand_less' : 'expand_more' }}</mat-icon>
|
||||
<span
|
||||
>{{ T.F.SIMPLE_COUNTER.HABIT_TRACKER.DISABLED_HABITS | translate }} ({{
|
||||
disabledSimpleCounters().length
|
||||
}})</span
|
||||
>
|
||||
</button>
|
||||
@if (showDisabled()) {
|
||||
<div class="disabled-list">
|
||||
@for (counter of disabledSimpleCounters(); track counter.id) {
|
||||
<div class="disabled-item">
|
||||
<div class="disabled-item-info">
|
||||
@if (counter.icon && counter.icon.startsWith(':')) {
|
||||
<mat-icon [svgIcon]="counter.icon"></mat-icon>
|
||||
} @else if (counter.icon) {
|
||||
<mat-icon>{{ counter.icon }}</mat-icon>
|
||||
}
|
||||
<span>{{ counter.title }}</span>
|
||||
</div>
|
||||
<div class="disabled-item-actions">
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="enableHabit(counter.id)"
|
||||
[matTooltip]="T.F.SIMPLE_COUNTER.FORM.L_IS_ENABLED | translate"
|
||||
>
|
||||
<mat-icon>visibility</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="openEditSettings(counter)"
|
||||
[matTooltip]="T.G.EDIT | translate"
|
||||
>
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="deleteHabit(counter)"
|
||||
[matTooltip]="T.G.DELETE | translate"
|
||||
>
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -260,6 +260,53 @@
|
|||
}
|
||||
}
|
||||
|
||||
.disabled-section {
|
||||
margin-top: 8px;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.disabled-section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
background: none;
|
||||
border: none;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
opacity: 0.6;
|
||||
padding: 8px 0;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.disabled-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.disabled-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.disabled-item-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.disabled-item-actions {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.day-cell {
|
||||
flex: 1 1 0px;
|
||||
min-width: 30px;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import {
|
|||
input,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CdkDrag, CdkDragDrop, CdkDropList } from '@angular/cdk/drag-drop';
|
||||
import { SimpleCounter, SimpleCounterType } from '../simple-counter.model';
|
||||
|
|
@ -19,6 +18,7 @@ import { MatIconModule } from '@angular/material/icon';
|
|||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { DialogSimpleCounterEditComponent } from '../dialog-simple-counter-edit/dialog-simple-counter-edit.component';
|
||||
import { DialogSimpleCounterEditSettingsComponent } from '../dialog-simple-counter-edit-settings/dialog-simple-counter-edit-settings.component';
|
||||
import { DialogConfirmComponent } from '../../../ui/dialog-confirm/dialog-confirm.component';
|
||||
import { EMPTY_SIMPLE_COUNTER } from '../simple-counter.const';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { moveItemInArray } from '../../../util/move-item-in-array';
|
||||
|
|
@ -43,11 +43,13 @@ import { IS_TOUCH_PRIMARY } from '../../../util/is-mouse-primary';
|
|||
})
|
||||
export class HabitTrackerComponent {
|
||||
simpleCounters = input.required<SimpleCounter[]>();
|
||||
disabledSimpleCounters = input<SimpleCounter[]>([]);
|
||||
|
||||
private _simpleCounterService = inject(SimpleCounterService);
|
||||
private _dateService = inject(DateService);
|
||||
private _matDialog = inject(MatDialog);
|
||||
private _router = inject(Router);
|
||||
|
||||
showDisabled = signal(false);
|
||||
|
||||
T = T;
|
||||
SimpleCounterType = SimpleCounterType;
|
||||
|
|
@ -245,9 +247,24 @@ export class HabitTrackerComponent {
|
|||
});
|
||||
}
|
||||
|
||||
openManageHabits(): void {
|
||||
this._router.navigate(['/config'], {
|
||||
queryParams: { tab: 3, section: 'SIMPLE_COUNTER_CFG' },
|
||||
});
|
||||
enableHabit(id: string): void {
|
||||
this._simpleCounterService.updateSimpleCounter(id, { isEnabled: true });
|
||||
}
|
||||
|
||||
deleteHabit(counter: SimpleCounter): void {
|
||||
this._matDialog
|
||||
.open(DialogConfirmComponent, {
|
||||
restoreFocus: true,
|
||||
data: {
|
||||
message: T.F.SIMPLE_COUNTER.D_CONFIRM_REMOVE.MSG,
|
||||
okTxt: T.F.SIMPLE_COUNTER.D_CONFIRM_REMOVE.OK,
|
||||
},
|
||||
})
|
||||
.afterClosed()
|
||||
.subscribe((confirmed: boolean) => {
|
||||
if (confirmed) {
|
||||
this._simpleCounterService.deleteSimpleCounter(counter.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,16 +2,18 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { SimpleCounterService } from '../../features/simple-counter/simple-counter.service';
|
||||
import { HabitTrackerComponent } from '../../features/simple-counter/habit-tracker/habit-tracker.component';
|
||||
import { T } from '../../t.const';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'habit-page',
|
||||
standalone: true,
|
||||
imports: [CommonModule, HabitTrackerComponent, TranslateModule],
|
||||
imports: [CommonModule, HabitTrackerComponent],
|
||||
template: `
|
||||
<div class="page-wrapper">
|
||||
<habit-tracker [simpleCounters]="(simpleCounters$ | async) || []"></habit-tracker>
|
||||
<habit-tracker
|
||||
[simpleCounters]="(simpleCounters$ | async) || []"
|
||||
[disabledSimpleCounters]="(disabledSimpleCounters$ | async) || []"
|
||||
></habit-tracker>
|
||||
</div>
|
||||
`,
|
||||
styles: [
|
||||
|
|
@ -26,7 +28,9 @@ import { TranslateModule } from '@ngx-translate/core';
|
|||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class HabitPageComponent {
|
||||
simpleCounterService = inject(SimpleCounterService);
|
||||
simpleCounters$ = this.simpleCounterService.enabledSimpleCounters$;
|
||||
T = T;
|
||||
private _simpleCounterService = inject(SimpleCounterService);
|
||||
simpleCounters$ = this._simpleCounterService.enabledSimpleCounters$;
|
||||
disabledSimpleCounters$ = this._simpleCounterService.simpleCounters$.pipe(
|
||||
map((counters) => counters.filter((c) => !c.isEnabled)),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -941,7 +941,7 @@ const T = {
|
|||
NEXT_WEEK: 'F.SIMPLE_COUNTER.HABIT_TRACKER.NEXT_WEEK',
|
||||
TODAY: 'F.SIMPLE_COUNTER.HABIT_TRACKER.TODAY',
|
||||
ADD_HABIT: 'F.SIMPLE_COUNTER.HABIT_TRACKER.ADD_HABIT',
|
||||
MANAGE_HABITS: 'F.SIMPLE_COUNTER.HABIT_TRACKER.MANAGE_HABITS',
|
||||
DISABLED_HABITS: 'F.SIMPLE_COUNTER.HABIT_TRACKER.DISABLED_HABITS',
|
||||
},
|
||||
S: {
|
||||
GOAL_REACHED_1: 'F.SIMPLE_COUNTER.S.GOAL_REACHED_1',
|
||||
|
|
|
|||
|
|
@ -915,7 +915,7 @@
|
|||
"NEXT_WEEK": "Next week",
|
||||
"TODAY": "Today",
|
||||
"ADD_HABIT": "Add a new habit",
|
||||
"MANAGE_HABITS": "Manage habits"
|
||||
"DISABLED_HABITS": "Disabled habits"
|
||||
},
|
||||
"S": {
|
||||
"GOAL_REACHED_1": "You reached your goal for today!",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue