Skip to content

Commit

Permalink
Fix back navigation bugs (#40)
Browse files Browse the repository at this point in the history
* Fix back navigation bugs
  • Loading branch information
kubk authored May 13, 2024
1 parent f313e26 commit f13c29b
Show file tree
Hide file tree
Showing 18 changed files with 127 additions and 91 deletions.
8 changes: 8 additions & 0 deletions src/api/create-cached-card-input-modes-request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { RequestStore } from "../lib/mobx-request/request-store.ts";
import { cardInputModeListRequest } from "./api.ts";

export const createCachedCardInputModesRequest = () => {
return new RequestStore(cardInputModeListRequest, {
cacheId: "cardInputModeList",
});
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { test, vi, expect } from "vitest";
import { expect, test, vi } from "vitest";
import { AiMassCreationStore } from "./ai-mass-creation-store.ts";
import { when } from "mobx";
import { isFormValid } from "mobx-form-lite";
Expand Down
6 changes: 0 additions & 6 deletions src/screens/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import { SnackbarProviderWrapper } from "./shared/snackbar/snackbar-provider-wra
import { Debug } from "./debug/debug.tsx";
import { BrowserHeader } from "./shared/browser-platform/browser-header.tsx";
import { BrowserMainButton } from "./shared/browser-platform/browser-main-button.tsx";
import { CardInputModeScreen } from "./card-input-mode/card-input-mode-screen.tsx";

export const App = observer(() => {
useRestoreFullScreenExpand();
Expand Down Expand Up @@ -170,11 +169,6 @@ export const App = observer(() => {
</AiMassCreationStoreProvider>
</PreventTelegramSwipeDownClosingIos>
)}
{screenStore.screen.type === "cardInputMode" && (
<PreventTelegramSwipeDownClosingIos>
<CardInputModeScreen />
</PreventTelegramSwipeDownClosingIos>
)}
<BrowserMainButton />
</div>
);
Expand Down
13 changes: 8 additions & 5 deletions src/screens/card-input-mode/card-input-mode-screen.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { observer } from "mobx-react-lite";
import { Screen } from "../shared/screen.tsx";
import { useBackButton } from "../../lib/platform/use-back-button.ts";
import { screenStore } from "../../store/screen-store.ts";
import { useState } from "react";
import { CardInputModeStore } from "./store/card-input-mode-store.ts";
import { useMount } from "../../lib/react/use-mount.ts";
Expand All @@ -10,12 +9,16 @@ import { RadioList } from "../../ui/radio-list/radio-list.tsx";
import { useMainButton } from "../../lib/platform/use-main-button.ts";
import { useProgress } from "../../lib/platform/use-progress.tsx";
import { t } from "../../translations/t.ts";
import { DeckFormStore } from "../deck-form/deck-form/store/deck-form-store.ts";

export const CardInputModeScreen = observer(() => {
const [store] = useState(() => new CardInputModeStore());
type Props = { deckFormStore: DeckFormStore };

export const CardInputModeScreen = observer((props: Props) => {
const { deckFormStore } = props;
const [store] = useState(() => new CardInputModeStore(deckFormStore));

useBackButton(() => {
screenStore.back();
deckFormStore.quitInnerScreen();
});

useMount(() => {
Expand All @@ -31,7 +34,7 @@ export const CardInputModeScreen = observer(() => {
});

return (
<Screen title={t('card_input_mode_screen')}>
<Screen title={t("card_input_mode_screen")}>
{store.cardInputModesRequest.result.status === "loading" ? (
<FullScreenLoader />
) : null}
Expand Down
36 changes: 13 additions & 23 deletions src/screens/card-input-mode/store/card-input-mode-store.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,28 @@
import { RequestStore } from "../../../lib/mobx-request/request-store.ts";
import {
cardInputModeListRequest,
deckChangeInputModeRequest,
} from "../../../api/api.ts";
import { deckChangeInputModeRequest } from "../../../api/api.ts";
import { makeAutoObservable } from "mobx";
import { TextField } from "mobx-form-lite";
import { screenStore } from "../../../store/screen-store.ts";
import { assert } from "../../../lib/typescript/assert.ts";
import { notifyError, notifySuccess } from "../../shared/snackbar/snackbar.tsx";
import { deckListStore } from "../../../store/deck-list-store.ts";
import { t } from "../../../translations/t.ts";

export const createCachedCardInputModesRequest = () => {
return new RequestStore(cardInputModeListRequest, {
cacheId: "cardInputModeList",
});
};
import { DeckFormStore } from "../../deck-form/deck-form/store/deck-form-store.ts";
import { createCachedCardInputModesRequest } from "../../../api/create-cached-card-input-modes-request.ts";

export class CardInputModeStore {
cardInputModesRequest = createCachedCardInputModesRequest();
deckChangeInputModeRequest = new RequestStore(deckChangeInputModeRequest);
modeId = new TextField<string | null>(null);

constructor() {
constructor(private deckFormStore: DeckFormStore) {
makeAutoObservable(this, {}, { autoBind: true });
}

load() {
const { screen } = screenStore;
assert(screen.type === "cardInputMode");
assert(this.deckFormStore.deckForm, "Deck form should be loaded");
const cardInputModeId = this.deckFormStore.deckForm.cardInputModeId;

this.modeId.onChange(screen.cardInputModeId);
this.modeId.onChange(cardInputModeId);
this.cardInputModesRequest.execute();
}

Expand All @@ -39,11 +31,12 @@ export class CardInputModeStore {
return;
}

const { screen } = screenStore;
assert(screen.type === "cardInputMode");
assert(this.deckFormStore.deckForm, "Deck form should be loaded");
const deckId = this.deckFormStore.deckForm.id;
assert(deckId, "Deck id should be defined");

const result = await this.deckChangeInputModeRequest.execute({
deckId: screen.deckId,
deckId: deckId,
cardInputModeId: this.modeId.value,
});

Expand All @@ -55,11 +48,8 @@ export class CardInputModeStore {
return;
}

deckListStore.updateDeckCardInputMode(screen.deckId, this.modeId.value);
deckListStore.updateDeckCardInputMode(deckId, this.modeId.value);
notifySuccess(t("card_input_mode_changed"));
screenStore.go({
type: "deckForm",
deckId: screen.deckId,
});
this.deckFormStore.quitInnerScreen();
}
}
18 changes: 0 additions & 18 deletions src/screens/deck-form/card-form/generated-card-form-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ import { Input } from "../../../ui/input.tsx";
import { HintTransparent } from "../../../ui/hint-transparent.tsx";
import { CardRowLoading } from "../../shared/card-row-loading.tsx";
import { CardRow } from "../../../ui/card-row.tsx";
import { css } from "@emotion/css";
import { theme } from "../../../ui/theme.tsx";
import { screenStore } from "../../../store/screen-store.ts";

type Props = { cardFormStore: CardFormStoreInterface };

Expand Down Expand Up @@ -68,21 +65,6 @@ export const GeneratedCardFormView = observer((props: Props) => {
return (
<CardRow>
<span>{inputMode.title}</span>
<span
onClick={() => {
screenStore.go({
type: "cardInputMode",
cardInputModeId: cardInputModeId,
deckId: localStore.deckId,
});
}}
className={css({
cursor: "pointer",
color: theme.linkColor,
})}
>
{t("edit")}
</span>
</CardRow>
);
})()
Expand Down
8 changes: 8 additions & 0 deletions src/screens/deck-form/card-form/manual-card-form-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { ButtonGrid } from "../../../ui/button-grid.tsx";
import { boolNarrow } from "../../../lib/typescript/bool-narrow.ts";
import { CardAnswerErrors } from "./card-answer-errors.tsx";
import { css } from "@emotion/css";
import { screenStore } from "../../../store/screen-store.ts";

type Props = { cardFormStore: CardFormStoreInterface };

Expand All @@ -40,6 +41,13 @@ export const ManualCardFormView = observer((props: Props) => {
useProgress(() => cardFormStore.isSending);

useBackButton(() => {

const screen = screenStore.screen;
// Avoid duplicated 'deckForm' in the router history
if (screen.type === "deckForm" && screen.cardId) {
screenStore.back();
}

cardFormStore.onBackCard();
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { createCardSideField } from "../../deck-form/store/deck-form-store.ts";
import { createCachedCardInputModesRequest } from "../../../card-input-mode/store/card-input-mode-store.ts";
import { RequestStore } from "../../../../lib/mobx-request/request-store.ts";
import { makeAutoObservable } from "mobx";
import { formTouchAll, isFormValid } from "mobx-form-lite";
Expand All @@ -8,6 +7,7 @@ import { assert } from "../../../../lib/typescript/assert.ts";
import { notifyError } from "../../../shared/snackbar/snackbar.tsx";
import { aiSingleCardGenerateRequest } from "../../../../api/api.ts";
import { deckListStore } from "../../../../store/deck-list-store.ts";
import { createCachedCardInputModesRequest } from "../../../../api/create-cached-card-input-modes-request.ts";

export class AiGeneratedCardFormStore {
form = {
Expand All @@ -26,7 +26,6 @@ export class AiGeneratedCardFormStore {
return;
}


const result = await this.aiSingleCardGenerateRequest.execute({
text: this.form.prompt.value,
deckId: this.deckId,
Expand All @@ -47,7 +46,11 @@ export class AiGeneratedCardFormStore {

const { card } = result.data.data;
deckListStore.addCardOptimistic(card);
screenStore.go({ type: "deckForm", deckId: card.deck_id, cardId: card.id });
screenStore.goOnce({
type: "deckForm",
deckId: card.deck_id,
cardId: card.id,
});
}

get deckId() {
Expand Down
17 changes: 15 additions & 2 deletions src/screens/deck-form/deck-form/deck-form-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { CardList } from "./card-list.tsx";
import { CardFormWrapper } from "../card-form/card-form-wrapper.tsx";
import { PreventTelegramSwipeDownClosingIos } from "../../../lib/platform/telegram/prevent-telegram-swipe-down-closing.tsx";
import { SpeakingCards } from "./speaking-cards.tsx";
import { CardInputModeScreen } from "../../card-input-mode/card-input-mode-screen.tsx";

export const DeckFormScreen = observer(() => {
const deckFormStore = useDeckFormStore();
Expand Down Expand Up @@ -34,6 +35,18 @@ export const DeckFormScreen = observer(() => {
);
}

// No PreventTelegramSwipeDownClosingIos because the description textarea usually requires scroll
return <DeckForm />;
if (deckFormStore.deckFormScreen === "cardInputMode") {
return (
<PreventTelegramSwipeDownClosingIos>
<CardInputModeScreen deckFormStore={deckFormStore} />
</PreventTelegramSwipeDownClosingIos>
);
}

if (deckFormStore.deckFormScreen === "deckForm") {
// No PreventTelegramSwipeDownClosingIos because the description textarea usually requires scroll
return <DeckForm />;
}

return deckFormStore.deckFormScreen satisfies never;
});
15 changes: 2 additions & 13 deletions src/screens/deck-form/deck-form/deck-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const DeckForm = observer(() => {
useProgress(() => deckFormStore.isSending);

if (!deckFormStore.deckForm) {
console.log("Deck form is not loaded");
return null;
}

Expand Down Expand Up @@ -174,19 +175,7 @@ export const DeckForm = observer(() => {
/>
),
onClick: () => {
if (
!deckFormStore.deckForm ||
!isFormValid(deckFormStore.deckForm)
) {
return;
}
const deckId = deckFormStore.deckForm.id;
assert(deckId, "Deck id should be defined");
screenStore.go({
type: "cardInputMode",
deckId: deckId,
cardInputModeId: deckFormStore.deckForm.cardInputModeId,
});
deckFormStore.goCardInputMode();
},
}
: undefined,
Expand Down
17 changes: 12 additions & 5 deletions src/screens/deck-form/deck-form/store/deck-form-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ export class DeckFormStore implements CardFormStoreInterface {
deckForm?: DeckFormType;
upsertDeckRequest = new RequestStore(upsertDeckRequest);
cardInnerScreen = new TextField<CardInnerScreenType>(null);
deckInnerScreen?: "cardList" | "speakingCards";
deckInnerScreen?: "cardList" | "speakingCards" | "cardInputMode";
cardFilter = {
text: new TextField(""),
sortBy: new TextField<CardFilterSortBy>("createdAt"),
Expand All @@ -203,10 +203,6 @@ export class DeckFormStore implements CardFormStoreInterface {
}

loadForm() {
if (this.deckForm) {
return;
}

const screen = screenStore.screen;
assert(screen.type === "deckForm");

Expand Down Expand Up @@ -254,6 +250,17 @@ export class DeckFormStore implements CardFormStoreInterface {
this.deckInnerScreen = "cardList";
}

goCardInputMode() {
if (!this.deckForm) {
return;
}
if (!isFormValid(this.deckForm)) {
formTouchAll(this.deckForm);
return;
}
this.deckInnerScreen = "cardInputMode";
}

quitInnerScreen() {
this.deckInnerScreen = undefined;
}
Expand Down
2 changes: 1 addition & 1 deletion src/screens/deck-list/view-more-decks-toggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const ViewMoreDecksToggle = observer(() => {
)}
onClick={deckListStore.isMyDecksExpanded.toggle}
>
<span className={css({ transform: "translateY(2px)" })}>
<span className={css({ transform: "translateY(2px)", focus: "none" })}>
<ChevronIcon
direction={deckListStore.isMyDecksExpanded.value ? "top" : "bottom"}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/screens/deck-review/deck-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export const DeckPreview = observer(() => {
icon={"mdi-plus-circle mdi-24px"}
outline
onClick={() => {
screenStore.go({
screenStore.goOnce({
type: "cardQuickAddForm",
deckId: deck.id,
});
Expand Down
2 changes: 1 addition & 1 deletion src/screens/deck-review/review-deck-name.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useReviewStore } from "./store/review-store-context.tsx";
import { css } from "@emotion/css";
import { theme } from "../../ui/theme.tsx";
import React from "react";
import { m, AnimatePresence } from "framer-motion";
import { AnimatePresence, m } from "framer-motion";
import { observer } from "mobx-react-lite";
import { LazyLoadFramerMotion } from "../../lib/framer-motion/lazy-load-framer-motion.tsx";

Expand Down
2 changes: 1 addition & 1 deletion src/screens/plans/format-paid-until.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it, expect, vi } from "vitest";
import { describe, expect, it, vi } from "vitest";
import { formatPaidUntil } from "./format-paid-until.tsx";

describe("formatPaidUntil", () => {
Expand Down
31 changes: 31 additions & 0 deletions src/store/screen-store.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { expect, test } from "vitest";
import { ScreenStore } from "./screen-store.ts";

test("screen store - push", () => {
const store = new ScreenStore();
expect(store.screen).toEqual({ type: "main" });
store.go({ type: "plans" });
expect(store.screen).toEqual({ type: "plans" });
store.back();
expect(store.screen).toEqual({ type: "main" });
});

test("screen store - push 1", () => {
const store = new ScreenStore();
expect(store.screen).toEqual({ type: "main" });
store.goOnce({ type: "plans" });
expect(store.screen).toEqual({ type: "plans" });
store.go({ type: "deckCatalog" });
expect(store.screen).toEqual({ type: "deckCatalog" });
store.back();
expect(store.screen).toEqual({ type: "main" });
});

test("screen store - push 2", () => {
const store = new ScreenStore();
expect(store.screen).toEqual({ type: "main" });
store.goOnce({ type: "plans" });
expect(store.screen).toEqual({ type: "plans" });
store.back();
expect(store.screen).toEqual({ type: "main" });
});
Loading

0 comments on commit f13c29b

Please sign in to comment.