Skip to content

Commit

Permalink
Duplicate folder (#7)
Browse files Browse the repository at this point in the history
* Duplicate folder
  • Loading branch information
kubk authored Jan 26, 2024
1 parent 1a8c319 commit 48bc53a
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 27 deletions.
8 changes: 8 additions & 0 deletions src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
CreateOrderResponse,
} from "../../functions/order.ts";
import { MyPlansResponse } from "../../functions/my-plans.ts";
import { DuplicateFolderResponse } from "../../functions/duplicate-folder.ts";

export const healthRequest = () => {
return request<HealthResponse>("/health");
Expand Down Expand Up @@ -82,6 +83,13 @@ export const duplicateDeckRequest = (deckId: number) => {
return request<CopyDeckResponse>(`/duplicate-deck?deck_id=${deckId}`, "POST");
};

export const duplicateFolderRequest = (folderId: number) => {
return request<DuplicateFolderResponse>(
`/duplicate-folder?folder_id=${folderId}`,
"POST",
);
};

export const userSettingsRequest = (body: UserSettingsRequest) => {
return request<UserSettingsResponse, UserSettingsRequest>(
"/user-settings",
Expand Down
5 changes: 4 additions & 1 deletion src/screens/deck-review/deck-finished.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useTelegramProgress } from "../../lib/telegram/use-telegram-progress.ts
import { t } from "../../translations/t.ts";
import { getEncouragingMessage } from "../../translations/get-encouraging-message.tsx";
import { WantMoreCardsButton } from "./want-more-cards-button.tsx";
import { deckListStore } from "../../store/deck-list-store.ts";

type Props = {
type: "deck" | "repeat_all";
Expand All @@ -21,7 +22,9 @@ export const DeckFinished = observer((props: Props) => {
const reviewStore = useReviewStore();

useMount(() => {
reviewStore.submitFinished();
reviewStore.submitFinished(() => {
deckListStore.load();
});
});
useMainButton(t("go_back"), () => {
screenStore.go({ type: "main" });
Expand Down
10 changes: 2 additions & 8 deletions src/screens/deck-review/deck-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { useMainButton } from "../../lib/telegram/use-main-button.tsx";
import { showConfirm } from "../../lib/telegram/show-confirm.ts";
import { ButtonSideAligned } from "../../ui/button-side-aligned.tsx";
import { useTelegramProgress } from "../../lib/telegram/use-telegram-progress.tsx";
import { duplicateDeckRequest } from "../../api/api.ts";
import { t } from "../../translations/t.ts";
import { userStore } from "../../store/user-store.ts";
import { ButtonGrid } from "../../ui/button-grid.tsx";
Expand Down Expand Up @@ -142,13 +141,8 @@ export const DeckPreview = observer(() => {
<ButtonSideAligned
icon={"mdi-content-duplicate mdi-24px"}
outline
onClick={async () => {
const isConfirmed = await showConfirm(t("duplicate_confirm"));
if (isConfirmed) {
duplicateDeckRequest(deck.id).then(() => {
screenStore.go({ type: "main" });
});
}
onClick={() => {
deckListStore.onDuplicateDeck(deck.id);
}}
>
{t("duplicate")}
Expand Down
9 changes: 3 additions & 6 deletions src/screens/deck-review/store/review-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import { assert } from "../../../lib/typescript/assert.ts";
import { reviewCardsRequest } from "../../../api/api.ts";
import { ReviewOutcome } from "../../../../functions/services/review-card.ts";
import { screenStore } from "../../../store/screen-store.ts";
import {
deckListStore,
DeckWithCardsWithReviewType,
} from "../../../store/deck-list-store.ts";
import { type DeckWithCardsWithReviewType } from "../../../store/deck-list-store.ts";

type ReviewResult = {
forgotIds: number[];
Expand Down Expand Up @@ -172,7 +169,7 @@ export class ReviewStore {
];
}

async submitFinished() {
async submitFinished(onReviewSuccess?: () => void) {
if (!this.hasResult) {
screenStore.go({ type: "main" });
return;
Expand All @@ -182,7 +179,7 @@ export class ReviewStore {

return reviewCardsRequest({ cards: this.cardsToSend }).finally(
action(() => {
deckListStore.load();
onReviewSuccess?.();
this.isReviewSending = false;
}),
);
Expand Down
12 changes: 12 additions & 0 deletions src/screens/folder-review/folder-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ListHeader } from "../../ui/list-header.tsx";
import { assert } from "../../lib/typescript/assert.ts";
import { DeckRowWithCardsToReview } from "../shared/deck-row-with-cards-to-review/deck-row-with-cards-to-review.tsx";
import { ButtonGrid } from "../../ui/button-grid.tsx";
import { userStore } from "../../store/user-store.ts";

export const FolderPreview = observer(() => {
const reviewStore = useReviewStore();
Expand Down Expand Up @@ -141,6 +142,17 @@ export const FolderPreview = observer(() => {
{t("add_deck_short")}
</ButtonSideAligned>
) : null}
{userStore.canDuplicateFolders && (
<ButtonSideAligned
icon={"mdi-content-duplicate mdi-24px"}
outline
onClick={() => {
deckListStore.onDuplicateFolder(folder.id);
}}
>
{t("duplicate")}
</ButtonSideAligned>
)}
{deckListStore.canEditFolder ? (
<ButtonSideAligned
icon={"mdi-pencil-circle mdi-24px"}
Expand Down
14 changes: 14 additions & 0 deletions src/store/deck-list-store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,20 @@ vi.mock("./screen-store", () => {
};
});

vi.mock("../lib/telegram/show-confirm.ts", () => {
return {
showConfirm: () => {
return Promise.resolve(true);
},
};
});

vi.mock("../translations/t.ts", () => {
return {
t: (arg: any) => arg,
};
});

describe("deck list store", () => {
afterEach(() => {
vi.clearAllMocks();
Expand Down
52 changes: 46 additions & 6 deletions src/store/deck-list-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,27 @@ import {
addDeckToMineRequest,
deckWithCardsRequest,
deleteFolderRequest,
duplicateDeckRequest,
duplicateFolderRequest,
getSharedDeckRequest,
myInfoRequest,
removeDeckFromMineRequest,
} from "../api/api.ts";
import { MyInfoResponse } from "../../functions/my-info.ts";
import { type MyInfoResponse } from "../../functions/my-info.ts";
import {
DeckCardDbType,
DeckWithCardsDbType,
type DeckCardDbType,
type DeckWithCardsDbType,
} from "../../functions/db/deck/decks-with-cards-schema.ts";
import { RouteType, screenStore } from "./screen-store.ts";
import { CardToReviewDbType } from "../../functions/db/deck/get-cards-to-review-db.ts";
import { type RouteType, screenStore } from "./screen-store.ts";
import { type CardToReviewDbType } from "../../functions/db/deck/get-cards-to-review-db.ts";
import { assert } from "../lib/typescript/assert.ts";
import { ReviewStore } from "../screens/deck-review/store/review-store.ts";
import { reportHandledError } from "../lib/rollbar/rollbar.tsx";
import { BooleanToggle } from "../lib/mobx-form/boolean-toggle.ts";
import { UserFoldersDbType } from "../../functions/db/folder/get-many-folders-with-decks-db.tsx";
import { type UserFoldersDbType } from "../../functions/db/folder/get-many-folders-with-decks-db.tsx";
import { userStore } from "./user-store.ts";
import { showConfirm } from "../lib/telegram/show-confirm.ts";
import { t } from "../translations/t.ts";

export enum StartParamType {
RepeatAll = "repeat_all",
Expand Down Expand Up @@ -96,6 +100,42 @@ export class DeckListStore {
);
}

async onDuplicateDeck(deckId: number) {
const isConfirmed = await showConfirm(t("duplicate_deck_confirm"));
if (!isConfirmed) {
return;
}

this.isFullScreenLoaderVisible = true;
duplicateDeckRequest(deckId)
.then(() => {
screenStore.go({ type: "main" });
})
.finally(
action(() => {
this.isFullScreenLoaderVisible = false;
}),
);
}

async onDuplicateFolder(folderId: number) {
const isConfirmed = await showConfirm(t("duplicate_folder_confirm"));
if (!isConfirmed) {
return;
}

this.isFullScreenLoaderVisible = true;
duplicateFolderRequest(folderId)
.then(() => {
screenStore.go({ type: "main" });
})
.finally(
action(() => {
this.isFullScreenLoaderVisible = false;
}),
);
}

async handleStartParam(startParam?: string) {
if (!startParam) {
return;
Expand Down
12 changes: 10 additions & 2 deletions src/store/user-store.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { makeAutoObservable } from "mobx";
import { UserDbType } from "../../functions/db/user/upsert-user-db.ts";
import { type UserDbType } from "../../functions/db/user/upsert-user-db.ts";
import { assert } from "../lib/typescript/assert.ts";
import { PlansForUser } from "../../functions/db/plan/get-plans-for-user.ts";
import { type PlansForUser } from "../../functions/db/plan/get-plans-for-user.ts";

export class UserStore {
userInfo?: UserDbType;
Expand Down Expand Up @@ -36,6 +36,14 @@ export class UserStore {
return this.plans?.some((plan) => plan.advanced_duplicate) ?? false;
}

get canDuplicateFolders() {
if (this.isAdmin) {
return true;
}

return this.plans?.some((plan) => plan.advanced_duplicate) ?? false;
}

get isSpeakingCardsEnabled() {
return this.user?.is_speaking_card_enabled ?? false;
}
Expand Down
12 changes: 8 additions & 4 deletions src/translations/t.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ const en = {
cards_new: "New cards",
cards_total: "Total cards",
duplicate: "Duplicate",
duplicate_confirm: "Are you sure to duplicate this deck?",
duplicate_deck_confirm: "Are you sure to duplicate this deck?",
duplicate_folder_confirm: "Are you sure to duplicate this folder?",
delete_deck_confirm:
"Are you sure to remove the deck from your collection? This action can't be undone",
deck_form_remove_card_confirm:
Expand Down Expand Up @@ -153,6 +154,7 @@ type Translation = typeof en;

const ru: Translation = {
validation_at_least_one_deck: "Пожалуйста выберите хотя бы 1 колоду",
duplicate_folder_confirm: "Вы уверены, что хотите продублировать эту папку?",
validation_answer_at_least_one_correct: "Выберите хотя бы 1 правильный ответ",
add_answer: "Добавить ответ",
answer_text: "Текст ответа",
Expand Down Expand Up @@ -244,7 +246,7 @@ const ru: Translation = {
cards_new: "Новых",
cards_total: "Всего",
duplicate: "Копировать",
duplicate_confirm: "Вы уверены, что хотите продублировать эту колоду?",
duplicate_deck_confirm: "Вы уверены, что хотите продублировать эту колоду?",
delete_deck_confirm:
"Вы уверены, что хотите удалить колоду из своей коллекции? Это действие нельзя отменить",
delete: "Удалить",
Expand Down Expand Up @@ -298,6 +300,7 @@ const ru: Translation = {

const es: Translation = {
validation_at_least_one_deck: "Por favor, selecciona al menos 1 mazo",
duplicate_folder_confirm: "¿Estás seguro de duplicar esta carpeta?",
yes_no: "Sí No",
validation_at_least_one_answer_required:
"Se debe proporcionar al menos una respuesta",
Expand Down Expand Up @@ -395,7 +398,7 @@ const es: Translation = {
cards_new: "Nuevas tarjetas",
cards_total: "Total de tarjetas",
duplicate: "Duplicar",
duplicate_confirm: "¿Estás seguro de duplicar este mazo?",
duplicate_deck_confirm: "¿Estás seguro de duplicar este mazo?",
delete_deck_confirm:
"¿Estás seguro de eliminar el mazo de tu colección? Esta acción no se puede deshacer",
delete: "Eliminar",
Expand Down Expand Up @@ -451,6 +454,7 @@ const ptBr: Translation = {
validation_answer_at_least_one_correct:
"Selecione pelo menos uma resposta correta",
is_correct_explanation: `Só pode haver uma resposta correta`,
duplicate_folder_confirm: "Tem certeza de que deseja duplicar esta pasta?",
add_answer: "Adicionar resposta",
answer_text: "Texto da resposta",
answer_type_choice: "Escolha",
Expand Down Expand Up @@ -545,7 +549,7 @@ const ptBr: Translation = {
cards_new: "Novos cartões",
cards_total: "Total de cartões",
duplicate: "Duplicar",
duplicate_confirm: "Tem certeza de que deseja duplicar este baralho?",
duplicate_deck_confirm: "Tem certeza de que deseja duplicar este baralho?",
delete_deck_confirm:
"Tem certeza de que deseja remover o baralho da sua coleção? Esta ação não pode ser desfeita",
delete: "Deletar",
Expand Down

0 comments on commit 48bc53a

Please sign in to comment.