Skip to content

Commit

Permalink
feat: user settings export
Browse files Browse the repository at this point in the history
  • Loading branch information
sunaurus committed Apr 14, 2024
1 parent 61fa1b6 commit 948580e
Show file tree
Hide file tree
Showing 16 changed files with 105 additions and 30 deletions.
16 changes: 16 additions & 0 deletions src/app/(api)/next/api/settings/export.json/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { apiClient } from "@/app/apiClient";

export const GET = async (_request: Request) => {
const { my_user: loggedInUser } = await apiClient.getSite();

if (!loggedInUser) {
return Response.json({ status: "not_authorized" }, { status: 401 });
}

const res = await apiClient.exportSettings();

const fileName = `export_${new URL(loggedInUser.local_user_view.person.actor_id).hostname}_${loggedInUser.local_user_view.person.name}_${Number(new Date())}.json`;
return Response.json(res, {
headers: { "Content-Disposition": `attachment; filename=${fileName}` },
});
};
1 change: 1 addition & 0 deletions src/app/(ui)/StyledLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Link, { LinkProps } from "next/link";
type Props = {
readonly children?: React.ReactNode;
readonly className?: string;
readonly download?: string;
} & LinkProps &
React.RefAttributes<HTMLAnchorElement>;

Expand Down
7 changes: 6 additions & 1 deletion src/app/(ui)/button/ButtonLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ type ButtonLinkProps = Pick<
"className" | "children" | "size" | "color"
> & {
readonly href: Route;
readonly download?: string;
};

export const ButtonLink = (props: ButtonLinkProps) => {
return (
<StyledLink className={getButtonClassnames(props)} href={props.href}>
<StyledLink
className={getButtonClassnames(props)}
download={props.download}
href={props.href}
>
{props.children}
</StyledLink>
);
Expand Down
3 changes: 2 additions & 1 deletion src/app/(ui)/markdown/Prose.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export const Prose = (props: Props) => {
`min-w-none prose prose-sm prose-neutral prose-invert max-w-full break-words
prose-p:mx-0 prose-p:my-1 prose-p:break-words prose-p:leading-snug
prose-a:text-primary-400 prose-a:no-underline hover:prose-a:text-primary-300
prose-ul:list-disc prose-li:leading-snug prose-hr:border-neutral-700`,
prose-ul:list-disc prose-li:leading-snug prose-hr:border-dashed
prose-hr:border-neutral-600`,
props.className,
)}
>
Expand Down
2 changes: 1 addition & 1 deletion src/app/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import classNames from "classnames";
import { NavbarCollapsibleLinks } from "@/app/NavbarCollapsibleLinks";
import { MagnifyingGlassIcon } from "@heroicons/react/16/solid";
import { LoggedInUserIcons } from "@/app/u/LoggedInUserIcons";
import { getUnreadCounts } from "@/app/settings/loggedInUserActions";
import { getUnreadCounts } from "@/app/settings/userActions";

export const Navbar = async () => {
const { site_view: siteView, my_user: loggedInUser } =
Expand Down
4 changes: 1 addition & 3 deletions src/app/settings/2fa/disable/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { apiClient } from "@/app/apiClient";
import { StyledLink } from "@/app/(ui)/StyledLink";
import { disable2faAction } from "@/app/settings/loggedInUserActions";
import { disable2faAction } from "@/app/settings/userActions";
import { Input } from "@/app/(ui)/form/Input";
import { SubmitButton } from "@/app/(ui)/button/SubmitButton";

Expand Down
5 changes: 1 addition & 4 deletions src/app/settings/2fa/enable/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { apiClient } from "@/app/apiClient";
import {
disable2faAction,
enable2faAction,
} from "@/app/settings/loggedInUserActions";
import { enable2faAction } from "@/app/settings/userActions";
import { Input } from "@/app/(ui)/form/Input";
import { SubmitButton } from "@/app/(ui)/button/SubmitButton";
import * as QRCode from "qrcode";
Expand Down
5 changes: 2 additions & 3 deletions src/app/settings/AuthForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@

import { SettingsInputWithLabel } from "@/app/settings/SettingsInputWithLabel";
import { MyUserInfo } from "lemmy-js-client";
import { postListSortOptions } from "@/app/post/postListSortOptions";
import {
changePasswordAction,
updateEmailAction,
updateSettingsAction,
} from "@/app/settings/loggedInUserActions";
} from "@/app/settings/userActions";
import { SubmitButton } from "@/app/(ui)/button/SubmitButton";
import { ButtonLink } from "@/app/(ui)/button/ButtonLink";

Expand Down Expand Up @@ -43,6 +41,7 @@ export const AuthForm = (props: { readonly loggedInUser: MyUserInfo }) => {
className={"hidden"}
id={"username"}
name={"username"}
readOnly={true}
type={"text"}
value={props.loggedInUser.local_user_view.person.name}
/>
Expand Down
16 changes: 16 additions & 0 deletions src/app/settings/BlocksForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use client";

import { MyUserInfo } from "lemmy-js-client";
import { updateSettingsAction } from "@/app/settings/userActions";

export const BlocksForm = (props: { readonly loggedInUser: MyUserInfo }) => {
return (
<form
action={updateSettingsAction}
className={"flex max-w-96 flex-col gap-4"}
>
<h1 className={"text-xl font-bold"}>{"Blocks"}</h1>
<p>{"(NOT IMPLEMENTED YET)"}</p>
</form>
);
};
43 changes: 43 additions & 0 deletions src/app/settings/ExportImportForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"use client";

import { MyUserInfo } from "lemmy-js-client";
import { importSettingsAction } from "@/app/settings/userActions";
import { SubmitButton } from "@/app/(ui)/button/SubmitButton";
import { Input } from "@/app/(ui)/form/Input";
import { ButtonLink } from "@/app/(ui)/button/ButtonLink";

export const ExportImportForm = (props: {
readonly loggedInUser: MyUserInfo;
}) => {
return (
<form
action={importSettingsAction}
className={"flex max-w-96 flex-col gap-4"}
>
<h1 className={"text-xl font-bold"}>{"Import/export settings"}</h1>
<p>{"Import and export your account settings as JSON"}</p>
<label>
{"Export"}
<ButtonLink
download={`export_${new URL(props.loggedInUser.local_user_view.person.actor_id).hostname}_${props.loggedInUser.local_user_view.person.name}_${Number(new Date())}.json`}
href={"/next/api/settings/export.json"}
>
{"Export"}
</ButtonLink>
</label>
<div className={"border-t border-dashed border-neutral-700 pt-2"}>
<label>{"Import (NOT IMPLEMENTED YET)"}</label>
<Input
disabled={true}
id={"imported_file"}
name={"imported_file"}
required={true}
type={"file"}
/>
<SubmitButton className={"mt-2 w-full"} disabled={true}>
{"Import"}
</SubmitButton>
</div>
</form>
);
};
2 changes: 1 addition & 1 deletion src/app/settings/ProfileForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { SettingsInputWithLabel } from "@/app/settings/SettingsInputWithLabel";
import { MyUserInfo } from "lemmy-js-client";
import { updateProfileAction } from "@/app/settings/loggedInUserActions";
import { updateProfileAction } from "@/app/settings/userActions";
import { SubmitButton } from "@/app/(ui)/button/SubmitButton";
import { ProfileImageInput } from "@/app/settings/ProfileImageInput";

Expand Down
8 changes: 2 additions & 6 deletions src/app/settings/ProfileImageInput.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import classNames from "classnames";
import { Input } from "@/app/(ui)/form/Input";
import { Select } from "@/app/(ui)/form/Select";
import { MarkdownTextArea } from "@/app/(ui)/markdown/MarkdownTextArea";
import { Image } from "@/app/(ui)/Image";
import { ChangeEvent, MouseEvent, useState } from "react";
import {
Expand All @@ -10,10 +8,7 @@ import {
} from "@/app/(ui)/markdown/imageActions";
import { Button } from "@/app/(ui)/button/Button";
import { TrashIcon } from "@heroicons/react/16/solid";
import {
removeUserAvatar,
removeUserBanner,
} from "@/app/settings/loggedInUserActions";
import { removeUserAvatar, removeUserBanner } from "@/app/settings/userActions";
import { Spinner } from "@/app/(ui)/Spinner";

type Props = {
Expand Down Expand Up @@ -166,6 +161,7 @@ export const ProfileImageInput = (props: Props) => {
className={"hidden"}
id={props.inputId}
name={props.inputId}
readOnly={true}
value={url}
/>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/app/settings/SettingsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
import { SettingsInputWithLabel } from "@/app/settings/SettingsInputWithLabel";
import { MyUserInfo } from "lemmy-js-client";
import { postListSortOptions } from "@/app/post/postListSortOptions";
import { updateSettingsAction } from "@/app/settings/loggedInUserActions";
import { updateSettingsAction } from "@/app/settings/userActions";
import { SubmitButton } from "@/app/(ui)/button/SubmitButton";

export const SettingsForm = (props: { readonly loggedInUser: MyUserInfo }) => {
return (
<form
action={updateSettingsAction}
className={"flex max-w-96 flex-col gap-4"}
className={"flex w-full max-w-96 flex-col gap-4"}
>
<h1 className={"text-xl font-bold"}>{"Preferences"}</h1>
<SettingsInputWithLabel
Expand Down
10 changes: 6 additions & 4 deletions src/app/settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import { apiClient } from "@/app/apiClient";
import { ProfileForm } from "@/app/settings/ProfileForm";
import { SettingsForm } from "@/app/settings/SettingsForm";
import { AuthForm } from "@/app/settings/AuthForm";
import { log } from "node:util";
import { ReactNode } from "react";
import classNames from "classnames";
import { ExportImportForm } from "@/app/settings/ExportImportForm";
import { BlocksForm } from "@/app/settings/BlocksForm";

const SettingsPage = async () => {
const { my_user: loggedInUser } = await apiClient.getSite();
Expand Down Expand Up @@ -44,10 +45,10 @@ const SettingsPage = async () => {
<AuthForm loggedInUser={loggedInUser} />
</Section>
<Section className={"border-l-0 lg:border-l xl:border-l-0"}>
<h1 className={"text-xl"}>{"Blocks"}</h1>
<BlocksForm loggedInUser={loggedInUser} />
</Section>
<Section className={"border-l-0 lg:border-l-0 xl:border-l"}>
<h1 className={"text-xl"}>{"Data"}</h1>
<ExportImportForm loggedInUser={loggedInUser} />
</Section>
<Section className={"border-l-0 lg:border-l xl:border-l"}>
{null}
Expand All @@ -64,7 +65,8 @@ const Section = (props: {
return (
<div
className={classNames(
"w-full border-l border-t border-neutral-700 p-10",
`flex w-full justify-center border-l border-t border-neutral-700 p-4 lg:p-10
xl:justify-start`,
props.className,
)}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,7 @@ export const removeUserBanner = async () => {
revalidatePath("/settings");
revalidatePath("/");
};

export const importSettingsAction = async (settings: object) => {
await apiClient.importSettings(settings);
};
5 changes: 1 addition & 4 deletions src/app/u/LoggedInUserIcons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ import {
import { ClipboardIcon } from "@heroicons/react/20/solid";
import { MyUserInfo } from "lemmy-js-client";
import classNames from "classnames";
import {
getUnreadCounts,
UnreadCounts,
} from "@/app/settings/loggedInUserActions";
import { getUnreadCounts, UnreadCounts } from "@/app/settings/userActions";
import { useInterval } from "usehooks-ts";
import { useState } from "react";

Expand Down

0 comments on commit 948580e

Please sign in to comment.