mirror of
https://codeberg.org/superseriousbusiness/gotosocial.git
synced 2024-12-22 08:54:26 +03:00
89e0cfd874
* update settings panels, add pending overview + approve/deny functions * add admin accounts get, approve, reject * send approved/rejected emails * use signup URL * docs! * email * swagger * web linting * fix email tests * wee lil fixerinos * use new paging logic for GetAccounts() series of admin endpoints, small changes to query building * shuffle useAccountIDIn check *before* adding to query * fix parse from toot react error * use `netip.Addr` * put valid slices in globals * optimistic updates for account state --------- Co-authored-by: kim <grufwub@gmail.com>
179 lines
5.1 KiB
TypeScript
179 lines
5.1 KiB
TypeScript
/*
|
|
GoToSocial
|
|
Copyright (C) GoToSocial Authors admin@gotosocial.org
|
|
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import React from "react";
|
|
import { useRoute, Redirect } from "wouter";
|
|
|
|
import { useGetAccountQuery } from "../../../lib/query";
|
|
|
|
import FormWithData from "../../../lib/form/form-with-data";
|
|
|
|
import { useBaseUrl } from "../../../lib/navigation/util";
|
|
import FakeProfile from "../../../components/fake-profile";
|
|
|
|
import { AdminAccount } from "../../../lib/types/account";
|
|
import { HandleSignup } from "./handlesignup";
|
|
import { AccountActions } from "./actions";
|
|
import BackButton from "../../../components/back-button";
|
|
|
|
export default function AccountDetail() {
|
|
// /settings/admin/accounts
|
|
const accountsBaseUrl = useBaseUrl();
|
|
|
|
let [_match, params] = useRoute(`${accountsBaseUrl}/:accountId`);
|
|
|
|
if (params?.accountId == undefined) {
|
|
return <Redirect to={accountsBaseUrl} />;
|
|
} else {
|
|
return (
|
|
<div className="account-detail">
|
|
<h1 className="text-cutoff">
|
|
<BackButton to={accountsBaseUrl} /> Account Details
|
|
</h1>
|
|
<FormWithData
|
|
dataQuery={useGetAccountQuery}
|
|
queryArg={params.accountId}
|
|
DataForm={AccountDetailForm}
|
|
{...{accountsBaseUrl}}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
interface AccountDetailFormProps {
|
|
accountsBaseUrl: string,
|
|
data: AdminAccount,
|
|
}
|
|
|
|
function AccountDetailForm({ data: adminAcct, accountsBaseUrl }: AccountDetailFormProps) {
|
|
let yesOrNo = (b: boolean) => {
|
|
return b ? "yes" : "no";
|
|
};
|
|
|
|
let created = new Date(adminAcct.created_at).toDateString();
|
|
let lastPosted = "never";
|
|
if (adminAcct.account.last_status_at) {
|
|
lastPosted = new Date(adminAcct.account.last_status_at).toDateString();
|
|
}
|
|
const local = !adminAcct.domain;
|
|
|
|
return (
|
|
<>
|
|
<FakeProfile {...adminAcct.account} />
|
|
<h3>General Account Details</h3>
|
|
{ adminAcct.suspended &&
|
|
<div className="info">
|
|
<i className="fa fa-fw fa-info-circle" aria-hidden="true"></i>
|
|
<b>Account is suspended.</b>
|
|
</div>
|
|
}
|
|
<dl className="info-list">
|
|
{ !local &&
|
|
<div className="info-list-entry">
|
|
<dt>Domain</dt>
|
|
<dd>{adminAcct.domain}</dd>
|
|
</div>}
|
|
<div className="info-list-entry">
|
|
<dt>Created</dt>
|
|
<dd><time dateTime={adminAcct.created_at}>{created}</time></dd>
|
|
</div>
|
|
<div className="info-list-entry">
|
|
<dt>Last posted</dt>
|
|
<dd>{lastPosted}</dd>
|
|
</div>
|
|
<div className="info-list-entry">
|
|
<dt>Suspended</dt>
|
|
<dd>{yesOrNo(adminAcct.suspended)}</dd>
|
|
</div>
|
|
<div className="info-list-entry">
|
|
<dt>Silenced</dt>
|
|
<dd>{yesOrNo(adminAcct.silenced)}</dd>
|
|
</div>
|
|
<div className="info-list-entry">
|
|
<dt>Statuses</dt>
|
|
<dd>{adminAcct.account.statuses_count}</dd>
|
|
</div>
|
|
<div className="info-list-entry">
|
|
<dt>Followers</dt>
|
|
<dd>{adminAcct.account.followers_count}</dd>
|
|
</div>
|
|
<div className="info-list-entry">
|
|
<dt>Following</dt>
|
|
<dd>{adminAcct.account.following_count}</dd>
|
|
</div>
|
|
</dl>
|
|
{ local &&
|
|
// Only show local account details
|
|
// if this is a local account!
|
|
<>
|
|
<h3>Local Account Details</h3>
|
|
{ !adminAcct.approved &&
|
|
<div className="info">
|
|
<i className="fa fa-fw fa-info-circle" aria-hidden="true"></i>
|
|
<b>Account is pending.</b>
|
|
</div>
|
|
}
|
|
{ !adminAcct.confirmed &&
|
|
<div className="info">
|
|
<i className="fa fa-fw fa-info-circle" aria-hidden="true"></i>
|
|
<b>Account email not yet confirmed.</b>
|
|
</div>
|
|
}
|
|
<dl className="info-list">
|
|
<div className="info-list-entry">
|
|
<dt>Email</dt>
|
|
<dd>{adminAcct.email} {<b>{adminAcct.confirmed ? "(confirmed)" : "(not confirmed)"}</b> }</dd>
|
|
</div>
|
|
<div className="info-list-entry">
|
|
<dt>Disabled</dt>
|
|
<dd>{yesOrNo(adminAcct.disabled)}</dd>
|
|
</div>
|
|
<div className="info-list-entry">
|
|
<dt>Approved</dt>
|
|
<dd>{yesOrNo(adminAcct.approved)}</dd>
|
|
</div>
|
|
<div className="info-list-entry">
|
|
<dt>Sign-Up Reason</dt>
|
|
<dd>{adminAcct.invite_request ?? <i>none provided</i>}</dd>
|
|
</div>
|
|
{ (adminAcct.ip && adminAcct.ip !== "0.0.0.0") &&
|
|
<div className="info-list-entry">
|
|
<dt>Sign-Up IP</dt>
|
|
<dd>{adminAcct.ip}</dd>
|
|
</div> }
|
|
{ adminAcct.locale &&
|
|
<div className="info-list-entry">
|
|
<dt>Locale</dt>
|
|
<dd>{adminAcct.locale}</dd>
|
|
</div> }
|
|
</dl>
|
|
</> }
|
|
{ local && !adminAcct.approved
|
|
?
|
|
<HandleSignup
|
|
account={adminAcct}
|
|
accountsBaseUrl={accountsBaseUrl}
|
|
/>
|
|
:
|
|
<AccountActions account={adminAcct} />
|
|
}
|
|
</>
|
|
);
|
|
}
|