mirror of
https://github.com/PeWu/topola-viewer.git
synced 2026-07-28 14:41:50 +00:00
Upgrade prettier and fix files
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import {SourceHead} from '../head/head';
|
||||
import {GedcomData} from '../../util/gedcom_util';
|
||||
import {ParsedQuery} from 'query-string';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {Checkbox, Form, Header, Item} from 'semantic-ui-react';
|
||||
import {GedcomData} from '../../util/gedcom_util';
|
||||
import {SourceHead} from '../head/head';
|
||||
|
||||
export enum ChartColors {
|
||||
NO_COLOR,
|
||||
@@ -82,158 +82,169 @@ export function ConfigPanel(props: {
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
{SourceHead(props.gedcom)}<Form className="details">
|
||||
<Item.Group>
|
||||
<Item>
|
||||
<Item.Content>
|
||||
<Header sub>
|
||||
<FormattedMessage id="config.colors" defaultMessage="Colors" />
|
||||
</Header>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.colors.NO_COLOR"
|
||||
defaultMessage="none"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="none"
|
||||
checked={props.config.color === ChartColors.NO_COLOR}
|
||||
onClick={() =>
|
||||
props.onChange({
|
||||
...props.config,
|
||||
color: ChartColors.NO_COLOR,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.colors.COLOR_BY_GENERATION"
|
||||
defaultMessage="by generation"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="generation"
|
||||
checked={props.config.color === ChartColors.COLOR_BY_GENERATION}
|
||||
onClick={() =>
|
||||
props.onChange({
|
||||
...props.config,
|
||||
color: ChartColors.COLOR_BY_GENERATION,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.colors.COLOR_BY_SEX"
|
||||
defaultMessage="by sex"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="gender"
|
||||
checked={props.config.color === ChartColors.COLOR_BY_SEX}
|
||||
onClick={() =>
|
||||
props.onChange({
|
||||
...props.config,
|
||||
color: ChartColors.COLOR_BY_SEX,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Form.Field>
|
||||
</Item.Content>
|
||||
</Item>
|
||||
<Item>
|
||||
<Item.Content>
|
||||
<Header sub>
|
||||
<FormattedMessage id="config.ids" defaultMessage="IDs" />
|
||||
</Header>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.ids.HIDE"
|
||||
defaultMessage="hide"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="hide"
|
||||
checked={props.config.id === Ids.HIDE}
|
||||
onClick={() => props.onChange({...props.config, id: Ids.HIDE})}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.ids.SHOW"
|
||||
defaultMessage="show"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="show"
|
||||
checked={props.config.id === Ids.SHOW}
|
||||
onClick={() => props.onChange({...props.config, id: Ids.SHOW})}
|
||||
/>
|
||||
</Form.Field>
|
||||
</Item.Content>
|
||||
</Item>
|
||||
<Item>
|
||||
<Item.Content>
|
||||
<Header sub>
|
||||
<FormattedMessage id="config.sex" defaultMessage="Sex" />
|
||||
</Header>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.sex.HIDE"
|
||||
defaultMessage="hide"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="hide"
|
||||
checked={props.config.sex === Sex.HIDE}
|
||||
onClick={() => props.onChange({...props.config, sex: Sex.HIDE})}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.sex.SHOW"
|
||||
defaultMessage="show"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="show"
|
||||
checked={props.config.sex === Sex.SHOW}
|
||||
onClick={() => props.onChange({...props.config, sex: Sex.SHOW})}
|
||||
/>
|
||||
</Form.Field>
|
||||
</Item.Content>
|
||||
</Item>
|
||||
</Item.Group>
|
||||
</Form>
|
||||
{SourceHead(props.gedcom)}
|
||||
<Form className="details">
|
||||
<Item.Group>
|
||||
<Item>
|
||||
<Item.Content>
|
||||
<Header sub>
|
||||
<FormattedMessage id="config.colors" defaultMessage="Colors" />
|
||||
</Header>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.colors.NO_COLOR"
|
||||
defaultMessage="none"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="none"
|
||||
checked={props.config.color === ChartColors.NO_COLOR}
|
||||
onClick={() =>
|
||||
props.onChange({
|
||||
...props.config,
|
||||
color: ChartColors.NO_COLOR,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.colors.COLOR_BY_GENERATION"
|
||||
defaultMessage="by generation"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="generation"
|
||||
checked={
|
||||
props.config.color === ChartColors.COLOR_BY_GENERATION
|
||||
}
|
||||
onClick={() =>
|
||||
props.onChange({
|
||||
...props.config,
|
||||
color: ChartColors.COLOR_BY_GENERATION,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.colors.COLOR_BY_SEX"
|
||||
defaultMessage="by sex"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="gender"
|
||||
checked={props.config.color === ChartColors.COLOR_BY_SEX}
|
||||
onClick={() =>
|
||||
props.onChange({
|
||||
...props.config,
|
||||
color: ChartColors.COLOR_BY_SEX,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Form.Field>
|
||||
</Item.Content>
|
||||
</Item>
|
||||
<Item>
|
||||
<Item.Content>
|
||||
<Header sub>
|
||||
<FormattedMessage id="config.ids" defaultMessage="IDs" />
|
||||
</Header>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.ids.HIDE"
|
||||
defaultMessage="hide"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="hide"
|
||||
checked={props.config.id === Ids.HIDE}
|
||||
onClick={() =>
|
||||
props.onChange({...props.config, id: Ids.HIDE})
|
||||
}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.ids.SHOW"
|
||||
defaultMessage="show"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="show"
|
||||
checked={props.config.id === Ids.SHOW}
|
||||
onClick={() =>
|
||||
props.onChange({...props.config, id: Ids.SHOW})
|
||||
}
|
||||
/>
|
||||
</Form.Field>
|
||||
</Item.Content>
|
||||
</Item>
|
||||
<Item>
|
||||
<Item.Content>
|
||||
<Header sub>
|
||||
<FormattedMessage id="config.sex" defaultMessage="Sex" />
|
||||
</Header>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.sex.HIDE"
|
||||
defaultMessage="hide"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="hide"
|
||||
checked={props.config.sex === Sex.HIDE}
|
||||
onClick={() =>
|
||||
props.onChange({...props.config, sex: Sex.HIDE})
|
||||
}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field className="no-margin">
|
||||
<Checkbox
|
||||
radio
|
||||
label={
|
||||
<FormattedMessage
|
||||
tagName="label"
|
||||
id="config.sex.SHOW"
|
||||
defaultMessage="show"
|
||||
/>
|
||||
}
|
||||
name="checkboxRadioGroup"
|
||||
value="show"
|
||||
checked={props.config.sex === Sex.SHOW}
|
||||
onClick={() =>
|
||||
props.onChange({...props.config, sex: Sex.SHOW})
|
||||
}
|
||||
/>
|
||||
</Form.Field>
|
||||
</Item.Content>
|
||||
</Item>
|
||||
</Item.Group>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ export function AdditionalFiles({files}: Props) {
|
||||
</a>
|
||||
</List.Header>
|
||||
<List.Description>
|
||||
{file.titl && <div>{file.titl}</div>}
|
||||
{file.titl && <div>{file.titl}</div>}
|
||||
</List.Description>
|
||||
</List.Content>
|
||||
</List.Item>
|
||||
|
||||
@@ -11,13 +11,13 @@ import {
|
||||
getNonImageFileEntry,
|
||||
mapToSource,
|
||||
} from '../../util/gedcom_util';
|
||||
import {FileEntry, AdditionalFiles} from './additional-files';
|
||||
import {Config, Ids} from '../config/config';
|
||||
import {AdditionalFiles, FileEntry} from './additional-files';
|
||||
import {ALL_SUPPORTED_EVENT_TYPES, Events} from './events';
|
||||
import {MultilineText} from './multiline-text';
|
||||
import {Sources} from './sources';
|
||||
import {TranslatedTag} from './translated-tag';
|
||||
import {WrappedImage} from './wrapped-image';
|
||||
import {Config, Ids} from '../config/config';
|
||||
|
||||
const EXCLUDED_TAGS = [
|
||||
...ALL_SUPPORTED_EVENT_TYPES,
|
||||
@@ -61,32 +61,30 @@ function attributeDetails(entry: GedcomEntry) {
|
||||
}
|
||||
|
||||
const attributeName = entry.tree
|
||||
.filter((subentry) => subentry.tag === 'TYPE')
|
||||
.flatMap((type) => getData(type))
|
||||
.join()
|
||||
.trim();
|
||||
.filter((subentry) => subentry.tag === 'TYPE')
|
||||
.flatMap((type) => getData(type))
|
||||
.join()
|
||||
.trim();
|
||||
|
||||
const attributeValue = getData(entry).join(' ').trim();
|
||||
if(attributeName) {
|
||||
if (attributeName) {
|
||||
return (
|
||||
<>
|
||||
<Header sub>
|
||||
<TranslatedTag tag={entry.tag}/>
|
||||
</Header>
|
||||
<div>
|
||||
<b>{attributeName}</b>: {attributeValue}
|
||||
</div>
|
||||
</>
|
||||
<>
|
||||
<Header sub>
|
||||
<TranslatedTag tag={entry.tag} />
|
||||
</Header>
|
||||
<div>
|
||||
<b>{attributeName}</b>: {attributeValue}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
<Header sub>
|
||||
<TranslatedTag tag={entry.tag}/>
|
||||
<TranslatedTag tag={entry.tag} />
|
||||
</Header>
|
||||
<div>
|
||||
{attributeValue}
|
||||
</div>
|
||||
<div>{attributeValue}</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -142,7 +140,9 @@ function sourceDetails(
|
||||
function fileDetails(objectEntries: GedcomEntry[], gedcom: GedcomData) {
|
||||
const files: FileEntry[] = [];
|
||||
objectEntries
|
||||
.map((objectEntry) => dereference(objectEntry, gedcom, (gedcom) => gedcom.other))
|
||||
.map((objectEntry) =>
|
||||
dereference(objectEntry, gedcom, (gedcom) => gedcom.other),
|
||||
)
|
||||
.forEach((objectEntry) => {
|
||||
const fileEntry = getNonImageFileEntry(objectEntry);
|
||||
if (fileEntry) {
|
||||
@@ -150,7 +150,7 @@ function fileDetails(objectEntries: GedcomEntry[], gedcom: GedcomData) {
|
||||
url: fileEntry.data,
|
||||
filename: getFileName(fileEntry),
|
||||
titl: objectEntry.tree.find((entry) => entry.tag === 'TITL')?.data,
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -314,14 +314,16 @@ function getOtherSections(entries: GedcomEntry[], gedcom: GedcomData) {
|
||||
));
|
||||
}
|
||||
|
||||
function getSectionForId(indi: string) : React.ReactNode {
|
||||
function getSectionForId(indi: string): React.ReactNode {
|
||||
return (
|
||||
<Item>
|
||||
<Item.Content>
|
||||
<Header sub>
|
||||
<FormattedMessage id="config.ids" defaultMessage="Identification" />
|
||||
</Header>
|
||||
<div><i>{indi}</i></div>
|
||||
<div>
|
||||
<i>{indi}</i>
|
||||
</div>
|
||||
</Item.Content>
|
||||
</Item>
|
||||
);
|
||||
@@ -354,10 +356,10 @@ export function Details(props: Props) {
|
||||
<Events gedcom={props.gedcom} entries={entries} indi={props.indi} />
|
||||
{props.config.id === Ids.SHOW ? getSectionForId(props.indi) : null}
|
||||
{getSectionForEachMatchingEntry(
|
||||
entries,
|
||||
props.gedcom,
|
||||
['FACT'],
|
||||
attributeDetails,
|
||||
entries,
|
||||
props.gedcom,
|
||||
['FACT'],
|
||||
attributeDetails,
|
||||
)}
|
||||
{getOtherSections(entries, props.gedcom)}
|
||||
{getSectionForEachMatchingEntry(
|
||||
|
||||
@@ -11,8 +11,17 @@ interface Props {
|
||||
export function LinkifyNewTab({children}: Props) {
|
||||
return (
|
||||
<Linkify
|
||||
componentDecorator={(decoratedHref: string, decoratedText: string, key: number) => (
|
||||
<a href={decoratedHref} key={key} target="_blank" rel="noopener noreferrer">
|
||||
componentDecorator={(
|
||||
decoratedHref: string,
|
||||
decoratedText: string,
|
||||
key: number,
|
||||
) => (
|
||||
<a
|
||||
href={decoratedHref}
|
||||
key={key}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{decoratedText}
|
||||
</a>
|
||||
)}
|
||||
|
||||
@@ -1,108 +1,128 @@
|
||||
import {
|
||||
dereference,
|
||||
GedcomData,
|
||||
} from '../../util/gedcom_util';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {Header, Divider, List} from 'semantic-ui-react';
|
||||
import {Divider, Header, List} from 'semantic-ui-react';
|
||||
import {getDate} from 'topola';
|
||||
import {formatDateOrRange} from '../../util/date_util';
|
||||
import {dereference, GedcomData} from '../../util/gedcom_util';
|
||||
|
||||
export function SourceHead(gedcom: GedcomData){
|
||||
export function SourceHead(gedcom: GedcomData) {
|
||||
const head = gedcom.head;
|
||||
/* Don't show the section if there is no relevant information */
|
||||
if (!head || !head.tree) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const sour = head.tree.find((entry) => entry.tag === 'SOUR');
|
||||
const sour_name = sour && sour.tree && sour.tree.find((entry) => entry.tag === 'NAME')?.data; // Software name
|
||||
const sour_name =
|
||||
sour && sour.tree && sour.tree.find((entry) => entry.tag === 'NAME')?.data; // Software name
|
||||
|
||||
const date = head.tree.find((entry) => entry.tag === 'DATE'); // Creation date
|
||||
const intl = useIntl();
|
||||
const dateFormatted = date ? formatDateOrRange(getDate(date.data), intl) : null; // Formatted creation date
|
||||
const dateFormatted = date
|
||||
? formatDateOrRange(getDate(date.data), intl)
|
||||
: null; // Formatted creation date
|
||||
|
||||
const file = head.tree.find((entry) => entry.tag === 'FILE')?.data; // File path
|
||||
const filename = file && ( file.split('\\').pop() || file.split('/').pop() ); // Extract file name from path
|
||||
const filename = file && (file.split('\\').pop() || file.split('/').pop()); // Extract file name from path
|
||||
const copr = head.tree.find((entry) => entry.tag === 'COPR')?.data; // Copyright
|
||||
|
||||
// Reference to submitter
|
||||
const submReference = head.tree.find((entry) => entry.tag === 'SUBM');
|
||||
const subm = submReference && dereference(submReference, gedcom, (gedcom) => gedcom.other);
|
||||
const subm =
|
||||
submReference &&
|
||||
dereference(submReference, gedcom, (gedcom) => gedcom.other);
|
||||
|
||||
const name = subm && subm.tree && subm.tree.find((entry) => entry.tag === 'NAME')?.data; // Submitter name
|
||||
const phon = subm && subm.tree && subm.tree.find((entry) => entry.tag === 'PHON')?.data; // Phone number
|
||||
const email = subm && subm.tree && subm.tree.find((entry) => entry.tag === 'EMAIL')?.data; // Email
|
||||
const name =
|
||||
subm && subm.tree && subm.tree.find((entry) => entry.tag === 'NAME')?.data; // Submitter name
|
||||
const phon =
|
||||
subm && subm.tree && subm.tree.find((entry) => entry.tag === 'PHON')?.data; // Phone number
|
||||
const email =
|
||||
subm && subm.tree && subm.tree.find((entry) => entry.tag === 'EMAIL')?.data; // Email
|
||||
|
||||
const addr = subm && subm.tree && subm.tree.find((entry) => entry.tag === 'ADDR'); // Address
|
||||
const adr1 = addr && addr.tree && addr.tree.find((entry) => entry.tag === 'ADR1')?.data; // Street address
|
||||
const city = addr && addr.tree && addr.tree.find((entry) => entry.tag === 'CITY')?.data; // City
|
||||
const post = addr && addr.tree && addr.tree.find((entry) => entry.tag === 'POST')?.data; // Postal code
|
||||
const addr =
|
||||
subm && subm.tree && subm.tree.find((entry) => entry.tag === 'ADDR'); // Address
|
||||
const adr1 =
|
||||
addr && addr.tree && addr.tree.find((entry) => entry.tag === 'ADR1')?.data; // Street address
|
||||
const city =
|
||||
addr && addr.tree && addr.tree.find((entry) => entry.tag === 'CITY')?.data; // City
|
||||
const post =
|
||||
addr && addr.tree && addr.tree.find((entry) => entry.tag === 'POST')?.data; // Postal code
|
||||
const location = [adr1, post, city].filter(Boolean).join(', '); // Combined location
|
||||
|
||||
/* Don't show the section if there is no relevant information */
|
||||
if (!(sour_name || dateFormatted || filename || copr || name || phon || email || location)) {
|
||||
if (
|
||||
!(
|
||||
sour_name ||
|
||||
dateFormatted ||
|
||||
filename ||
|
||||
copr ||
|
||||
name ||
|
||||
phon ||
|
||||
email ||
|
||||
location
|
||||
)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Icons: https://react.semantic-ui.com/elements/icon/
|
||||
return (
|
||||
<>
|
||||
return (
|
||||
<>
|
||||
<Header sub>
|
||||
<FormattedMessage id="head.source" defaultMessage="Data source" />
|
||||
</Header>
|
||||
<List>
|
||||
{sour_name && (
|
||||
{sour_name && (
|
||||
<List.Item>
|
||||
<List.Icon name='edit' />
|
||||
<List.Icon name="edit" />
|
||||
<List.Content>{sour_name}</List.Content>
|
||||
</List.Item>
|
||||
)}
|
||||
|
||||
|
||||
{date && (
|
||||
<List.Item>
|
||||
<List.Icon name='calendar' />
|
||||
<List.Icon name="calendar" />
|
||||
<List.Content>{dateFormatted}</List.Content>
|
||||
</List.Item>
|
||||
)}
|
||||
{file && (
|
||||
<List.Item>
|
||||
<List.Icon name='file' />
|
||||
<List.Icon name="file" />
|
||||
<List.Content>{filename}</List.Content>
|
||||
</List.Item>
|
||||
)}
|
||||
{name && (
|
||||
<List.Item>
|
||||
<List.Icon name='user' />
|
||||
<List.Icon name="user" />
|
||||
<List.Content>{name}</List.Content>
|
||||
</List.Item>
|
||||
)}
|
||||
{adr1 && (
|
||||
<List.Item>
|
||||
<List.Icon name='marker' />
|
||||
<List.Icon name="marker" />
|
||||
<List.Content>{location}</List.Content>
|
||||
</List.Item>
|
||||
)}
|
||||
{phon && (
|
||||
{phon && (
|
||||
<List.Item>
|
||||
<List.Icon name='phone' />
|
||||
<List.Icon name="phone" />
|
||||
<List.Content>{phon}</List.Content>
|
||||
</List.Item>
|
||||
)}
|
||||
{email && (
|
||||
<List.Item>
|
||||
<List.Icon name='mail' />
|
||||
<List.Icon name="mail" />
|
||||
<List.Content>{email}</List.Content>
|
||||
</List.Item>
|
||||
)}
|
||||
{copr && (
|
||||
<List.Item>
|
||||
<List.Icon name='copyright' />
|
||||
<List.Icon name="copyright" />
|
||||
<List.Content>{copr}</List.Content>
|
||||
</List.Item>
|
||||
)}
|
||||
</List>
|
||||
|
||||
<Divider />
|
||||
</>
|
||||
);
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user