This commit is contained in:
Andras Schmelczer 2026-05-28 21:24:47 +01:00
parent 3ad2766f82
commit f74ee43cb4
196 changed files with 18949 additions and 32173 deletions

View file

@ -1,31 +0,0 @@
<section class="towers" cdkDropList cdkDropListOrientation="horizontal" (cdkDropListDropped)="dropDrag($event)">
<app-tower
*ngFor="let tower of towers"
[tower$]="tower.asObservable()"
[dateRange$]="dateRange"
cdkDrag
(cdkDragStarted)="startDrag(towers.indexOf(tower))"
></app-tower>
<div *ngIf="(page$ | async)?.towers.length < 5 && !(page$ | async)?.userData?.hideCreateTowerButton">
<img src="assets/plus-sign.svg" alt="add tower" class="add-tower" (click)="page.addTower()" />
</div>
</section>
<img
[ngClass]="isDragging ? 'active' : ''"
src="assets/trash.svg"
alt="trashcan"
class="trash"
(pointerenter)="trashEnter()"
(pointerleave)="trashExit()"
(pointerup)="removeTower()"
/>
<div class="double-slider-container" [ngStyle]="{ opacity: isDragging ? '0' : '1' }">
<app-double-slider
*ngIf="dates.length >= MIN_BLOCK_COUNT_BEFORE_SHOWING_SLIDER"
[values]="dates"
[labels]="dateLabels"
(range)="dateRange.next($event)"
></app-double-slider>
</div>

View file

@ -1,108 +0,0 @@
@import '../../../../styles';
:host {
display: flex;
flex-direction: column;
height: 100%;
@include inner-spacing(var(--large-padding));
button {
margin-top: 0;
}
.towers {
display: flex;
justify-content: center;
width: 100%;
margin-left: auto;
margin-right: auto;
flex: 1 0 auto;
transition: box-shadow $short-animation-time;
max-width: 800px;
&.cdk-drop-list-dragging {
*:not(.cdk-drag-placeholder) {
transition: transform $long-animation-time cubic-bezier(0, 0, 0.2, 1);
}
}
div {
@include center-child();
img.add-tower {
height: 48px;
@media (max-width: $mobile-width) {
height: 32px;
}
opacity: 0.33;
transition: opacity $long-animation-time;
cursor: pointer;
&:hover {
opacity: 1;
}
}
}
& > * {
max-width: 200px;
box-sizing: content-box;
flex: 0 0 auto;
&:not(:nth-last-child(1)) {
margin-right: var(--medium-padding);
@media (max-width: $mobile-width) {
margin-right: var(--small-padding);
}
}
}
position: relative;
@for $i from 1 to 6 {
& > *:first-child:nth-last-child(#{$i}),
& > *:first-child:nth-last-child(#{$i}) ~ * {
width: calc((100% - (#{$i} - 1) * var(--medium-padding)) / #{$i});
@media (max-width: $mobile-width) {
width: calc((100% - (#{$i} - 1) * var(--small-padding)) / #{$i});
}
}
}
}
.double-slider-container {
@media (max-height: $min-height) {
display: none;
}
}
img.trash {
@include square(48px);
padding: 16px;
position: absolute;
z-index: 1500;
bottom: 8px;
left: 50%;
margin: 0 !important;
transform: translateX(-50%) scale(0);
transition: transform $long-animation-time;
&.active {
transform: translateX(-50%) scale(1);
}
&:hover {
transform: translateX(-50%) scale(1.1);
}
}
}

View file

@ -1,92 +0,0 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Page } from '../../../model/page';
import { ModalService } from '../../../services/modal.service';
import { Observable } from 'rxjs/internal/Observable';
import { Range } from '../../../interfaces/range';
import { Subject } from 'rxjs/internal/Subject';
import { Tower } from '../../../model/tower';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
@Component({
selector: 'app-page',
templateUrl: './page.component.html',
styleUrls: ['./page.component.scss']
})
export class PageComponent implements OnInit {
@Input() page$: Observable<Page>;
private page: Page;
towers: Array<BehaviorSubject<Tower>> = [];
@Output() isDragHappening: EventEmitter<boolean> = new EventEmitter();
readonly MIN_BLOCK_COUNT_BEFORE_SHOWING_SLIDER = 6;
isDragging = false;
draggedTowerIndex: number;
nearTrashcan = false;
dates: Date[] = [];
dateRange: Subject<Range<Date>> = new Subject<Range<Date>>();
get dateLabels(): string[] {
return this.dates.map(d => d.toLocaleDateString());
}
constructor(private modalService: ModalService) {}
ngOnInit(): void {
this.page$.subscribe(value => {
if (value) {
this.towers = value.towers.map((t, index) => {
if (index < this.towers.length) {
this.towers[index].next(t);
return this.towers[index];
}
return new BehaviorSubject(t);
});
this.page = value;
this.dates = value.towers
.reduce((all, t) => [...t.blocks.map(b => b.created), ...all], [])
.sort((d1, d2) => d1.getTime() - d2.getTime());
}
});
}
dropDrag(event: any) {
this.page.moveTower(event);
this.isDragging = false;
this.isDragHappening.emit(false);
}
startDrag(id: number) {
this.draggedTowerIndex = id;
this.isDragging = true;
this.isDragHappening.emit(true);
}
trashEnter() {
this.nearTrashcan = true;
window.document.querySelector('.cdk-drag-preview').className += ' trash-highlight';
}
trashExit() {
this.nearTrashcan = false;
const elem = window.document.querySelector('.cdk-drag-preview');
elem.className = elem.className
.split(' ')
.slice(0, -1)
.join(' ');
}
async removeTower() {
try {
const tower = this.page.towers[this.draggedTowerIndex];
await this.modalService.showRemoveTower(tower);
this.page.removeTower(tower);
} catch {
// pass
}
}
}

View file

@ -1 +0,0 @@
<div [ngStyle]="{ 'background-color': block.color | color }" (click)="$event.stopPropagation() || handleClick()"></div>

View file

@ -1,15 +0,0 @@
@import '../../../../../../styles';
:host {
position: relative;
width: calc(100% / 6);
padding-bottom: calc(100% / 6);
div {
position: absolute;
width: 100%;
height: 100%;
@include gravitate();
}
}

View file

@ -1,28 +0,0 @@
import { ChangeDetectorRef, Component, Input } from '@angular/core';
import { ModalService } from '../../../../../services/modal.service';
import { ColoredBlock, Tower } from '../../../../../model/tower';
import { Observable } from 'rxjs/internal/Observable';
@Component({
selector: 'app-block',
templateUrl: './block.component.html',
styleUrls: ['./block.component.scss']
})
export class BlockComponent {
@Input() block: ColoredBlock;
@Input() tower$: Observable<Tower>;
constructor(private modalService: ModalService) {}
async handleClick() {
try {
await this.modalService.showBlocks({
tower$: this.tower$,
startBlock: this.block,
onlyDone: true
});
} catch {
// pass
}
}
}

View file

@ -1,15 +0,0 @@
<div *ngIf="tasks" class="container {{ tasks.length > 0 ? 'show-hover' : '' }}" (click)="$event.stopPropagation()">
<p class="header" (click)="isOpen = !isOpen">
<strong>
{{ tasks.length == 0 ? '' : tasks.length }}
</strong>
<!-- &#8203; is the zero width space -->
{{ tasks.length == 0 ? '&#8203;' : tasks.length == 1 ? 'task' : 'tasks' }}
</p>
<div class="all-task" #allTask [ngStyle]="{ height: (isOpen ? allTask?.scrollHeight : 0) + 'px' }">
<div class="task-container" *ngFor="let task of tasks" [ngStyle]="{ color: task.color | color }">
<div [ngStyle]="{ 'background-color': task.color | color }"></div>
<p (click)="handleClick(task)" [innerText]="task.description ? task.description : 'unknown'"></p>
</div>
</div>
</div>

View file

@ -1,80 +0,0 @@
@import '../../../../../../styles';
:host {
width: 100%;
box-sizing: border-box;
position: relative;
z-index: 100000;
.container {
@include card();
cursor: pointer;
transition: box-shadow $long-animation-time;
&.show-hover:hover {
box-shadow: $shadow-border;
}
padding: calc(var(--small-padding) / 2);
margin: calc(var(--small-padding) / 2);
max-height: 30vh;
overflow-y: auto;
.header {
cursor: pointer;
}
p {
font-size: var(--medium-font-size);
}
.all-task {
@include inner-spacing(var(--small-padding));
:first-child {
margin-top: var(--small-padding);
}
height: 0;
box-sizing: border-box;
transition: height $long-animation-time;
overflow-y: hidden;
.task-container {
display: flex;
align-items: center;
&:hover {
p {
@media (min-width: $mobile-width) {
color: inherit !important;
}
}
}
div {
flex: 0 0 auto;
margin: 0 calc(var(--small-padding) / 2) 0 0;
@include square(var(--small-padding));
@media (max-width: $mobile-width) {
@include square(calc(var(--small-padding) / 2));
}
}
p {
white-space: nowrap;
text-overflow: ellipsis;
overflow-x: hidden;
text-align: left;
@media (max-width: $mobile-width) {
font-size: calc(var(--small-font-size) / 2 + var(--medium-font-size) / 2);
}
position: relative;
}
}
}
}
}

View file

@ -1,55 +0,0 @@
import { ChangeDetectorRef, Component, ElementRef, Input, ViewChild } from '@angular/core';
import { Block } from '../../../../../model/block';
import { Tower } from '../../../../../model/tower';
import { ModalService } from '../../../../../services/modal.service';
import { CancelService } from '../../../../../services/cancel.service';
import { IColor } from '../../../../../interfaces/color';
import { Observable } from 'rxjs/internal/Observable';
@Component({
selector: 'app-tasks',
templateUrl: './tasks.component.html',
styleUrls: ['./tasks.component.scss']
})
export class TasksComponent {
@Input() tasks: Array<Block & { color: IColor }>;
@Input() tower$: Observable<Tower>;
private _isOpen = false;
@Input() set isOpen(value: boolean) {
if (value) {
this.cancelService.cancelAllExcept(this);
}
this._isOpen = value;
}
get isOpen(): boolean {
return this._isOpen;
}
@ViewChild('allTask') allTask: ElementRef;
constructor(
private modalService: ModalService,
private cancelService: CancelService,
private changeDetection: ChangeDetectorRef
) {
this.cancelService.subscribe(this, () => {
this.isOpen = false;
});
}
async handleClick(block: Block) {
try {
await this.modalService.showBlocks({
tower$: this.tower$,
startBlock: block,
onlyDone: false
});
} catch {
// pass
} finally {
this.changeDetection.markForCheck();
}
}
}

View file

@ -1,31 +0,0 @@
<div class="tower" *ngIf="tower$ | async">
<div class="container">
<div class="tasks-container">
<app-tasks [tasks]="tasks" [tower$]="tower$"></app-tasks>
</div>
<img src="assets/plus-sign.svg" alt="add item" (click)="$event.stopPropagation() || addBlock()" />
<div class="block-container-container">
<div class="block-container" *ngIf="styledBlocks.length > 0">
<app-block
*ngFor="let block of drawableBlocks"
[ngClass]="block.cssClass"
[ngStyle]="block.style"
[block]="block"
[tower$]="tower$"
></app-block>
</div>
</div>
</div>
<label class="hidden">
Card name
<input
type="text"
placeholder="name…"
[(ngModel)]="towerName"
[ngStyle]="{ color: (tower$ | async)?.baseColor | color }"
/>
</label>
</div>

View file

@ -1,152 +0,0 @@
@import '../../../../../styles';
:host {
cursor: pointer;
&.cdk-drag-animating {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
&.cdk-drag-placeholder {
opacity: 0;
}
&:hover {
@media (min-width: $mobile-width) {
div.container {
box-shadow: $shadow;
}
}
}
&.cdk-drag-preview {
div.container {
@media (max-width: $mobile-width) {
@keyframes shadow {
from {
box-shadow: none;
}
to {
box-shadow: $shadow;
}
}
animation: shadow $long-animation-time forwards;
}
}
}
&.trash-highlight {
.container {
transform: scale(0.75);
position: relative;
:before {
opacity: 0.5 !important;
}
}
input {
display: none;
}
}
.tower {
display: flex;
flex-direction: column;
align-items: center;
max-width: 100%;
height: 100%;
@include inner-spacing(var(--small-padding));
.container {
display: flex;
flex-direction: column;
flex: 1 1 auto;
position: relative;
@include card();
overflow: hidden;
transition: transform $short-animation-time, box-shadow $long-animation-time;
@include inner-spacing(var(--medium-padding));
width: 100%;
:before {
content: '';
pointer-events: none;
position: absolute;
z-index: 2;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: red;
opacity: 0;
border-radius: var(--border-radius);
transition: opacity $short-animation-time;
}
img {
position: relative;
z-index: 2;
height: 48px;
@media (max-width: $mobile-width) {
height: 32px;
}
opacity: 0.33;
transition: opacity $long-animation-time;
cursor: pointer;
&:hover {
opacity: 1;
}
}
.block-container-container {
position: relative;
flex: 1;
.block-container {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
align-content: flex-start;
align-items: flex-end;
position: absolute;
bottom: 0;
width: 100%;
transform: scaleY(-1);
* {
transform: translateY(500%);
}
.descend {
transition: transform 1.5s cubic-bezier(0.5, 0, 1, 0), opacity 500ms cubic-bezier(0.5, 0, 1, 0);
}
.ascend {
transition: transform 1.5s cubic-bezier(0.5, 0, 1, 0), opacity 500ms cubic-bezier(0.5, 0, 1, 0) 1s;
}
}
}
}
input[type='text'] {
font-size: var(--small-font-size);
text-align: center;
@media (min-width: $mobile-width) {
width: 50%;
}
}
}
}

View file

@ -1,123 +0,0 @@
import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
import { ColoredBlock, Tower } from '../../../../model/tower';
import { ModalService } from '../../../../services/modal.service';
import { Observable } from 'rxjs/internal/Observable';
import { Range } from '../../../../interfaces/range';
import { top } from '../../../../utils/top';
import { CancelService } from '../../../../services/cancel.service';
type StyledBlock = ColoredBlock & { style: { [p: string]: string }; shouldDraw: boolean; cssClass: string };
@Component({
selector: 'app-tower',
templateUrl: './tower.component.html',
styleUrls: ['./tower.component.scss']
})
export class TowerComponent implements OnInit {
@Input() dateRange$: Observable<Range<Date>>;
@Input() tower$: Observable<Tower>;
private dateRange: Range<Date>;
private tower: Tower;
get towerName(): string {
return this.tower ? this.tower.name : 'Loading…';
}
set towerName(value: string) {
this.tower.changeName(value);
}
tasks: Array<ColoredBlock>;
styledBlocks: Array<StyledBlock> = [];
get drawableBlocks(): Array<StyledBlock> {
return this.styledBlocks.filter(b => b.shouldDraw);
}
public constructor(private modalService: ModalService, private changeDetection: ChangeDetectorRef) {}
ngOnInit() {
this.tower$.subscribe(value => {
// console.log(this.tower, value);
if (value) {
this.styledBlocks = value.coloredBlocks
.filter(b => b.isDone)
.map(b => {
const classedBlock = b as StyledBlock;
classedBlock.shouldDraw = true;
classedBlock.style = { transform: 'translateY(0)', opacity: '1' };
classedBlock.cssClass = '';
return classedBlock;
});
if (this.tower && this.tower.latestVersion === value) {
const difference = this.tower.blocks.map((b, index) => {
return b === value.blocks[index];
});
if (
(difference.every(i => i) &&
this.tower.blocks.length + 1 === value.blocks.length &&
top(value.blocks).isDone) ||
(this.tower.blocks.length === value.blocks.length &&
this.tower.blocks.filter(b => b.isDone).length + 1 === value.blocks.filter(b => b.isDone).length)
) {
const lastBlock = top(this.styledBlocks);
if (lastBlock) {
lastBlock.style = { transform: 'translateY(500%)', opacity: '0' };
setTimeout(() => {
this.makeBlockDescend(lastBlock);
this.changeDetection.markForCheck();
}, 0);
}
}
}
this.tasks = value.coloredBlocks.filter(block => !block.isDone);
this.tower = value;
this.changeDetection.markForCheck();
}
});
this.dateRange$.subscribe(dateRange => {
this.initData(dateRange);
this.dateRange = dateRange;
});
}
makeBlockDescend(block: StyledBlock) {
block.cssClass = 'descend';
block.style = { transform: 'translateY(0)', opacity: '1' };
}
makeBlockAscend(block: StyledBlock) {
block.cssClass = 'ascend';
block.style = { transform: 'translateY(500%)', opacity: '0' };
}
initData(newDateRange: Range<Date>) {
for (const block of this.styledBlocks) {
block.shouldDraw = newDateRange.from <= block.created;
if (newDateRange.to < block.created) {
this.makeBlockAscend(block);
}
if (block.shouldDraw && block.created <= newDateRange.to) {
this.makeBlockDescend(block);
}
}
}
public async addBlock() {
try {
await this.modalService.showBlocks({
tower$: this.tower$,
onlyDone: true
});
} catch {
// pass
}
}
}

View file

@ -1,22 +1,44 @@
<div class="select-add-container">
<!-- wrapper for easier styling -->
<app-select-add
[options]="pageNames"
[default]="(selectedPage$ | async)?.name"
(value)="selectPage($event)"
(optionChange)="changeName($event)"
[placeholder]="'Add a new page…'"
[editable]="true"
></app-select-add>
<lt-select-add
[options]="pageNames()"
[selectedIndex]="selectedPageIndex()"
placeholder="Add a new page…"
(selectionChange)="onSelectPage($event)"
(add)="onAddPage($event)"
/>
</div>
<!-- wrapper for easier styling -->
<div class="page-container">
<!-- wrapper for easier styling -->
<app-page [page$]="selectedPage$" (isDragHappening)="isDragHappening = $event"></app-page>
@if (selectedPage(); as page) {
<lt-page [page]="page" (dragHappening)="dragHappening.set($event)" />
} @else {
<p>Add a new page to get started!</p>
}
</div>
<!-- wrapper for easier styling -->
<button [ngClass]="isDragHappening ? 'transparent' : ''" (click)="$event.stopPropagation(); openSettings()">
<button [class.transparent]="dragHappening()" (click)="showSettings.set(true)">
Settings
</button>
@if (showSettings()) {
<lt-modal (close)="showSettings.set(false)">
<lt-settings
[token]="store.token()"
[page]="selectedPage()"
(close)="showSettings.set(false)"
(updatePage)="onUpdatePage($event)"
(deletePage)="onRemovePage()"
(switchAccount)="onSwitchAccount($event)"
/>
</lt-modal>
}
@if (showWelcome()) {
<lt-modal (close)="showWelcome.set(false)">
<lt-welcome
(close)="showWelcome.set(false)"
(startFresh)="showWelcome.set(false)"
(loadExample)="onLoadExample()"
/>
</lt-modal>
}

View file

@ -13,6 +13,8 @@
width: 250px;
margin-left: auto;
margin-right: auto;
position: relative;
z-index: 1000;
}
.page-container {

View file

@ -1,113 +1,108 @@
import { ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { Page } from '../../model/page';
import { DataService } from '../../services/data.service';
import { ModalService } from '../../services/modal.service';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
import { Observable } from 'rxjs/internal/Observable';
import { Data } from '../../model/data';
import { of } from 'rxjs/internal/observable/of';
const USER_DATA_KEY = 'life-towers.user-data.v.2';
import {
Component,
ChangeDetectionStrategy,
inject,
signal,
computed,
effect,
} from '@angular/core';
import { StoreService } from '../../services/store.service';
import { PageComponent } from '../page/page.component';
import { ModalComponent } from '../modal/modal.component';
import { SettingsComponent, UpdatePagePayload } from '../modal/settings.component';
import { SelectAddComponent } from '../shared/select-add/select-add.component';
import { WelcomeComponent } from '../welcome/welcome.component';
import { Page } from '../../models';
@Component({
selector: 'app-pages',
selector: 'lt-pages',
standalone: true,
imports: [PageComponent, ModalComponent, SettingsComponent, SelectAddComponent, WelcomeComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './pages.component.html',
styleUrls: ['./pages.component.scss']
styleUrl: './pages.component.scss',
})
export class PagesComponent implements OnInit {
@ViewChild('top') top: ElementRef;
@ViewChild('page') page: ElementRef;
@ViewChild('bottom') bottom: ElementRef;
export class PagesComponent {
protected readonly store = inject(StoreService);
data: Data;
pages: Array<Page>;
isDragHappening = false;
/** ID of currently selected page within store.pages(). */
private readonly selectedPageId = signal<string | null>(null);
get pageNames() {
if (this.pages) {
return this.pages.map(p => p.name);
}
return [];
}
readonly showSettings = signal(false);
readonly dragHappening = signal(false);
readonly showWelcome = signal(false);
selectedPageName: string;
private readonly _selectedPage: BehaviorSubject<Page> = new BehaviorSubject(null);
readonly selectedPage$: Observable<Page> = this._selectedPage.asObservable();
constructor(
public dataService: DataService,
private modalService: ModalService,
private changeDetection: ChangeDetectorRef
) {
const userData = JSON.parse(window.localStorage.getItem(USER_DATA_KEY));
if (userData !== null) {
this.selectedPageName = userData.selectedPage;
}
}
ngOnInit() {
this.dataService.children$.subscribe(dataContainer => {
if (dataContainer && dataContainer.length > 0) {
this.data = dataContainer[0];
const pages = this.data.pages;
if (this.pages && !pages.includes(this._selectedPage.getValue().latestVersion)) {
this.selectedPageName = null;
}
this.pages = pages;
this.selectPage(this.selectedPageName);
constructor() {
effect(() => {
if (!this.store.loading() && this.store.pages().length === 0) {
this.showWelcome.set(true);
} else if (this.store.pages().length > 0) {
this.showWelcome.set(false);
}
});
}
changeName({ from, to }: { from: string; to: string }) {
const page = this.pages.find(p => p.name === from);
onLoadExample(): void {
this.store.loadExample();
this.showWelcome.set(false);
}
readonly pageNames = computed(() => this.store.pages().map((p) => p.name));
readonly selectedPage = computed<Page | null>(() => {
const pages = this.store.pages();
if (pages.length === 0) return null;
const id = this.selectedPageId();
if (id) {
const found = pages.find((p) => p.id === id);
if (found) return found;
}
// Default to first page.
return pages[0] ?? null;
});
readonly selectedPageName = computed(() => this.selectedPage()?.name ?? null);
readonly selectedPageIndex = computed(() => {
const page = this.selectedPage();
if (!page) return -1;
return this.store.pages().findIndex((p) => p.id === page.id);
});
onSelectPage(index: number): void {
const pages = this.store.pages();
const page = pages[index];
if (page) {
if (from === this.selectedPageName) {
this.selectedPageName = to;
}
page.changeName(to);
this.selectedPageId.set(page.id);
}
}
selectPage(name: string) {
if (!name) {
if (this.pages && this.pages.length > 0) {
name = this.pages[0].name;
}
onAddPage(name: string): void {
this.store.addPage(name);
// Select the newly added page.
const pages = this.store.pages();
const newPage = pages[pages.length - 1];
if (newPage) {
this.selectedPageId.set(newPage.id);
}
this.selectedPageName = name;
window.localStorage.setItem(
USER_DATA_KEY,
JSON.stringify({
selectedPage: name
})
);
if (this.pages && name) {
if (!this.pageNames.includes(name)) {
this.data.addPage(name);
}
const index = this.pageNames.indexOf(name);
this._selectedPage.next(this.pages[index]);
return;
}
this._selectedPage.next(null);
}
async openSettings() {
try {
await this.modalService.showSettings({
page$: this.selectedPage$,
data$: of(this.data)
});
} catch {
// pass
} finally {
this.changeDetection.markForCheck();
onUpdatePage(payload: UpdatePagePayload): void {
const page = this.selectedPage();
if (page) {
this.store.updatePage(page.id, payload);
}
}
onRemovePage(): void {
const page = this.selectedPage();
if (!page) return;
this.store.deletePage(page.id);
this.selectedPageId.set(null);
this.showSettings.set(false);
}
onSwitchAccount(token: string): void {
this.store.switchToken(token);
}
}