Skip to content

Commit

Permalink
Card input mode (#39)
Browse files Browse the repository at this point in the history
* Card input mode
  • Loading branch information
kubk authored May 12, 2024
1 parent 6d7993a commit bd5475d
Show file tree
Hide file tree
Showing 69 changed files with 930 additions and 366 deletions.
31 changes: 31 additions & 0 deletions src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ import {
AiSpeechGenerateRequest,
AiSpeechGenerateResponse,
} from "../../functions/ai-speech-generate.ts";
import {
AiSingleCardRequest,
AiSingleCardResponse,
} from "../../functions/ai-single-card-generate.ts";
import { CardInputModeListResponse } from "../../functions/card-input-mode-list.ts";
import {
CardInputModeChangeRequest,
CardInputModeChangeResponse,
} from "../../functions/card-input-mode-change.ts";

export const healthRequest = () => {
return request<HealthResponse>("/health");
Expand Down Expand Up @@ -263,3 +272,25 @@ export const aiSpeechGenerateRequest = (body: AiSpeechGenerateRequest) => {
body,
);
};

export const aiSingleCardGenerateRequest = (body: AiSingleCardRequest) => {
return request<AiSingleCardResponse, AiSingleCardRequest>(
"/ai-single-card-generate",
"POST",
body,
);
};

export const cardInputModeListRequest = () => {
return request<CardInputModeListResponse>("/card-input-mode-list");
};

export const deckChangeInputModeRequest = (
body: CardInputModeChangeRequest,
) => {
return request<CardInputModeChangeResponse, CardInputModeChangeRequest>(
"/card-input-mode-change",
"PUT",
body,
);
};
2 changes: 1 addition & 1 deletion src/lib/platform/browser/browser-platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Platform, PlatformTheme } from "../platform.ts";
import { makeAutoObservable } from "mobx";
import { assert } from "../../typescript/assert.ts";
import { BooleanToggle } from "mobx-form-lite";
import { PlatformSchemaType } from "../../../../functions/services/get-user.ts";
import { PlatformSchemaType } from "../../../../functions/services/get-telegram-user.ts";
import { Language } from "../../../translations/t.ts";

const cssVariables = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { platform } from "../platform.ts";
import { assert } from "../../typescript/assert.ts";
import { BrowserPlatform } from "./browser-platform.ts";

export const useMainButtonProgressBrowser = (cb: () => boolean) => {
export const useProgressBrowser = (cb: () => boolean) => {
useMount(() => {
return autorun(() => {
if (cb()) {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/platform/platform.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TelegramPlatform } from "./telegram/telegram-platform.ts";
import { BrowserPlatform } from "./browser/browser-platform.ts";
import { isRunningWithinTelegram } from "./is-running-within-telegram.ts";
import { PlatformSchemaType } from "../../../functions/services/get-user.ts";
import { PlatformSchemaType } from "../../../functions/services/get-telegram-user.ts";
import { Language } from "../../translations/t.ts";

export type PlatformTheme = {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/platform/telegram/telegram-platform.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import WebApp from "@twa-dev/sdk";
import { Platform, PlatformTheme } from "../platform.ts";
import { cssVarToValue } from "./css-var-to-value.ts";
import { PlatformSchemaType } from "../../../../functions/services/get-user.ts";
import { PlatformSchemaType } from "../../../../functions/services/get-telegram-user.ts";
import { Language } from "../../../translations/t.ts";

const buttonColor = "var(--tg-theme-button-color)";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useMount } from "../../react/use-mount.ts";
import { autorun } from "mobx";
import WebApp from "@twa-dev/sdk";

export const useMainButtonProgressTelegram = (cb: () => boolean) => {
export const useProgressTelegram = (cb: () => boolean) => {
return useMount(() => {
return autorun(() => {
if (cb()) {
Expand Down
9 changes: 0 additions & 9 deletions src/lib/platform/use-main-button-progress.tsx

This file was deleted.

9 changes: 9 additions & 0 deletions src/lib/platform/use-progress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { platform } from "./platform.ts";
import { TelegramPlatform } from "./telegram/telegram-platform.ts";
import { useProgressTelegram } from "./telegram/use-progress-telegram.tsx";
import { useProgressBrowser } from "./browser/use-progress-browser.ts";

export const useProgress =
platform instanceof TelegramPlatform
? useProgressTelegram
: useProgressBrowser;
2 changes: 1 addition & 1 deletion src/lib/request/request.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { trimEnd, trimStart } from "../string/trim.ts";
import { platform } from "../platform/platform.ts";
import { collectClientData } from "./collect-client-data.ts";
import { UserHeaders } from "../../../functions/services/get-user.ts";
import { UserHeaders } from "../../../functions/services/get-telegram-user.ts";

const baseUrl = import.meta.env.VITE_API_URL || "";

Expand Down
3 changes: 3 additions & 0 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { App } from "./screens/app.tsx";
import "./index.css";
import "@mdi/font/css/materialdesignicons.min.css";
import { platform } from "./lib/platform/platform.ts";
import { applyFormatters } from "mobx-log";

applyFormatters();

platform.initialize();

Expand Down
4 changes: 2 additions & 2 deletions src/screens/ai-mass-creation/ai-mass-creation-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Input } from "../../ui/input.tsx";
import React from "react";
import { ValidationError } from "../../ui/validation-error.tsx";
import { useMainButton } from "../../lib/platform/use-main-button.ts";
import { useMainButtonProgress } from "../../lib/platform/use-main-button-progress.tsx";
import { useProgress } from "../../lib/platform/use-progress.tsx";
import { useBackButton } from "../../lib/platform/use-back-button.ts";
import { screenStore } from "../../store/screen-store.ts";

Expand All @@ -28,7 +28,7 @@ export const AiMassCreationForm = observer(() => {
screenStore.back();
});

useMainButtonProgress(() => store.aiMassGenerateRequest.isLoading);
useProgress(() => store.aiMassGenerateRequest.isLoading);

return (
<Screen title={t("ai_cards_title")}>
Expand Down
4 changes: 2 additions & 2 deletions src/screens/ai-mass-creation/api-keys-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { theme } from "../../ui/theme.tsx";
import { Flex } from "../../ui/flex.tsx";
import { chatGptModels } from "./store/ai-mass-creation-store.ts";
import { useBackButton } from "../../lib/platform/use-back-button.ts";
import { useMainButtonProgress } from "../../lib/platform/use-main-button-progress.tsx";
import { useProgress } from "../../lib/platform/use-progress.tsx";
import { TextField } from "mobx-form-lite";

export const ApiKeysScreen = observer(() => {
Expand All @@ -29,7 +29,7 @@ export const ApiKeysScreen = observer(() => {
store.screen.onChange(null);
});

useMainButtonProgress(() => store.upsertUserAiCredentialsRequest.isLoading);
useProgress(() => store.upsertUserAiCredentialsRequest.isLoading);

const isRegularInput = store.isApiKeyRegularInput;

Expand Down
4 changes: 2 additions & 2 deletions src/screens/ai-mass-creation/cards-generated-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { theme } from "../../ui/theme.tsx";
import React from "react";
import { t } from "../../translations/t.ts";
import { screenStore } from "../../store/screen-store.ts";
import { useMainButtonProgress } from "../../lib/platform/use-main-button-progress.tsx";
import { useProgress } from "../../lib/platform/use-progress.tsx";
import { CardNumber } from "../../ui/card-number.tsx";
import { translateAddCards } from "./translations.ts";

Expand All @@ -37,7 +37,7 @@ export const CardsGeneratedScreen = observer(() => {
},
);

useMainButtonProgress(() => store.addCardsMultipleRequest.isLoading);
useProgress(() => store.addCardsMultipleRequest.isLoading);

return (
<Screen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { observer } from "mobx-react-lite";
import { useAiMassCreationStore } from "./store/ai-mass-creation-store-provider.tsx";
import { assert } from "../../lib/typescript/assert.ts";
import { useState } from "react";
import { createMockCardPreviewForm } from "../deck-form/create-mock-card-preview-form.ts";
import { CardPreview } from "../deck-form/card-preview.tsx";
import { createMockCardPreviewForm } from "../deck-form/card-form/create-mock-card-preview-form.ts";
import { CardPreview } from "../deck-form/card-form/card-preview.tsx";

type Props = {
card: { front: string; back: string; example?: string };
Expand Down
8 changes: 4 additions & 4 deletions src/screens/ai-mass-creation/previous-prompts-screen.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { observer, useLocalStore } from "mobx-react-lite";
import { observer, useLocalObservable } from "mobx-react-lite";
import { Screen } from "../shared/screen.tsx";
import { useAiMassCreationStore } from "./store/ai-mass-creation-store-provider.tsx";
import { useMount } from "../../lib/react/use-mount.ts";
Expand All @@ -16,7 +16,7 @@ import { EmptyState } from "../../ui/empty-state.tsx";

export const PreviousPromptsScreen = observer(() => {
const store = useAiMassCreationStore();
const localStore = useLocalStore(() => ({
const localStore = useLocalObservable(() => ({
selectedIndex: new TextField<number | null>(null),
get isMainButtonVisible() {
return localStore.selectedIndex.value !== null;
Expand All @@ -41,7 +41,7 @@ export const PreviousPromptsScreen = observer(() => {

return (
<Screen title={t("ai_cards_previous_prompts")}>
<Flex direction={"column"} gap={4}>
<Flex direction={"column"} gap={8}>
{store.userPreviousPromptsRequest.isLoading && <ScreenLoader />}
{store.userPreviousPromptsRequest.result.status === "success" &&
store.userPreviousPromptsRequest.result.data.length === 0 && (
Expand Down Expand Up @@ -72,7 +72,7 @@ export const PreviousPromptsScreen = observer(() => {
}),
isSelected &&
css({
border: `2px solid ${theme.buttonColor}`,
outline: `2px solid ${theme.buttonColor}`,
}),
)}
key={i}
Expand Down
9 changes: 6 additions & 3 deletions src/screens/ai-mass-creation/store/ai-mass-creation-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,12 @@ export class AiMassCreationStore {
return;
}

assert(screenStore.screen.type === "aiMassCreation", "Invalid screen type");
const { screen } = screenStore;

assert(screen.type === "aiMassCreation", "Invalid screen type");

const result = await this.addCardsMultipleRequest.execute({
deckId: screenStore.screen.deckId,
deckId: screen.deckId,
cards: this.massCreationForm.cards.value,
});

Expand All @@ -284,9 +286,10 @@ export class AiMassCreationStore {

notifySuccess(t("ai_cards_added"));
deckListStore.replaceDeck(result.data.deck);
deckListStore.updateCardsToReview(result.data.cardsToReview);
screenStore.go({
type: "deckForm",
deckId: screenStore.screen.deckId,
deckId: screen.deckId,
});
}
}
4 changes: 2 additions & 2 deletions src/screens/ai-mass-creation/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,13 @@ export const translateHowMassCreationWorksText = () => {
example2: "Пример 2",
description:
"Генерируйте множество карточек за раз с использованием ИИ и вашего собственного ключа API",
promptExample1: "Сгенерировать 3 карточки со столицами мира",
promptExample1: "Сгенерируй 3 карточки со столицами мира",
frontExample1: "Страна",
backExample1: "Столица",
resultExample1:
"Пример результата: Германия - Берлин, Франция - Париж, Канада - Оттава",
promptExample2:
"Сгенерировать 2 карточки с русскими и французскими словами на тему фруктов",
"Сгенерируй 2 карточки с русскими и французскими словами на тему фруктов",
frontExample2: "Фрукт на русском",
backExample2: "Фрукт на французском",
resultExample2: "Пример результата: Яблоко - Pomme, Банан - Banane",
Expand Down
12 changes: 9 additions & 3 deletions src/screens/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { MainScreen } from "./deck-list/main-screen.tsx";
import { DeckScreen } from "./deck-review/deck-screen.tsx";
import { ReviewStoreProvider } from "./deck-review/store/review-store-context.tsx";
import { screenStore } from "../store/screen-store.ts";
import { DeckFormScreen } from "./deck-form/deck-form-screen.tsx";
import { DeckFormStoreProvider } from "./deck-form/store/deck-form-store-context.tsx";
import { QuickAddCardFormPage } from "./deck-form/quick-add-card-form-page.tsx";
import { DeckFormScreen } from "./deck-form/deck-form/deck-form-screen.tsx";
import { DeckFormStoreProvider } from "./deck-form/deck-form/store/deck-form-store-context.tsx";
import { QuickAddCardFormPage } from "./deck-form/card-form/quick-add-card-form-page.tsx";
import { VersionWarning } from "./shared/version-warning.tsx";
import React from "react";
import { deckListStore } from "../store/deck-list-store.ts";
Expand Down Expand Up @@ -40,6 +40,7 @@ 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 @@ -169,6 +170,11 @@ export const App = observer(() => {
</AiMassCreationStoreProvider>
</PreventTelegramSwipeDownClosingIos>
)}
{screenStore.screen.type === "cardInputMode" && (
<PreventTelegramSwipeDownClosingIos>
<CardInputModeScreen />
</PreventTelegramSwipeDownClosingIos>
)}
<BrowserMainButton />
</div>
);
Expand Down
59 changes: 59 additions & 0 deletions src/screens/card-input-mode/card-input-mode-screen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
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";
import { FullScreenLoader } from "../../ui/full-screen-loader.tsx";
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";

export const CardInputModeScreen = observer(() => {
const [store] = useState(() => new CardInputModeStore());

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

useMount(() => {
store.load();
});

useMainButton(t("save"), () => {
store.submit();
});

useProgress(() => {
return store.cardInputModesRequest.isLoading;
});

return (
<Screen title={t('card_input_mode_screen')}>
{store.cardInputModesRequest.result.status === "loading" ? (
<FullScreenLoader />
) : null}
{store.cardInputModesRequest.result.status === "success" ? (
<div>
<RadioList
selectedId={store.modeId?.value}
options={[
{ id: null, title: "Manual input" } as {
id: string | null;
title: string;
},
].concat(
store.cardInputModesRequest.result.data.map((inputMode) => ({
id: inputMode.id,
title: inputMode.title,
})),
)}
onChange={store.modeId.onChange}
/>
</div>
) : null}
</Screen>
);
});
Loading

0 comments on commit bd5475d

Please sign in to comment.