Skip to content

Commit

Permalink
f
Browse files Browse the repository at this point in the history
  • Loading branch information
kubk committed Jan 5, 2024
1 parent d2bed4c commit a7bf2cb
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 32 deletions.
27 changes: 24 additions & 3 deletions functions/db/deck-access/get-last-deck-accesses-for-deck-db.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,38 @@
import { DatabaseException } from "../database-exception.ts";
import { getDatabase } from "../get-database.ts";
import { EnvSafe } from "../../env/env-schema.ts";
import { z } from "zod";

const responseSchema = z.array(
z.object({
used_by: z.number().nullable(),
user: z
.object({
id: z.number(),
username: z.string().nullable(),
first_name: z.string().nullable(),
last_name: z.string().nullable(),
})
.nullable(),
share_id: z.string(),
id: z.number(),
created_at: z.string(),
duration_days: z.number().nullable(),
}),
);

export type DeckAccessesForDeckTypeDb = z.infer<typeof responseSchema>;

export const getLastDeckAccessesForDeckDb = async (
envSafe: EnvSafe,
deckId: number,
) => {
): Promise<DeckAccessesForDeckTypeDb> => {
const db = getDatabase(envSafe);

const { data, error } = await db
.from("deck_access")
.select(
"deck_id, author_id, used_by, share_id, id, created_at, duration_days",
"deck_id, author_id, used_by, share_id, id, created_at, duration_days, user:used_by (id, username, first_name, last_name)",
)
.eq("deck_id", deckId)
.order("created_at", { ascending: false })
Expand All @@ -21,5 +42,5 @@ export const getLastDeckAccessesForDeckDb = async (
throw new DatabaseException(error);
}

return data;
return responseSchema.parse(data);
};
24 changes: 8 additions & 16 deletions functions/deck-accesses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,14 @@ import { createAuthFailedResponse } from "./lib/json-response/create-auth-failed
import { handleError } from "./lib/handle-error/handle-error.ts";
import { envSchema } from "./env/env-schema.ts";
import { createBadRequestResponse } from "./lib/json-response/create-bad-request-response.ts";
import { getLastDeckAccessesForDeckDb } from "./db/deck-access/get-last-deck-accesses-for-deck-db.ts";
import { z } from "zod";
import {
DeckAccessesForDeckTypeDb,
getLastDeckAccessesForDeckDb,
} from "./db/deck-access/get-last-deck-accesses-for-deck-db.ts";

const responseSchema = z.object({
accesses: z.array(
z.object({
used_by: z.number().nullable(),
share_id: z.string(),
id: z.number(),
created_at: z.string(),
duration_days: z.number().nullable(),
}),
),
});

export type DeckAccessesForDeckTypeDb = z.infer<typeof responseSchema>;
export type DeckAccessesResponse = {
accesses: DeckAccessesForDeckTypeDb;
};

export const onRequest = handleError(async ({ request, env }) => {
const user = await getUser(request, env);
Expand All @@ -35,7 +27,7 @@ export const onRequest = handleError(async ({ request, env }) => {

const data = await getLastDeckAccessesForDeckDb(envSafe, Number(deckId));

return createJsonResponse<DeckAccessesForDeckTypeDb>({
return createJsonResponse<DeckAccessesResponse>({
accesses: data,
});
});
4 changes: 2 additions & 2 deletions src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { DeckCatalogResponse } from "../../functions/catalog-decks.ts";
import { DeckWithCardsResponse } from "../../functions/deck-with-cards.ts";
import { CopyDeckResponse } from "../../functions/duplicate-deck.ts";
import { DeckCategoryResponse } from "../../functions/deck-categories.ts";
import { DeckAccessesForDeckTypeDb } from "../../functions/deck-accesses.ts";
import { DeckAccessesResponse } from "../../functions/deck-accesses.ts";
import {
AddDeckAccessRequest,
AddDeckAccessResponse,
Expand All @@ -54,7 +54,7 @@ export const addDeckToMineRequest = (body: AddDeckToMineRequest) => {
};

export const getDeckAccessesOfDeckRequest = (deckId: number) => {
return request<DeckAccessesForDeckTypeDb>(`/deck-accesses?deck_id=${deckId}`);
return request<DeckAccessesResponse>(`/deck-accesses?deck_id=${deckId}`);
};

export const addDeckAccessRequest = (body: AddDeckAccessRequest) => {
Expand Down
26 changes: 25 additions & 1 deletion src/screens/deck-form/deck-form.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { observer } from "mobx-react-lite";
import { css } from "@emotion/css";
import { css, cx } from "@emotion/css";
import { Label } from "../../ui/label.tsx";
import { Input } from "../../ui/input.tsx";
import React from "react";
Expand All @@ -23,6 +23,8 @@ import {
import { DeckSpeakFieldEnum } from "../../../functions/db/deck/decks-with-cards-schema.ts";
import { theme } from "../../ui/theme.tsx";
import { t } from "../../translations/t.ts";
import { deckListStore } from "../../store/deck-list-store.ts";
import { reset } from "../../ui/reset.ts";

export const DeckForm = observer(() => {
const deckFormStore = useDeckFormStore();
Expand Down Expand Up @@ -141,12 +143,34 @@ export const DeckForm = observer(() => {
<div className={css({ marginTop: 18 })} />

<Button
icon={"mdi mdi-plus"}
onClick={() => {
deckFormStore.openNewCardForm();
}}
>
{t("add_card")}
</Button>
{deckFormStore.form.id ? (
<button
className={cx(
reset.button,
css({
width: "100%",
color: theme.linkColor,
fontSize: 14,
paddingTop: 6,
textTransform: "uppercase",
}),
)}
onClick={() => {
assert(deckFormStore.form);
assert(deckFormStore.form.id);
deckListStore.goDeckById(deckFormStore.form.id);
}}
>
{t("deck_preview")}
</button>
) : null}
</div>
);
});
27 changes: 23 additions & 4 deletions src/screens/share-deck/share-deck-one-time-links.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@ import { theme } from "../../ui/theme.tsx";
import { DateTime } from "luxon";
import { useShareDeckStore } from "./store/share-deck-store-context.tsx";

const formatAccessUser = (user: {
id: number;
username: string | null;
first_name: string | null;
last_name: string | null;
}) => {
if (user.username) {
return `@${user.username}`;
}
if (user.first_name || user.last_name) {
return `${user.first_name ?? ""} ${user.last_name ?? ""}`;
}
return `#${user.id}`;
};

export const ShareDeckOneTimeLinks = observer(() => {
const store = useShareDeckStore();

Expand Down Expand Up @@ -64,7 +79,8 @@ export const ShareDeckOneTimeLinks = observer(() => {
className={css({
paddingTop: 6,
marginLeft: 12,
borderTop: i !== 0 ? "1px solid #ccc" : undefined,
borderTop:
i !== 0 ? `1px solid ${theme.dividerColor}` : undefined,
})}
>
<div>
Expand All @@ -73,8 +89,7 @@ export const ShareDeckOneTimeLinks = observer(() => {
fontWeight: 500,
})}
>
#{access.id}:{" "}
{access.used_by ? t("share_used") : t("share_unused")}
#{access.id}{" "}
<span
onClick={async () => {
const link = getDeckLink(access.share_id);
Expand All @@ -86,10 +101,14 @@ export const ShareDeckOneTimeLinks = observer(() => {
cursor: "pointer",
})}
>
{" "}
{t("share_copy_link")}
</span>
</div>
<div>
{access.used_by && access.user
? `${t("share_used")} ${formatAccessUser(access.user)}`
: t("share_unused")}
</div>
<div>
{t("share_access_duration_days")}:{" "}
{access.duration_days ?? (
Expand Down
4 changes: 2 additions & 2 deletions src/screens/share-deck/store/share-deck-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import {
} from "../../../api/api.ts";
import { persistableField } from "../../../lib/mobx-form/persistable-field.ts";
import { fromPromise, IPromiseBasedObservable } from "mobx-utils";
import { DeckAccessesForDeckTypeDb } from "../../../../functions/deck-accesses.ts";
import { DeckAccessesResponse } from "../../../../functions/deck-accesses.ts";

export class ShareDeckStore {
isSending = false;
deckAccesses?: IPromiseBasedObservable<DeckAccessesForDeckTypeDb>;
deckAccesses?: IPromiseBasedObservable<DeckAccessesResponse>;
isDeckAccessesOpen = new BooleanToggle(false);

form = {
Expand Down
16 changes: 16 additions & 0 deletions src/store/deck-list-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,22 @@ export class DeckListStore {
);
}

goDeckById(deckId: number) {
if (!this.myInfo) {
return null;
}
const myDeck = this.myInfo.myDecks.find((deck) => deck.id === deckId);
if (myDeck) {
screenStore.go({ type: "deckMine", deckId });
return;
}
const publicDeck = this.publicDecks.find((deck) => deck.id === deckId);
if (publicDeck) {
screenStore.go({ type: "deckPublic", deckId });
return;
}
}

searchDeckById(deckId: number) {
if (!this.myInfo) {
return null;
Expand Down
12 changes: 8 additions & 4 deletions src/translations/t.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const en = {
category_History: "History",
save: "Save",
add_card: "Add card",
deck_preview: 'Deck preview',
add_card_short: "Add card",
card_front_title: "Front side",
card_back_title: "Back side",
Expand Down Expand Up @@ -98,7 +99,7 @@ const en = {
share_days_description:
"How long the deck will be available after the first use",
share_one_time_links_usage: "One-time links",
share_used: "Link have been used ",
share_used: "Link have been used by",
share_unused: "Haven't been used",
share_link_copied: "The link has been copied to your clipboard",
share_copy_link: "Copy link",
Expand All @@ -112,6 +113,7 @@ type Translation = typeof en;

const ru: Translation = {
my_decks: "Мои колоды",
deck_preview: 'Предпросмотр колоды',
show_all_decks: "Показать",
hide_all_decks: "Скрыть",
no_personal_decks_start: "У вас еще нет персональных колод. Вы можете",
Expand Down Expand Up @@ -196,7 +198,7 @@ const ru: Translation = {
validation_number: "Это поле должно быть числом",
validation_positive_number: "Это поле должно быть положительным числом",
share_access_duration_days: "Длительность доступа в днях",
share_used: "Использована ✅",
share_used: "Ссылка была использована",
share_one_time_access_link: "Одноразовая ссылка",
share_deck_settings: "Настройки шеринга колоды",
share_access_duration: "Длительность доступа",
Expand All @@ -219,6 +221,7 @@ const ru: Translation = {
const es: Translation = {
my_decks: "Mis mazos",
show_all_decks: "Mostrar todos",
deck_preview: 'Vista previa del mazo',
hide_all_decks: "Ocultar",
no_personal_decks_start:
"Todavía no tienes ningún mazo personal. Siéntete libre de",
Expand Down Expand Up @@ -319,7 +322,7 @@ const es: Translation = {
"Cuánto tiempo estará disponible el mazo después del primer uso",
share_access_duration_no_limit: "Sin límite",
share_access_duration: "Duración del acceso",
share_used: "El enlace ha sido utilizado ",
share_used: "El enlace ha sido utilizado por",
share_one_time_access_link: "Enlace de acceso de un solo uso",
share_access_duration_days: "Duración del acceso en días",
share_deck_settings: "Compartir un mazo",
Expand All @@ -330,6 +333,7 @@ const ptBr: Translation = {
my_decks: "Meus baralhos",
show_all_decks: "Mostrar todos",
hide_all_decks: "Ocultar",
deck_preview: 'Visualização do baralho',
no_personal_decks_start:
"Você ainda não tem nenhum baralho pessoal. Sinta-se à vontade para",
no_personal_decks_create: "criar um",
Expand Down Expand Up @@ -418,7 +422,7 @@ const ptBr: Translation = {
share_perpetual_link: "Compartilhar link perpétuo",
share_deck_settings: "Compartilhar um baralho",
share_access_duration_days: "Duração do acesso em dias",
share_used: "O link foi usado ",
share_used: "O link foi usado por",
share_one_time_access_link: "Link de acesso único",
share_access_duration: "Duração do acesso",
share_access_duration_no_limit: "Sem limite",
Expand Down

0 comments on commit a7bf2cb

Please sign in to comment.