Remove the closed people pages, keep their user form in settings
This commit is contained in:
@@ -45,7 +45,7 @@ export default function LogDetailsModal({
|
||||
{
|
||||
label: "User",
|
||||
value: log.user_id ? (
|
||||
<Link href={`/admin/people/${log.user_id}`}>
|
||||
<Link href={`/admin/settings/users/${log.user_id}`}>
|
||||
{user_name || "User"} #{log.user_id}
|
||||
</Link>
|
||||
) : (
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
import _ from "lodash";
|
||||
import { AppData } from "@/src/data/app-data";
|
||||
import { useContext, useRef } from "react";
|
||||
import useStatus from "@moduletrace/twui/hooks/useStatus";
|
||||
import type { ApiReqParams, UserType } from "@/src/types";
|
||||
import { AppContext } from "@/src/pages/__root";
|
||||
import checkUserAccess from "@/src/functions/backend/auth/check-user-access";
|
||||
import EJSON from "@/src/utils/ejson";
|
||||
import { useUsersGet } from "@/src/hooks/use-users-get";
|
||||
import type { BUN_SQLITE_COBBLE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
|
||||
type Props = {
|
||||
users_type?: UserType | null;
|
||||
};
|
||||
|
||||
export default function useAllPeopleListInit({ users_type }: Props) {
|
||||
const { pageProps, query } = useContext(AppContext);
|
||||
const { user_types, url } = pageProps || {};
|
||||
|
||||
const limit = AppData["DefaultQueryLimit"];
|
||||
const can_view_users = checkUserAccess({
|
||||
user_types,
|
||||
includes: ["admin"],
|
||||
});
|
||||
|
||||
let location_query = EJSON.parse(url?.searchParams?.q || "") as
|
||||
| ApiReqParams
|
||||
| undefined;
|
||||
|
||||
if (query?.user_type) {
|
||||
if (!location_query) {
|
||||
location_query = {
|
||||
target_user_type: query.user_type as any,
|
||||
};
|
||||
} else {
|
||||
location_query.target_user_type = query.user_type as any;
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
users: people,
|
||||
count,
|
||||
page,
|
||||
setPage,
|
||||
setUsersQuery,
|
||||
setUsers: set_people,
|
||||
ready,
|
||||
} = useUsersGet({
|
||||
query: location_query,
|
||||
});
|
||||
|
||||
const selected = useRef(new Set<BUN_SQLITE_COBBLE_USERS_JOIN>());
|
||||
|
||||
const { refresh, setRefresh } = useStatus();
|
||||
|
||||
return {
|
||||
user_types,
|
||||
limit,
|
||||
can_view_users,
|
||||
people,
|
||||
count,
|
||||
page,
|
||||
setPage,
|
||||
setUsersQuery,
|
||||
set_people,
|
||||
selected,
|
||||
refresh,
|
||||
setRefresh,
|
||||
users_type,
|
||||
location_query,
|
||||
ready,
|
||||
};
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
import Search from "@moduletrace/twui/elements/Search";
|
||||
import Select from "@moduletrace/twui/form/Select";
|
||||
import Divider from "@moduletrace/twui/layout/Divider";
|
||||
import { useRef } from "react";
|
||||
import _ from "lodash";
|
||||
import twuiSlugToNormalText from "@moduletrace/twui/utils/slug-to-normal-text";
|
||||
import type useAllPeopleListInit from "../(hooks)/use-all-people-list-init";
|
||||
import type { BUN_SQLITE_COBBLE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
import searchableFieldToQueryField from "@/src/utils/searchable-field-to-query-field";
|
||||
import type { ApiReqParams } from "@/src/types";
|
||||
|
||||
export default function AllPeopleListSearch({
|
||||
setUsersQuery,
|
||||
location_query,
|
||||
}: ReturnType<typeof useAllPeopleListInit>) {
|
||||
const searchable_fields: (keyof BUN_SQLITE_COBBLE_USERS_JOIN)[] = [
|
||||
"first_name",
|
||||
"last_name",
|
||||
"email",
|
||||
"user_types",
|
||||
];
|
||||
|
||||
const initial_search_field = (Object.keys(location_query || {}).filter(
|
||||
(q) => q.startsWith("search_term"),
|
||||
)?.[0] ||
|
||||
searchableFieldToQueryField({
|
||||
field: searchable_fields[0]!,
|
||||
})) as keyof ApiReqParams;
|
||||
|
||||
const initial_search = String(location_query?.[initial_search_field] || "");
|
||||
|
||||
const search_field_ref = useRef(initial_search_field);
|
||||
const search_value_ref = useRef(initial_search);
|
||||
const initialized_ref = useRef(false);
|
||||
|
||||
function appendQuery() {
|
||||
setUsersQuery((prev) => {
|
||||
let nq = _.cloneDeep(prev) || {};
|
||||
|
||||
for (let i = 0; i < searchable_fields.length; i++) {
|
||||
const sf = searchableFieldToQueryField({
|
||||
field: searchable_fields[i]!,
|
||||
});
|
||||
delete nq[sf];
|
||||
}
|
||||
|
||||
if (search_value_ref.current.match(/./)) {
|
||||
nq[search_field_ref.current] = search_value_ref.current;
|
||||
}
|
||||
|
||||
nq.page = 1;
|
||||
|
||||
if (_.isEqual(nq, prev)) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
return nq;
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Search
|
||||
placeholder="Find People"
|
||||
changeHandler={(value) => {
|
||||
search_value_ref.current = value || "";
|
||||
|
||||
if (!initialized_ref.current) {
|
||||
initialized_ref.current = true;
|
||||
if ((value || "") === initial_search) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
appendQuery();
|
||||
}}
|
||||
defaultValue={initial_search}
|
||||
no_search_button
|
||||
inputProps={{
|
||||
suffix: (
|
||||
<>
|
||||
<Divider vertical className="-my-4 -mr-2 h-9" />
|
||||
<Select
|
||||
options={searchable_fields.map((sf) => ({
|
||||
value: sf,
|
||||
default:
|
||||
searchableFieldToQueryField({
|
||||
field: sf,
|
||||
}) == search_field_ref.current,
|
||||
title: twuiSlugToNormalText(
|
||||
sf.replace(/user_types/, "user_type"),
|
||||
),
|
||||
}))}
|
||||
className="-my-4 min-w-[80px] xs:min-w-[150px] -mr-2 pl-4"
|
||||
wrapperWrapperProps={{
|
||||
className: "-mr-2",
|
||||
}}
|
||||
wrapperProps={{
|
||||
className: "border-none!",
|
||||
}}
|
||||
changeHandler={(value) => {
|
||||
search_field_ref.current =
|
||||
searchableFieldToQueryField({
|
||||
field: value,
|
||||
});
|
||||
appendQuery();
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
autoFocus: true,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import Row from "@moduletrace/twui/layout/Row";
|
||||
import _ from "lodash";
|
||||
import Span from "@moduletrace/twui/layout/Span";
|
||||
import Card from "@moduletrace/twui/elements/Card";
|
||||
import type { RefObject } from "react";
|
||||
import type { BUN_SQLITE_COBBLE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
|
||||
type Props = {
|
||||
selected: RefObject<Set<BUN_SQLITE_COBBLE_USERS_JOIN>>;
|
||||
};
|
||||
|
||||
export default function AllPeopleListSelections({ selected }: Props) {
|
||||
const total = Array.from(selected.current.entries()).length;
|
||||
|
||||
if (!total) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="py-2! px-3! w-full">
|
||||
<Row>
|
||||
<Span>
|
||||
{Array.from(selected.current.entries()).length} items
|
||||
selected
|
||||
</Span>
|
||||
</Row>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import Row from "@moduletrace/twui/layout/Row";
|
||||
import _ from "lodash";
|
||||
import { AppData } from "@/src/data/app-data";
|
||||
import type useAllPeopleListInit from "../(hooks)/use-all-people-list-init";
|
||||
import AllPeopleListSearch from "./all-people-list-search";
|
||||
import AllPeopleListUsersTypeSelect from "./all-people-list-users-type-select";
|
||||
|
||||
export default function AllPeopleListTitleSection(
|
||||
props: ReturnType<typeof useAllPeopleListInit>,
|
||||
) {
|
||||
const { users_type, people, page, count } = props;
|
||||
|
||||
const limit = AppData["DefaultQueryLimit"];
|
||||
|
||||
const range_start = people?.length ? (page - 1) * limit + 1 : 0;
|
||||
const range_end = people?.length ? range_start + people.length - 1 : 0;
|
||||
|
||||
return (
|
||||
<Row className="flex items-center justify-between gap-4 w-full">
|
||||
<Row>
|
||||
<AllPeopleListSearch {...props} />
|
||||
{users_type ? null : (
|
||||
<AllPeopleListUsersTypeSelect {...props} />
|
||||
)}
|
||||
</Row>
|
||||
|
||||
{typeof count === "number" && count > 0 ? (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Showing {range_start}-{range_end} of {count} users
|
||||
</p>
|
||||
) : (
|
||||
<span className="text-sm text-muted-foreground">
|
||||
No Results
|
||||
</span>
|
||||
)}
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import _ from "lodash";
|
||||
import type useAllPeopleListInit from "../(hooks)/use-all-people-list-init";
|
||||
import { UserTypes } from "@/src/dict/user-types-dict";
|
||||
import SearchSelect from "@moduletrace/twui/form/SearchSelect";
|
||||
|
||||
export default function AllPeopleListUsersTypeSelect({
|
||||
setUsersQuery,
|
||||
location_query,
|
||||
}: ReturnType<typeof useAllPeopleListInit>) {
|
||||
const initial_user_type = String(location_query?.target_user_type || "");
|
||||
|
||||
const options = [
|
||||
{ value: "N/A", label: "All Users" },
|
||||
...UserTypes.map((ut) => ({
|
||||
value: ut.value,
|
||||
label: ut.value,
|
||||
})),
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-1">
|
||||
<SearchSelect
|
||||
options={options}
|
||||
defaultValues={[initial_user_type]}
|
||||
changeHandler={(value) => {
|
||||
setUsersQuery((prev) => {
|
||||
const new_query = _.cloneDeep(prev) || {};
|
||||
if (!value || value === "N/A") {
|
||||
delete new_query?.target_user_type;
|
||||
} else {
|
||||
new_query.target_user_type = value as any;
|
||||
}
|
||||
return new_query;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
import Card from "@moduletrace/twui/elements/Card";
|
||||
import LucideIcon from "@moduletrace/twui/elements/lucide-icon";
|
||||
import Tag from "@moduletrace/twui/elements/Tag";
|
||||
import Button from "@moduletrace/twui/layout/Button";
|
||||
import H3 from "@moduletrace/twui/layout/H3";
|
||||
import Img from "@moduletrace/twui/layout/Img";
|
||||
import Row from "@moduletrace/twui/layout/Row";
|
||||
import Span from "@moduletrace/twui/layout/Span";
|
||||
import Stack from "@moduletrace/twui/layout/Stack";
|
||||
import grabMediaURL from "@/src/functions/backend/media/grab-media-url";
|
||||
import type { BUN_SQLITE_COBBLE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
import { AppContext } from "@/src/pages/__root";
|
||||
import isReadOnlyUser from "@/src/utils/rbac/is-read-only-user";
|
||||
import { useContext } from "react";
|
||||
import dayjs from "dayjs";
|
||||
import UserAvatar from "@/src/components/general/user-avatar";
|
||||
|
||||
type Props = {
|
||||
person: BUN_SQLITE_COBBLE_USERS_JOIN;
|
||||
};
|
||||
|
||||
export default function PeopleListCard({ person }: Props) {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
const is_read_only = isReadOnlyUser({
|
||||
user_types: pageProps?.user_types,
|
||||
});
|
||||
const person_name = `${person.first_name + (person.last_name ? ` ${person.last_name}` : "")}`;
|
||||
const person_profile_image = person.profile_media_id
|
||||
? grabMediaURL({
|
||||
media: { id: person.profile_media_id },
|
||||
})
|
||||
: undefined;
|
||||
|
||||
const person_url = `/admin/people/${person.id}`;
|
||||
const edit_person_url = `/admin/people/${person.id}/edit`;
|
||||
|
||||
const date_created = dayjs(Number(person.created_at));
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="cursor-pointer"
|
||||
onClick={(e) => {
|
||||
const target_el = e.target as HTMLElement;
|
||||
|
||||
if (target_el.closest(".cancel-link")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.ctrlKey) {
|
||||
window.open(person_url, "__blank");
|
||||
} else {
|
||||
window.location.pathname = person_url;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Row className="w-full justify-between">
|
||||
<Row>
|
||||
<UserAvatar person={person} size="md" />
|
||||
<Img
|
||||
alt={`${person_name}`}
|
||||
src={
|
||||
person_profile_image?.media_url || "/icons/man.png"
|
||||
}
|
||||
size={60}
|
||||
circle
|
||||
/>
|
||||
<Stack className="gap-2">
|
||||
<H3>{person_name}</H3>
|
||||
<Row className="gap-2!">
|
||||
{person.user_types?.split(",").map((ut, i) => (
|
||||
<Tag key={i} color="gray">
|
||||
{ut}
|
||||
</Tag>
|
||||
))}
|
||||
</Row>
|
||||
<Row className="gap-2!">
|
||||
<LucideIcon
|
||||
name="Clock"
|
||||
size={14}
|
||||
className="opacity-50"
|
||||
/>
|
||||
<Span variant="faded" className="text-xs">
|
||||
{date_created.toString()}
|
||||
</Span>
|
||||
</Row>
|
||||
</Stack>
|
||||
</Row>
|
||||
|
||||
<Row className="cancel-link">
|
||||
{is_read_only ? null : (
|
||||
<Button
|
||||
title="Edit Person"
|
||||
href={edit_person_url}
|
||||
variant="ghost"
|
||||
color="gray"
|
||||
>
|
||||
<LucideIcon name="Edit2" size={18} />
|
||||
</Button>
|
||||
)}
|
||||
</Row>
|
||||
</Row>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import Loading from "@moduletrace/twui/elements/Loading";
|
||||
import Center from "@moduletrace/twui/layout/Center";
|
||||
import Span from "@moduletrace/twui/layout/Span";
|
||||
import Stack from "@moduletrace/twui/layout/Stack";
|
||||
import PeopleListCard from "./people-list-card";
|
||||
import Paper from "@moduletrace/twui/elements/Paper";
|
||||
import AllPeopleListSelections from "./all-people-list-selections";
|
||||
import useAllPeopleListInit from "../(hooks)/use-all-people-list-init";
|
||||
import AllPeopleListSearch from "./all-people-list-search";
|
||||
|
||||
export default function PeopleList() {
|
||||
const init = useAllPeopleListInit({});
|
||||
|
||||
const { people } = init;
|
||||
|
||||
return (
|
||||
<Stack className="w-full items-stretch">
|
||||
<AllPeopleListSearch {...init} />
|
||||
<AllPeopleListSelections {...init} />
|
||||
|
||||
{!people ? (
|
||||
<Paper>
|
||||
<Center className="p-20">
|
||||
<Loading />
|
||||
</Center>
|
||||
</Paper>
|
||||
) : !people[0] ? (
|
||||
<Paper>
|
||||
<Center className="p-20">
|
||||
<Span>No People Found!</Span>
|
||||
</Center>
|
||||
</Paper>
|
||||
) : (
|
||||
people.map((person, index) => {
|
||||
return <PeopleListCard person={person} key={index} />;
|
||||
})
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import AdminHero from "@/src/components/general/admin-hero";
|
||||
import Button from "@moduletrace/twui/layout/Button";
|
||||
import { AppContext } from "@/src/pages/__root";
|
||||
import isReadOnlyUser from "@/src/utils/rbac/is-read-only-user";
|
||||
import { useContext } from "react";
|
||||
|
||||
export default function Hero() {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
const is_read_only = isReadOnlyUser({ user_types: pageProps?.user_types });
|
||||
|
||||
return (
|
||||
<AdminHero
|
||||
title="People"
|
||||
buttons={
|
||||
<>
|
||||
{is_read_only ? null : (
|
||||
<Button
|
||||
title="Create New Person"
|
||||
href="/admin/people/create"
|
||||
>
|
||||
Create New Person
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import Section from "@moduletrace/twui/layout/Section";
|
||||
import Stack from "@moduletrace/twui/layout/Stack";
|
||||
import PeopleList from "../(partials)/people-list";
|
||||
|
||||
export default function PeopleListSection() {
|
||||
return (
|
||||
<Section>
|
||||
<Stack className="w-full items-stretch">
|
||||
<PeopleList />
|
||||
</Stack>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import AdminHero from "@/src/components/general/admin-hero";
|
||||
import Tag from "@moduletrace/twui/elements/Tag";
|
||||
import Button from "@moduletrace/twui/layout/Button";
|
||||
import Row from "@moduletrace/twui/layout/Row";
|
||||
import Span from "@moduletrace/twui/layout/Span";
|
||||
import Stack from "@moduletrace/twui/layout/Stack";
|
||||
import { AppContext } from "@/src/pages/__root";
|
||||
import isReadOnlyUser from "@/src/utils/rbac/is-read-only-user";
|
||||
import { useContext } from "react";
|
||||
|
||||
export default function Hero() {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
|
||||
const person = pageProps?.person;
|
||||
|
||||
if (!person) return null;
|
||||
|
||||
const is_read_only = isReadOnlyUser({
|
||||
user_types: pageProps?.user_types,
|
||||
});
|
||||
|
||||
const person_name = `${person.first_name + (person.last_name ? ` ${person.last_name}` : "")}`;
|
||||
|
||||
return (
|
||||
<AdminHero
|
||||
title={person_name}
|
||||
buttons={
|
||||
<>
|
||||
{is_read_only ? null : (
|
||||
<Button
|
||||
title={`Edit ${person_name} profile`}
|
||||
href={`/admin/people/${person.id}/edit`}
|
||||
>
|
||||
Edit Person
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
description={
|
||||
<Stack className="gap-4">
|
||||
{person.user_types?.[0] ? (
|
||||
<Row className="flex-nowrap">
|
||||
{person.user_types?.split(",").map((ut, i) => (
|
||||
<Tag key={i} color="gray" variant="outlined">
|
||||
{ut}
|
||||
</Tag>
|
||||
))}
|
||||
</Row>
|
||||
) : null}
|
||||
{person.bio ? (
|
||||
<div
|
||||
dangerouslySetInnerHTML={{ __html: person.bio }}
|
||||
className="bio-subtitle"
|
||||
/>
|
||||
) : null}
|
||||
</Stack>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import Paper from "@moduletrace/twui/elements/Paper";
|
||||
import H2 from "@moduletrace/twui/layout/H2";
|
||||
import Row from "@moduletrace/twui/layout/Row";
|
||||
import Section from "@moduletrace/twui/layout/Section";
|
||||
import Span from "@moduletrace/twui/layout/Span";
|
||||
import Stack from "@moduletrace/twui/layout/Stack";
|
||||
import { AppContext } from "@/src/pages/__root";
|
||||
import { useContext } from "react";
|
||||
|
||||
export default function PersonInfo() {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
|
||||
const person = pageProps?.person;
|
||||
|
||||
if (!person) return null;
|
||||
|
||||
const person_name = `${person.first_name + (person.last_name ? ` ${person.last_name}` : "")}`;
|
||||
|
||||
return (
|
||||
<Section>
|
||||
<Row className="w-full grid xl:grid-cols-2">
|
||||
<Paper>
|
||||
<Stack>
|
||||
<H2>Biography</H2>
|
||||
{person.bio ? (
|
||||
<div
|
||||
dangerouslySetInnerHTML={{ __html: person.bio }}
|
||||
className="bio-content"
|
||||
/>
|
||||
) : (
|
||||
<Span>No Bio</Span>
|
||||
)}
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Row>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import Section from "@moduletrace/twui/layout/Section";
|
||||
import { AppContext } from "@/src/pages/__root";
|
||||
import { useContext } from "react";
|
||||
import UserForm from "../../../create/(partials)/user-form";
|
||||
|
||||
export default function EditPersonFormSection() {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
|
||||
const person = pageProps?.person;
|
||||
|
||||
if (!person) return null;
|
||||
|
||||
return (
|
||||
<Section>
|
||||
<UserForm person={person} />
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import AdminHero from "@/src/components/general/admin-hero";
|
||||
import { AppContext } from "@/src/pages/__root";
|
||||
import { useContext } from "react";
|
||||
|
||||
export default function Hero() {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
|
||||
const person = pageProps?.person;
|
||||
|
||||
if (!person) return null;
|
||||
|
||||
const person_name = `${person.first_name + (person.last_name ? ` ${person.last_name}` : "")}`;
|
||||
|
||||
return <AdminHero title={`Edit ${person_name} Profile`} />;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { server as person_server } from "../index.server";
|
||||
import isReadOnlyUser from "@/src/utils/rbac/is-read-only-user";
|
||||
import type { PagePropsType } from "@/src/types";
|
||||
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 await person_server(params);
|
||||
};
|
||||
@@ -1,26 +0,0 @@
|
||||
import type { PagePropsType } from "@/src/types";
|
||||
import type { BunextPageModuleMetaFn } from "@moduletrace/bunext/types";
|
||||
import Hero from "./(sections)/hero";
|
||||
import EditPersonFormSection from "./(sections)/edit-person-form-section";
|
||||
import { SiteData } from "@/src/data/site-data";
|
||||
|
||||
export default function EditPersonPage() {
|
||||
return (
|
||||
<>
|
||||
<Hero />
|
||||
<EditPersonFormSection />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const meta: BunextPageModuleMetaFn = async (params) => {
|
||||
const person = (params.serverRes?.props as PagePropsType | undefined)
|
||||
?.person;
|
||||
|
||||
const person_name = `${person?.first_name + (person?.last_name ? ` ${person.last_name}` : "")}`;
|
||||
|
||||
return {
|
||||
title: `Edit ${person_name} profile | ${SiteData["SiteName"]}`,
|
||||
description: person?.bio || `${SiteData["SiteName"]} Personnel`,
|
||||
};
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
import grabUsers from "@/src/functions/backend/db/users/grab-users";
|
||||
import sanitizeUserBio from "@/src/functions/backend/db/users/sanitize-user-bio";
|
||||
import type { PagePropsType, PageQueryObject } from "@/src/types";
|
||||
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
|
||||
|
||||
export const server: BunextPageServerFn<PagePropsType> = async (params) => {
|
||||
const query: PageQueryObject = params.query;
|
||||
|
||||
if (!query.user_id) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: "/admin",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const user_res = await grabUsers({ query: { user_id: query.user_id } });
|
||||
|
||||
if (!user_res.singleRes) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: "/admin",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
person: sanitizeUserBio({ user: user_res.singleRes }),
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,24 +0,0 @@
|
||||
import type { PagePropsType } from "@/src/types";
|
||||
import type { BunextPageModuleMetaFn } from "@moduletrace/bunext/types";
|
||||
import Hero from "./(sections)/hero";
|
||||
import PersonInfo from "./(sections)/person-info";
|
||||
import { SiteData } from "@/src/data/site-data";
|
||||
|
||||
export default function PersonPage() {
|
||||
return (
|
||||
<>
|
||||
<Hero />
|
||||
<PersonInfo />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const meta: BunextPageModuleMetaFn = async (params) => {
|
||||
const person = (params.serverRes?.props as PagePropsType | undefined)
|
||||
?.person;
|
||||
|
||||
return {
|
||||
title: `${person?.first_name + (person?.last_name ? ` ${person.last_name}` : "")} | ${SiteData["SiteName"]}`,
|
||||
description: person?.bio || `${SiteData["SiteName"]} Personnel`,
|
||||
};
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
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" />;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import Section from "@moduletrace/twui/layout/Section";
|
||||
import UserForm from "../(partials)/user-form";
|
||||
|
||||
export default function UserFormSection() {
|
||||
return (
|
||||
<Section>
|
||||
<UserForm />
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
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 {};
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
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.",
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
import type { BunextPageModuleMeta } from "@moduletrace/bunext/types";
|
||||
import Hero from "./(sections)/hero";
|
||||
import PeopleListSection from "./(sections)/people-list-section";
|
||||
import { SiteData } from "@/src/data/site-data";
|
||||
|
||||
export default function AdminUsersPage() {
|
||||
return (
|
||||
<>
|
||||
<Hero />
|
||||
<PeopleListSection />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const meta: BunextPageModuleMeta = {
|
||||
title: `Admin People | ${SiteData["SiteName"]}`,
|
||||
description: "Manage admin users in the dashboard.",
|
||||
};
|
||||
+1
-1
@@ -59,6 +59,6 @@ export default async function submitUserForm({
|
||||
} else if (existing_full?.id) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
window.location.pathname = `/admin/people/${res.singleRes.id}`;
|
||||
window.location.pathname = `/admin/settings/users/${res.singleRes.id}`;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import AddModalShell from "@/src/layouts/bots/(partials)/add-modal-shell";
|
||||
import type { BUN_SQLITE_COBBLE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
import UserForm from "@/src/pages/admin/people/create/(partials)/user-form";
|
||||
import UserForm from "./user-form";
|
||||
|
||||
type Props = {
|
||||
open: boolean;
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import { UneditableUserTypes } from "@/src/dict/user-types-dict";
|
||||
import type { UserFormObject } from "@/src/types";
|
||||
import type { BUN_SQLITE_COBBLE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
import parseUserTypes from "@/src/utils/parse-user-types";
|
||||
import submitUserForm from "../../(functions)/submit-user-form";
|
||||
import submitUserForm from "@/src/pages/admin/settings/users/(functions)/submit-user-form";
|
||||
import UserFormName from "./user-form-name";
|
||||
import UserFormAction from "./user-form-action";
|
||||
import UserFormEmail from "./user-form-email";
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState } from "react";
|
||||
import type { BUN_SQLITE_COBBLE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
import UserForm from "@/src/pages/admin/people/create/(partials)/user-form";
|
||||
import UserForm from "../../(partials)/user-form";
|
||||
import SettingsGroup from "../../../(partials)/settings-group";
|
||||
import SettingsStatus from "../../../(partials)/settings-status";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user