aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2021-06-26 19:13:19 +0800
committercrupest <crupest@outlook.com>2021-06-26 19:13:19 +0800
commita168336c0761b263ee5371218cbf6da236c0acce (patch)
treefbd965f152c1129cd4692e73112c2557e755cddb /FrontEnd
parentb468fd9a0119b97d1ecc1090a028975e917aa75f (diff)
downloadtimeline-a168336c0761b263ee5371218cbf6da236c0acce.tar.gz
timeline-a168336c0761b263ee5371218cbf6da236c0acce.tar.bz2
timeline-a168336c0761b263ee5371218cbf6da236c0acce.zip
...
Diffstat (limited to 'FrontEnd')
-rw-r--r--FrontEnd/src/views/admin/UserAdmin.tsx9
-rw-r--r--FrontEnd/src/views/common/Menu.tsx26
-rw-r--r--FrontEnd/src/views/common/SearchInput.tsx13
-rw-r--r--FrontEnd/src/views/common/Spinner.tsx13
-rw-r--r--FrontEnd/src/views/common/TabPages.tsx20
-rw-r--r--FrontEnd/src/views/common/alert/AlertHost.tsx11
-rw-r--r--FrontEnd/src/views/common/button/LoadingButton.tsx23
-rw-r--r--FrontEnd/src/views/common/dailog/OperationDialog.tsx71
-rw-r--r--FrontEnd/src/views/login/index.tsx114
-rw-r--r--FrontEnd/src/views/timeline-common/MarkdownPostEdit.tsx8
-rw-r--r--FrontEnd/src/views/timeline-common/TimelineMember.tsx21
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx1
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePostDeleteConfirmDialog.tsx40
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx1
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePostView.tsx6
15 files changed, 142 insertions, 235 deletions
diff --git a/FrontEnd/src/views/admin/UserAdmin.tsx b/FrontEnd/src/views/admin/UserAdmin.tsx
index 125219c3..481db1cc 100644
--- a/FrontEnd/src/views/admin/UserAdmin.tsx
+++ b/FrontEnd/src/views/admin/UserAdmin.tsx
@@ -15,6 +15,7 @@ import {
import { Trans, useTranslation } from "react-i18next";
import Button from "../common/button/Button";
import TextButton from "../common/button/TextButton";
+import Spinner from "../common/Spinner";
interface DialogProps<TData = undefined, TReturn = undefined> {
open: boolean;
@@ -203,7 +204,7 @@ const UserItem: React.FC<UserItemProps> = ({ user, on }) => {
const [editMaskVisible, setEditMaskVisible] = React.useState<boolean>(false);
return (
- <ListGroup.Item className="admin-user-item">
+ <div className="admin-user-item">
<i
className="bi-pencil-square float-end icon-button text-warning"
onClick={() => setEditMaskVisible(true)}
@@ -242,7 +243,7 @@ const UserItem: React.FC<UserItemProps> = ({ user, on }) => {
onClick={on[kDelete]}
/>
</div>
- </ListGroup.Item>
+ </div>
);
};
@@ -251,8 +252,6 @@ interface UserAdminProps {
}
const UserAdmin: React.FC<UserAdminProps> = () => {
- const { t } = useTranslation();
-
type DialogInfo =
| null
| {
@@ -390,7 +389,7 @@ const UserAdmin: React.FC<UserAdminProps> = () => {
</>
);
} else {
- return <Spinner animation="border" />;
+ return <Spinner />;
}
};
diff --git a/FrontEnd/src/views/common/Menu.tsx b/FrontEnd/src/views/common/Menu.tsx
index ae73a331..a5d2ec2c 100644
--- a/FrontEnd/src/views/common/Menu.tsx
+++ b/FrontEnd/src/views/common/Menu.tsx
@@ -1,9 +1,9 @@
import React from "react";
import classnames from "classnames";
-import { OverlayTrigger, OverlayTriggerProps, Popover } from "react-bootstrap";
import { useTranslation } from "react-i18next";
-import { BootstrapThemeColor, convertI18nText, I18nText } from "@/common";
+import { convertI18nText, I18nText } from "@/common";
+import { PaletteColorType } from "@/palette";
export type MenuItem =
| {
@@ -13,7 +13,7 @@ export type MenuItem =
type: "button";
text: I18nText;
iconClassName?: string;
- color?: BootstrapThemeColor;
+ color?: PaletteColorType;
onClick: () => void;
};
@@ -67,26 +67,14 @@ export default Menu;
export interface PopupMenuProps {
items: MenuItems;
- children: OverlayTriggerProps["children"];
+ children: React.ReactElement;
}
export const PopupMenu: React.FC<PopupMenuProps> = ({ items, children }) => {
const [show, setShow] = React.useState<boolean>(false);
const toggle = (): void => setShow(!show);
- return (
- <OverlayTrigger
- trigger="click"
- rootClose
- overlay={
- <Popover id="menu-popover">
- <Menu items={items} onItemClicked={() => setShow(false)} />
- </Popover>
- }
- show={show}
- onToggle={toggle}
- >
- {children}
- </OverlayTrigger>
- );
+ // TODO:
+
+ return <Menu items={items} onItemClicked={() => setShow(false)} />;
};
diff --git a/FrontEnd/src/views/common/SearchInput.tsx b/FrontEnd/src/views/common/SearchInput.tsx
index 79eb2732..fff11b95 100644
--- a/FrontEnd/src/views/common/SearchInput.tsx
+++ b/FrontEnd/src/views/common/SearchInput.tsx
@@ -1,7 +1,8 @@
import React, { useCallback } from "react";
import classnames from "classnames";
import { useTranslation } from "react-i18next";
-import { Spinner, Form, Button } from "react-bootstrap";
+
+import LoadingButton from "./button/LoadingButton";
export interface SearchInputProps {
value: string;
@@ -64,13 +65,9 @@ const SearchInput: React.FC<SearchInputProps> = (props) => {
"flex-shrink-0"
)}
>
- {props.loading ? (
- <Spinner variant="primary" animation="border" />
- ) : (
- <Button variant="outline-primary" onClick={props.onButtonClick}>
- {props.buttonText ?? t("search")}
- </Button>
- )}
+ <LoadingButton loading={props.loading} onClick={props.onButtonClick}>
+ {props.buttonText ?? t("search")}
+ </LoadingButton>
</div>
</div>
);
diff --git a/FrontEnd/src/views/common/Spinner.tsx b/FrontEnd/src/views/common/Spinner.tsx
new file mode 100644
index 00000000..783c9be2
--- /dev/null
+++ b/FrontEnd/src/views/common/Spinner.tsx
@@ -0,0 +1,13 @@
+import { PaletteColorType } from "@/palette";
+import React from "react";
+
+export interface SpinnerProps {
+ size?: "sm" | "md" | "lg" | number;
+ color?: PaletteColorType;
+}
+
+export default function Spinner(
+ props: SpinnerProps
+): React.ReactElement | null {
+ return <span />;
+}
diff --git a/FrontEnd/src/views/common/TabPages.tsx b/FrontEnd/src/views/common/TabPages.tsx
index 2b1d91cb..b7a9fb36 100644
--- a/FrontEnd/src/views/common/TabPages.tsx
+++ b/FrontEnd/src/views/common/TabPages.tsx
@@ -1,5 +1,4 @@
import React from "react";
-import { Nav } from "react-bootstrap";
import { useTranslation } from "react-i18next";
import { convertI18nText, I18nText, UiLogicError } from "@/common";
@@ -31,6 +30,8 @@ const TabPages: React.FC<TabPagesProps> = ({
pageContainerClassName,
pageContainerStyle,
}) => {
+ // TODO:
+
if (pages.length === 0) {
throw new UiLogicError("Page list can't be empty.");
}
@@ -47,23 +48,6 @@ const TabPages: React.FC<TabPagesProps> = ({
return (
<div className={className} style={style}>
- <Nav variant="tabs" className={navClassName} style={navStyle}>
- {pages.map((page) => (
- <Nav.Item key={page.id}>
- <Nav.Link
- active={tab === page.id}
- onClick={() => {
- setTab(page.id);
- }}
- >
- {convertI18nText(page.tabText, t)}
- </Nav.Link>
- </Nav.Item>
- ))}
- {actions != null && (
- <div className="ms-auto cru-tab-pages-action-area">{actions}</div>
- )}
- </Nav>
<div className={pageContainerClassName} style={pageContainerStyle}>
{currentPage.page}
</div>
diff --git a/FrontEnd/src/views/common/alert/AlertHost.tsx b/FrontEnd/src/views/common/alert/AlertHost.tsx
index 949be7ed..21b9882d 100644
--- a/FrontEnd/src/views/common/alert/AlertHost.tsx
+++ b/FrontEnd/src/views/common/alert/AlertHost.tsx
@@ -1,7 +1,6 @@
import React from "react";
import without from "lodash/without";
import { useTranslation } from "react-i18next";
-import { Alert } from "react-bootstrap";
import {
alertService,
@@ -52,13 +51,7 @@ export const AutoCloseAlert: React.FC<AutoCloseAlertProps> = (props) => {
};
return (
- <Alert
- className="m-3"
- variant={alert.type ?? "primary"}
- onClick={cancelTimer}
- onClose={close}
- dismissible
- >
+ <div className="m-3" onClick={cancelTimer}>
{(() => {
const { message } = alert;
if (typeof message === "function") {
@@ -66,7 +59,7 @@ export const AutoCloseAlert: React.FC<AutoCloseAlertProps> = (props) => {
return <Message />;
} else return convertI18nText(message, t);
})()}
- </Alert>
+ </div>
);
};
diff --git a/FrontEnd/src/views/common/button/LoadingButton.tsx b/FrontEnd/src/views/common/button/LoadingButton.tsx
index fd1c19b3..aee83aa2 100644
--- a/FrontEnd/src/views/common/button/LoadingButton.tsx
+++ b/FrontEnd/src/views/common/button/LoadingButton.tsx
@@ -1,26 +1,19 @@
import React from "react";
-const LoadingButton: React.FC<{ loading?: boolean } & ButtonProps> = ({
+import { CommonButtonProps } from "./common";
+import Button from "./Button";
+import Spinner from "../Spinner";
+
+const LoadingButton: React.FC<{ loading?: boolean } & CommonButtonProps> = ({
loading,
- variant,
disabled,
+ color,
...otherProps
}) => {
return (
- <Button
- variant={variant != null ? `outline-${variant}` : "outline-primary"}
- disabled={disabled || loading}
- {...otherProps}
- >
+ <Button color={color} disabled={disabled || loading} {...otherProps}>
{otherProps.children}
- {loading ? (
- <Spinner
- className="ms-1"
- variant={variant}
- animation="grow"
- size="sm"
- />
- ) : null}
+ {loading ? <Spinner color={color} /> : null}
</Button>
);
};
diff --git a/FrontEnd/src/views/common/dailog/OperationDialog.tsx b/FrontEnd/src/views/common/dailog/OperationDialog.tsx
index 129e85d5..1e765276 100644
--- a/FrontEnd/src/views/common/dailog/OperationDialog.tsx
+++ b/FrontEnd/src/views/common/dailog/OperationDialog.tsx
@@ -5,6 +5,8 @@ import moment from "moment";
import { convertI18nText, I18nText, UiLogicError } from "@/common";
+import { PaletteColorType } from "@/palette";
+
import Button from "../button/Button";
import LoadingButton from "../button/LoadingButton";
import Dialog from "./Dialog";
@@ -144,7 +146,7 @@ export interface OperationDialogProps<
open: boolean;
onClose: () => void;
title: I18nText | (() => React.ReactNode);
- themeColor?: "danger" | "success" | string;
+ themeColor?: PaletteColorType;
onProcess: (
inputs: MapOperationInputInfoValueTypeList<OperationInputInfoList>
) => Promise<TData>;
@@ -290,50 +292,42 @@ const OperationDialog = <
if (item.type === "text") {
return (
- <Form.Group key={index}>
+ <div key={index}>
{item.label && (
- <Form.Label>{convertI18nText(item.label, t)}</Form.Label>
+ <label>{convertI18nText(item.label, t)}</label>
)}
- <Form.Control
+ <input
type={item.password === true ? "password" : "text"}
value={value as string}
onChange={(e) => {
const v = e.target.value;
updateValue(index, v);
}}
- isInvalid={error != null}
disabled={process}
/>
- {error != null && (
- <Form.Control.Feedback type="invalid">
- {error}
- </Form.Control.Feedback>
- )}
- {item.helperText && (
- <Form.Text>{t(item.helperText)}</Form.Text>
- )}
- </Form.Group>
+ {error != null && <div>{error}</div>}
+ {item.helperText && <div>{t(item.helperText)}</div>}
+ </div>
);
} else if (item.type === "bool") {
return (
- <Form.Group key={index}>
- <Form.Check<"input">
+ <div key={index}>
+ <input
type="checkbox"
checked={value as boolean}
onChange={(event) => {
updateValue(index, event.currentTarget.checked);
}}
- label={convertI18nText(item.label, t)}
disabled={process}
/>
- </Form.Group>
+ <label>{convertI18nText(item.label, t)}</label>
+ </div>
);
} else if (item.type === "select") {
return (
- <Form.Group key={index}>
- <Form.Label>{convertI18nText(item.label, t)}</Form.Label>
- <Form.Control
- as="select"
+ <div key={index}>
+ <label>{convertI18nText(item.label, t)}</label>
+ <select
value={value as string}
onChange={(event) => {
updateValue(index, event.target.value);
@@ -348,14 +342,14 @@ const OperationDialog = <
</option>
);
})}
- </Form.Control>
- </Form.Group>
+ </select>
+ </div>
);
} else if (item.type === "color") {
return (
- <Form.Group key={index}>
+ <div key={index}>
{item.canBeNull ? (
- <Form.Check<"input">
+ <input
type="checkbox"
checked={value !== null}
onChange={(event) => {
@@ -365,42 +359,35 @@ const OperationDialog = <
updateValue(index, null);
}
}}
- label={convertI18nText(item.label, t)}
disabled={process}
/>
- ) : (
- <Form.Label>{convertI18nText(item.label, t)}</Form.Label>
- )}
+ ) : null}
+ <label>{convertI18nText(item.label, t)}</label>
{value !== null && (
<TwitterPicker
color={value as string}
onChange={(result) => updateValue(index, result.hex)}
/>
)}
- </Form.Group>
+ </div>
);
} else if (item.type === "datetime") {
return (
- <Form.Group key={index}>
+ <div key={index}>
{item.label && (
- <Form.Label>{convertI18nText(item.label, t)}</Form.Label>
+ <label>{convertI18nText(item.label, t)}</label>
)}
- <Form.Control
+ <input
type="datetime-local"
value={value as string}
onChange={(e) => {
const v = e.target.value;
updateValue(index, v);
}}
- isInvalid={error != null}
disabled={process}
/>
- {error != null && (
- <Form.Control.Feedback type="invalid">
- {error}
- </Form.Control.Feedback>
- )}
- </Form.Group>
+ {error != null && <div>{error}</div>}
+ </div>
);
}
})}
@@ -412,7 +399,7 @@ const OperationDialog = <
onClick={close}
/>
<LoadingButton
- variant={props.themeColor}
+ color={props.themeColor}
loading={process}
disabled={!canProcess}
onClick={() => {
diff --git a/FrontEnd/src/views/login/index.tsx b/FrontEnd/src/views/login/index.tsx
index 6c0aaf67..6d70c64a 100644
--- a/FrontEnd/src/views/login/index.tsx
+++ b/FrontEnd/src/views/login/index.tsx
@@ -81,67 +81,59 @@ const LoginPage: React.FC = (_) => {
<div className="login-container container-fluid mt-2">
<h1 className="text-center">{t("welcome")}</h1>
<div>
- <Form.Label htmlFor="username">{t("user.username")}</Form.Label>
- <Form.Control
- id="username"
- disabled={process}
- onChange={(e) => {
- setUsername(e.target.value);
- setUsernameDirty(true);
- }}
- value={username}
- isInvalid={usernameDirty && username === ""}
- />
- {usernameDirty && username === "" && (
- <Form.Control.Feedback type="invalid">
- {t("login.emptyUsername")}
- </Form.Control.Feedback>
- )}
- <Form.Label htmlFor="password">{t("user.password")}</Form.Label>
- <Form.Control
- id="password"
- type="password"
- disabled={process}
- onChange={(e) => {
- setPassword(e.target.value);
- setPasswordDirty(true);
- }}
- value={password}
- onKeyDown={onEnterPressInPassword}
- isInvalid={passwordDirty && password === ""}
- />
- {passwordDirty && password === "" && (
- <Form.Control.Feedback type="invalid">
- {t("login.emptyPassword")}
- </Form.Control.Feedback>
- )}
- </Form.Group>
- <Form.Group>
- <Form.Check<"input">
- id="remember-me"
- type="checkbox"
- checked={rememberMe}
- onChange={(e) => {
- setRememberMe(e.currentTarget.checked);
- }}
- label={t("user.rememberMe")}
- />
- </Form.Group>
- {error ? <p className="text-danger">{t(error)}</p> : null}
- <div className="text-end">
- <LoadingButton
- loading={process}
- variant="primary"
- onClick={(e) => {
- submit();
- e.preventDefault();
- }}
- disabled={username === "" || password === "" ? true : undefined}
- >
- {t("user.login")}
- </LoadingButton>
- </div>
- </Form>
+ <label htmlFor="username">{t("user.username")}</label>
+ <input
+ id="username"
+ disabled={process}
+ onChange={(e) => {
+ setUsername(e.target.value);
+ setUsernameDirty(true);
+ }}
+ value={username}
+ />
+ {usernameDirty && username === "" && (
+ <div>{t("login.emptyUsername")}</div>
+ )}
+ <label htmlFor="password">{t("user.password")}</label>
+ <input
+ id="password"
+ type="password"
+ disabled={process}
+ onChange={(e) => {
+ setPassword(e.target.value);
+ setPasswordDirty(true);
+ }}
+ value={password}
+ onKeyDown={onEnterPressInPassword}
+ />
+ {passwordDirty && password === "" && (
+ <div>{t("login.emptyPassword")}</div>
+ )}
+ </div>
+ <div>
+ <input
+ id="remember-me"
+ type="checkbox"
+ checked={rememberMe}
+ onChange={(e) => {
+ setRememberMe(e.currentTarget.checked);
+ }}
+ />
+ <label>{t("user.rememberMe")}</label>
+ </div>
+ {error ? <p className="text-danger">{t(error)}</p> : null}
+ <div className="text-end">
+ <LoadingButton
+ loading={process}
+ onClick={(e) => {
+ submit();
+ e.preventDefault();
+ }}
+ disabled={username === "" || password === "" ? true : undefined}
+ >
+ {t("user.login")}
+ </LoadingButton>
+ </div>
</div>
);
};
diff --git a/FrontEnd/src/views/timeline-common/MarkdownPostEdit.tsx b/FrontEnd/src/views/timeline-common/MarkdownPostEdit.tsx
index 6cb64dd3..9f0753b9 100644
--- a/FrontEnd/src/views/timeline-common/MarkdownPostEdit.tsx
+++ b/FrontEnd/src/views/timeline-common/MarkdownPostEdit.tsx
@@ -1,15 +1,17 @@
+/* eslint-disable react/jsx-no-undef */
import React from "react";
import classnames from "classnames";
-import { Form, Spinner } from "react-bootstrap";
import { useTranslation } from "react-i18next";
import { Prompt } from "react-router";
import { getHttpTimelineClient, HttpTimelinePostInfo } from "@/http/timeline";
+import TimelinePostBuilder from "@/services/TimelinePostBuilder";
+
import FlatButton from "../common/button/FlatButton";
import TabPages from "../common/TabPages";
-import TimelinePostBuilder from "@/services/TimelinePostBuilder";
import ConfirmDialog from "../common/dailog/ConfirmDialog";
+import Spinner from "../common/Spinner";
export interface MarkdownPostEditProps {
timeline: string;
@@ -102,7 +104,7 @@ const MarkdownPostEdit: React.FC<MarkdownPostEditProps> = ({
pageContainerClassName="py-2"
actions={
process ? (
- <Spinner variant="primary" animation="border" size="sm" />
+ <Spinner />
) : (
<>
<FlatButton
diff --git a/FrontEnd/src/views/timeline-common/TimelineMember.tsx b/FrontEnd/src/views/timeline-common/TimelineMember.tsx
index 830ecd45..c8f26da7 100644
--- a/FrontEnd/src/views/timeline-common/TimelineMember.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelineMember.tsx
@@ -5,21 +5,20 @@ import { convertI18nText, I18nText } from "@/common";
import { HttpUser } from "@/http/user";
import { getHttpSearchClient } from "@/http/search";
+import { getHttpTimelineClient, HttpTimelineInfo } from "@/http/timeline";
import SearchInput from "../common/SearchInput";
import UserAvatar from "../common/user/UserAvatar";
-import { getHttpTimelineClient, HttpTimelineInfo } from "@/http/timeline";
import Button from "../common/button/Button";
+import Dialog from "../common/dailog/Dialog";
const TimelineMemberItem: React.FC<{
user: HttpUser;
add?: boolean;
onAction?: (username: string) => void;
}> = ({ user, add, onAction }) => {
- const { t } = useTranslation();
-
return (
- <ListGroup.Item className="container">
+ <div className="container">
<div className="row">
<div className="col col-auto">
<UserAvatar username={user.username} className="avatar small" />
@@ -42,7 +41,7 @@ const TimelineMemberItem: React.FC<{
</div>
) : null}
</div>
- </ListGroup.Item>
+ </div>
);
};
@@ -109,7 +108,7 @@ const TimelineMemberUserSearch: React.FC<{
return <div>{t("timeline.member.noUserAvailableToAdd")}</div>;
} else {
return (
- <ListGroup className="mt-2">
+ <div className="mt-2">
{users.map((user) => (
<TimelineMemberItem
key={user.username}
@@ -126,7 +125,7 @@ const TimelineMemberUserSearch: React.FC<{
}}
/>
))}
- </ListGroup>
+ </div>
);
}
} else if (userSearchState.type === "error") {
@@ -152,7 +151,7 @@ const TimelineMember: React.FC<TimelineMemberProps> = (props) => {
return (
<div className="container px-4 py-3">
- <ListGroup>
+ <div>
{members.map((member, index) => (
<TimelineMemberItem
key={member.username}
@@ -168,7 +167,7 @@ const TimelineMember: React.FC<TimelineMemberProps> = (props) => {
}
/>
))}
- </ListGroup>
+ </div>
{timeline.manageable ? (
<TimelineMemberUserSearch timeline={timeline} onChange={onChange} />
) : null}
@@ -187,8 +186,8 @@ export const TimelineMemberDialog: React.FC<TimelineMemberDialogProps> = (
props
) => {
return (
- <Modal show centered onHide={props.onClose}>
+ <Dialog open onClose={props.onClose}>
<TimelineMember {...props} />
- </Modal>
+ </Dialog>
);
};
diff --git a/FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx b/FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx
index d05f18d4..ea6e8d40 100644
--- a/FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx
@@ -1,5 +1,4 @@
import React from "react";
-import { Container } from "react-bootstrap";
import { HubConnectionState } from "@microsoft/signalr";
import { HttpTimelineInfo } from "@/http/timeline";
diff --git a/FrontEnd/src/views/timeline-common/TimelinePostDeleteConfirmDialog.tsx b/FrontEnd/src/views/timeline-common/TimelinePostDeleteConfirmDialog.tsx
deleted file mode 100644
index e04bb7e1..00000000
--- a/FrontEnd/src/views/timeline-common/TimelinePostDeleteConfirmDialog.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import React from "react";
-import { useTranslation } from "react-i18next";
-
-import Button from "../common/button/Button";
-
-const TimelinePostDeleteConfirmDialog: React.FC<{
- onClose: () => void;
- onConfirm: () => void;
-}> = ({ onClose, onConfirm }) => {
- const { t } = useTranslation();
-
- return (
- <Modal onHide={onClose} show centered>
- <Modal.Header>
- <Modal.Title className="text-danger">
- {t("timeline.post.deleteDialog.title")}
- </Modal.Title>
- </Modal.Header>
- <Modal.Body>{t("timeline.post.deleteDialog.prompt")}</Modal.Body>
- <Modal.Footer>
- <Button
- text="operationDialog.cancel"
- color="secondary"
- onClick={onClose}
- />
- <Button
- variant="danger"
- onClick={() => {
- onConfirm();
- onClose();
- }}
- >
- {t("operationDialog.confirm")}
- </Button>
- </Modal.Footer>
- </Modal>
- );
-};
-
-export default TimelinePostDeleteConfirmDialog;
diff --git a/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx b/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx
index 5e59bee4..13aacb54 100644
--- a/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx
@@ -265,7 +265,6 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => {
</PopupMenu>
</div>
<LoadingButton
- variant="primary"
onClick={onSend}
disabled={!canSend}
loading={process}
diff --git a/FrontEnd/src/views/timeline-common/TimelinePostView.tsx b/FrontEnd/src/views/timeline-common/TimelinePostView.tsx
index 7b16e898..995c43df 100644
--- a/FrontEnd/src/views/timeline-common/TimelinePostView.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelinePostView.tsx
@@ -9,9 +9,9 @@ import { pushAlert } from "@/services/alert";
import UserAvatar from "../common/user/UserAvatar";
import Card from "../common/Card";
import FlatButton from "../common/button/FlatButton";
+import ConfirmDialog from "../common/dailog/ConfirmDialog";
import TimelineLine from "./TimelineLine";
import TimelinePostContentView from "./TimelinePostContentView";
-import TimelinePostDeleteConfirmDialog from "./TimelinePostDeleteConfirmDialog";
import PostPropertyChangeDialog from "./PostPropertyChangeDialog";
export interface TimelinePostViewProps {
@@ -116,7 +116,9 @@ const TimelinePostView: React.FC<TimelinePostViewProps> = (props) => {
) : null}
</Card>
{dialog === "delete" ? (
- <TimelinePostDeleteConfirmDialog
+ <ConfirmDialog
+ title="timeline.post.deleteDialog.title"
+ body="timeline.post.deleteDialog.prompt"
onClose={() => {
setDialog(null);
setOperationMaskVisible(false);