First Commit. Duplicate bunext-sqlite preset
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
import type {
|
||||
BUN_SQLITE_BSQLITE_USER_TYPES,
|
||||
BUN_SQLITE_BSQLITE_USERS,
|
||||
} from "@/db/types/db";
|
||||
import adminCrudHandler from "@/src/functions/frontend/admin-crud-handler";
|
||||
import clientDeleteMediaHandler from "@/src/functions/frontend/client-delete-media-handler";
|
||||
import clientUploadMediaHandler from "@/src/functions/frontend/client-upload-media-handler";
|
||||
import type useFormInit from "@/src/hooks/use-form-init";
|
||||
import type { UserFormObject } from "@/src/types";
|
||||
import _ from "lodash";
|
||||
|
||||
export default async function submitUserForm({
|
||||
setLoading,
|
||||
setStatus,
|
||||
form,
|
||||
existing_full,
|
||||
existing,
|
||||
image,
|
||||
}: ReturnType<typeof useFormInit<UserFormObject>>) {
|
||||
try {
|
||||
const confirm_msg = existing_full?.id
|
||||
? `Update this user?`
|
||||
: `Create new user?`;
|
||||
|
||||
if (!window.confirm(confirm_msg)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const new_user_data: BUN_SQLITE_BSQLITE_USERS = _.pick<
|
||||
UserFormObject,
|
||||
keyof UserFormObject
|
||||
>(form, ["first_name", "last_name", "email", "username", "bio"]);
|
||||
|
||||
setLoading(true);
|
||||
|
||||
const create_or_update_user_res = await adminCrudHandler({
|
||||
action: existing_full?.id ? "update" : "insert",
|
||||
table: "users",
|
||||
insert_data: [new_user_data],
|
||||
update_data: new_user_data,
|
||||
id: existing_full?.id,
|
||||
});
|
||||
|
||||
const target_user_id =
|
||||
existing_full?.id || create_or_update_user_res.singleRes?.id;
|
||||
|
||||
if (image?.imageBase64Full) {
|
||||
const is_user_settings =
|
||||
window.location.pathname.includes("admin/settings");
|
||||
|
||||
const delete_media_res = await clientDeleteMediaHandler({
|
||||
user_id: target_user_id,
|
||||
media_paradigm: "user-profile-image",
|
||||
});
|
||||
|
||||
if (!delete_media_res.success) {
|
||||
console.log("delete_media_res", delete_media_res);
|
||||
|
||||
throw new Error(
|
||||
delete_media_res.msg ||
|
||||
delete_media_res.error ||
|
||||
`Couldn't delete old media`,
|
||||
);
|
||||
}
|
||||
|
||||
const upload_image_res = await clientUploadMediaHandler({
|
||||
user_id: target_user_id,
|
||||
media_base_64_data_url: image.imageBase64Full,
|
||||
media_paradigms: ["user-profile-image"],
|
||||
media_type: "image",
|
||||
is_media_primary: true,
|
||||
update_on_duplicate: true,
|
||||
reauth: is_user_settings,
|
||||
});
|
||||
|
||||
console.log("upload_image_res", upload_image_res);
|
||||
|
||||
if (!upload_image_res.success) {
|
||||
throw new Error(
|
||||
upload_image_res.msg || "Couldn't upload Image",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (create_or_update_user_res.success && target_user_id) {
|
||||
const delete_user_types = await adminCrudHandler({
|
||||
action: "delete",
|
||||
table: "user_types",
|
||||
sql_query: {
|
||||
query: {
|
||||
user_id: {
|
||||
value: target_user_id,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const user_types = form.user_types;
|
||||
|
||||
if (user_types?.[0]) {
|
||||
const add_user_types =
|
||||
await adminCrudHandler<BUN_SQLITE_BSQLITE_USER_TYPES>({
|
||||
action: "insert",
|
||||
table: "user_types",
|
||||
insert_data: user_types.map((ut) => ({
|
||||
user_id: target_user_id,
|
||||
user_type: ut,
|
||||
})),
|
||||
});
|
||||
|
||||
if (existing_full?.id) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
window.location.pathname = `/admin/people/${target_user_id}`;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log("res", create_or_update_user_res);
|
||||
console.log("form", form);
|
||||
|
||||
throw new Error(
|
||||
create_or_update_user_res.msg || "Person Creation Failed",
|
||||
);
|
||||
}
|
||||
} catch (error: any) {
|
||||
setStatus({
|
||||
error: true,
|
||||
msg: error.message || "User Form Error",
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import Form from "@moduletrace/twui/form/Form";
|
||||
import LoadingOverlay from "@moduletrace/twui/elements/LoadingOverlay";
|
||||
import useFormInit from "@/src/hooks/use-form-init";
|
||||
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
|
||||
import submitUserForm from "../../(functions)/submit-user-form";
|
||||
import UserFormName from "./user-form-name";
|
||||
import Tag from "@moduletrace/twui/elements/Tag";
|
||||
import UserFormAction from "./user-form-action";
|
||||
import UserFormEmail from "./user-form-email";
|
||||
import UserFormUsername from "./user-form-username";
|
||||
import Row from "@moduletrace/twui/layout/Row";
|
||||
import type { UserFormObject } from "@/src/types";
|
||||
import UserFormUserTypes from "./user-form-user-types";
|
||||
import UserFormBio from "./user-form-bio";
|
||||
import UserFormImage from "./user-form-image";
|
||||
|
||||
type Props = {
|
||||
existing_user?: UserFormObject;
|
||||
existing_user_full?: BUN_SQLITE_BSQLITE_USERS;
|
||||
};
|
||||
|
||||
export default function UserForm({ existing_user, existing_user_full }: Props) {
|
||||
const init = useFormInit<UserFormObject>({
|
||||
existing: existing_user,
|
||||
existing_full: existing_user_full,
|
||||
});
|
||||
|
||||
const { loading, status } = init;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form
|
||||
className="w-full gap-6"
|
||||
onSubmit={() => {
|
||||
submitUserForm(init);
|
||||
}}
|
||||
>
|
||||
{status?.error && <Tag color="error">{status.msg}</Tag>}
|
||||
{loading && <LoadingOverlay />}
|
||||
|
||||
<UserFormName {...init} />
|
||||
<Row className="w-full grid xl:grid-cols-2">
|
||||
<UserFormEmail {...init} />
|
||||
<UserFormUsername {...init} />
|
||||
</Row>
|
||||
<UserFormUserTypes {...init} />
|
||||
<Row className="w-full grid xl:grid-cols-2 items-stretch">
|
||||
<UserFormBio {...init} />
|
||||
<UserFormImage {...init} />
|
||||
</Row>
|
||||
<UserFormAction {...init} />
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
|
||||
import Button from "@moduletrace/twui/layout/Button";
|
||||
import useFormInit from "@/src/hooks/use-form-init";
|
||||
|
||||
export default function UserFormAction({
|
||||
setForm,
|
||||
existing,
|
||||
existing_full,
|
||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_BSQLITE_USERS>>) {
|
||||
const title = existing_full?.id ? "Update User" : "Create New User";
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button title={title}>{title}</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
|
||||
import TinyMCEEditor from "@moduletrace/twui/editors/TinyMCE";
|
||||
import Button from "@moduletrace/twui/layout/Button";
|
||||
import useFormInit from "@/src/hooks/use-form-init";
|
||||
|
||||
export default function UserFormBio({
|
||||
setForm,
|
||||
existing,
|
||||
existing_full,
|
||||
form,
|
||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_BSQLITE_USERS>>) {
|
||||
const title = existing_full?.id ? "Update User" : "Create New User";
|
||||
|
||||
return (
|
||||
<>
|
||||
<TinyMCEEditor
|
||||
defaultValue={form.bio}
|
||||
changeHandler={(content) => {
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
bio: content,
|
||||
}));
|
||||
}}
|
||||
placeholder="Write Something about yourself"
|
||||
options={{ height: 300 }}
|
||||
name="Bio"
|
||||
showLabel
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
|
||||
import Input from "@moduletrace/twui/form/Input";
|
||||
import useFormInit from "@/src/hooks/use-form-init";
|
||||
|
||||
export default function UserFormEmail({
|
||||
setForm,
|
||||
form,
|
||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_BSQLITE_USERS>>) {
|
||||
return (
|
||||
<>
|
||||
<Input
|
||||
type="email"
|
||||
placeholder="Email Addres"
|
||||
onChange={(e) => {
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
email: e.target.value,
|
||||
}));
|
||||
}}
|
||||
defaultValue={form.email}
|
||||
showLabel
|
||||
required
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import ImageUpload from "@moduletrace/twui/form/ImageUpload";
|
||||
import grabMediaURL from "@/src/functions/backend/media/grab-media-url";
|
||||
import useFormInit from "@/src/hooks/use-form-init";
|
||||
import type { UserFormObject } from "@/src/types";
|
||||
import type { BUN_SQLITE_BSQLITE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
|
||||
export default function UserFormImage({
|
||||
setForm,
|
||||
existing_full,
|
||||
setImage,
|
||||
}: ReturnType<typeof useFormInit<UserFormObject>>) {
|
||||
const title = existing_full?.id ? "Update User" : "Create New User";
|
||||
|
||||
const person = existing_full as BUN_SQLITE_BSQLITE_USERS_JOIN | undefined;
|
||||
|
||||
const user_image_url = person?.profile_media_id
|
||||
? grabMediaURL({
|
||||
media: { id: person?.profile_media_id },
|
||||
})
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<>
|
||||
<ImageUpload
|
||||
label="User Image"
|
||||
existingImageUrl={user_image_url?.media_url}
|
||||
onChangeHandler={(imgData) => {
|
||||
setImage(imgData);
|
||||
}}
|
||||
setImgURL={(imgURL) => {
|
||||
if (
|
||||
typeof imgURL !== "string" &&
|
||||
typeof imgURL !== "undefined"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
image: imgURL || "",
|
||||
image_thumbnail: imgURL || "",
|
||||
}));
|
||||
}}
|
||||
restoreImageFn={() => {
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
image: user_image_url || "",
|
||||
image_thumbnail: user_image_url || "",
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
|
||||
import Input from "@moduletrace/twui/form/Input";
|
||||
import Row from "@moduletrace/twui/layout/Row";
|
||||
import useFormInit from "@/src/hooks/use-form-init";
|
||||
|
||||
export default function UserFormName({
|
||||
setForm,
|
||||
form,
|
||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_BSQLITE_USERS>>) {
|
||||
return (
|
||||
<Row className="w-full grid xl:grid-cols-2">
|
||||
<Input
|
||||
title="First Name"
|
||||
placeholder="Eg. John"
|
||||
onChange={(e) => {
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
first_name: e.target.value,
|
||||
}));
|
||||
}}
|
||||
defaultValue={form.first_name}
|
||||
autoComplete="given-name"
|
||||
showLabel
|
||||
required
|
||||
/>
|
||||
|
||||
<Input
|
||||
title="Last Name"
|
||||
placeholder="Eg. Doe"
|
||||
onChange={(e) => {
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
last_name: e.target.value,
|
||||
}));
|
||||
}}
|
||||
defaultValue={form.last_name}
|
||||
autoComplete="family-name"
|
||||
showLabel
|
||||
/>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import SearchSelect from "@moduletrace/twui/form/SearchSelect";
|
||||
import { UneditableUserTypes, UserTypes } from "@/src/dict/user-types-dict";
|
||||
import useFormInit from "@/src/hooks/use-form-init";
|
||||
import type { UserFormObject, UserType } from "@/src/types";
|
||||
|
||||
export default function UserFormUserTypes({
|
||||
setForm,
|
||||
form,
|
||||
}: ReturnType<typeof useFormInit<UserFormObject>>) {
|
||||
return (
|
||||
<>
|
||||
<SearchSelect
|
||||
multiple
|
||||
options={UserTypes.filter(
|
||||
(ut) => !UneditableUserTypes.includes(ut.value),
|
||||
).map((ut) => ({
|
||||
value: ut.value,
|
||||
}))}
|
||||
defaultValues={form.user_types || []}
|
||||
changeHandler={(value) => {
|
||||
const user_types = Array.isArray(value)
|
||||
? (value as UserType[])
|
||||
: value
|
||||
? ([value] as UserType[])
|
||||
: [];
|
||||
setForm({ ...form, user_types });
|
||||
}}
|
||||
title="User Types"
|
||||
showLabel
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
|
||||
import Input from "@moduletrace/twui/form/Input";
|
||||
import useFormInit from "@/src/hooks/use-form-init";
|
||||
|
||||
export default function UserFormUsername({
|
||||
setForm,
|
||||
form,
|
||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_BSQLITE_USERS>>) {
|
||||
return (
|
||||
<>
|
||||
<Input
|
||||
placeholder="Username"
|
||||
onChange={(e) => {
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
username: e.target.value,
|
||||
}));
|
||||
}}
|
||||
defaultValue={form.username}
|
||||
showLabel
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import AdminHero from "@/src/components/general/admin-hero";
|
||||
import Button from "@moduletrace/twui/layout/Button";
|
||||
|
||||
export default function Hero() {
|
||||
return <AdminHero title="Create New Person" />;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import Section from "@moduletrace/twui/layout/Section";
|
||||
import UserForm from "../(partials)/user-form";
|
||||
|
||||
export default function UserFormSection() {
|
||||
return (
|
||||
<Section>
|
||||
<UserForm />
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { PagePropsType } from "@/src/types";
|
||||
import isReadOnlyUser from "@/src/utils/rbac/is-read-only-user";
|
||||
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
|
||||
|
||||
export const server: BunextPageServerFn<PagePropsType> = async (params) => {
|
||||
const user_types = params.props?.user_types;
|
||||
|
||||
if (isReadOnlyUser({ user_types })) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: "/admin/people",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
import type { BunextPageModuleMeta } from "@moduletrace/bunext/types";
|
||||
import Hero from "./(sections)/hero";
|
||||
import UserFormSection from "./(sections)/user-form-section";
|
||||
import { SiteData } from "@/src/data/site-data";
|
||||
|
||||
export default function AdminUsersCreatePage() {
|
||||
return (
|
||||
<>
|
||||
<Hero />
|
||||
<UserFormSection />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const meta: BunextPageModuleMeta = {
|
||||
title: `Create Admin User | ${SiteData["SiteName"]}`,
|
||||
description: "Create a new admin user in the dashboard.",
|
||||
};
|
||||
Reference in New Issue
Block a user