mirror of
https://github.com/wassname/talk.git
synced 2026-09-09 11:38:08 +08:00
add react hooks eslint plugin (#3059)
* add eslint react hooks * fix code breaking the rules-of-hooks eslint rule * fix spinnerWhileRendering for tests Co-authored-by: Wyatt Johnson <wyattjoh@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
Wyatt Johnson
kodiakhq[bot]
parent
9d02391062
commit
0f1dd7d707
@@ -21,10 +21,6 @@ interface Props {
|
||||
}
|
||||
|
||||
const UserStatusDetailsContainer: FunctionComponent<Props> = ({ user }) => {
|
||||
if (!user.status.ban.active && !user.status.suspension.active) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const activeBan = useMemo(() => {
|
||||
return user.status.ban.history.find((item) => item.active);
|
||||
}, [user]);
|
||||
@@ -41,6 +37,10 @@ const UserStatusDetailsContainer: FunctionComponent<Props> = ({ user }) => {
|
||||
minute: "2-digit",
|
||||
});
|
||||
|
||||
if (!user.status.ban.active && !user.status.suspension.active) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Popover
|
||||
|
||||
@@ -17,20 +17,23 @@ interface Props {
|
||||
}
|
||||
|
||||
const AddSiteRoute: FunctionComponent<Props> = ({ data }) => {
|
||||
const { setMessage, clearMessage } = useNotification();
|
||||
const onSiteEdit = useCallback(
|
||||
(name: string) => {
|
||||
setMessage(
|
||||
<Localized id="configure-sites-edit-success" $site={name}>
|
||||
<AppNotification icon="check_circle_outline" onClose={clearMessage}>
|
||||
Changes to {name} have been saved
|
||||
</AppNotification>
|
||||
</Localized>
|
||||
);
|
||||
},
|
||||
[setMessage, clearMessage]
|
||||
);
|
||||
if (!data || !data.site) {
|
||||
return null;
|
||||
}
|
||||
const { site } = data;
|
||||
const { setMessage, clearMessage } = useNotification();
|
||||
const onSiteEdit = useCallback((name: string) => {
|
||||
setMessage(
|
||||
<Localized id="configure-sites-edit-success" $site={name}>
|
||||
<AppNotification icon="check_circle_outline" onClose={clearMessage}>
|
||||
Changes to {name} have been saved
|
||||
</AppNotification>
|
||||
</Localized>
|
||||
);
|
||||
}, []);
|
||||
return (
|
||||
<ConfigBox
|
||||
title={
|
||||
|
||||
@@ -38,13 +38,6 @@ interface Props {
|
||||
site?: Site | null;
|
||||
}
|
||||
const DashboardContainer: React.FunctionComponent<Props> = (props) => {
|
||||
if (!props.site) {
|
||||
return null;
|
||||
}
|
||||
const sites = props.query
|
||||
? props.query.sites.edges.map((edge) => edge.node)
|
||||
: [];
|
||||
|
||||
const [lastUpdated, setLastUpdated] = useState<string>(new Date().toString());
|
||||
const [loadMore, isLoadingMore] = useLoadMore(props.relay, 10);
|
||||
const [, isRefetching] = useRefetch<
|
||||
@@ -53,6 +46,12 @@ const DashboardContainer: React.FunctionComponent<Props> = (props) => {
|
||||
const onRefetch = useCallback(() => {
|
||||
setLastUpdated(new Date().toString());
|
||||
}, []);
|
||||
if (!props.site) {
|
||||
return null;
|
||||
}
|
||||
const sites = props.query
|
||||
? props.query.sites.edges.map((edge) => edge.node)
|
||||
: [];
|
||||
return (
|
||||
<MainLayout className={styles.root}>
|
||||
<Popover
|
||||
|
||||
@@ -23,7 +23,7 @@ function calculateBottomPadding(width: number, height: number) {
|
||||
return `${(height / width) * 100}%`;
|
||||
}
|
||||
|
||||
const oEmbed: FunctionComponent<Props> = ({
|
||||
const OEmbed: FunctionComponent<Props> = ({
|
||||
url,
|
||||
type,
|
||||
className,
|
||||
@@ -47,7 +47,7 @@ const oEmbed: FunctionComponent<Props> = ({
|
||||
if (containerRef.current) {
|
||||
setMaxWidth(containerRef.current.offsetWidth);
|
||||
}
|
||||
}, [containerRef.current, maxWidth]);
|
||||
}, [containerRef, maxWidth]);
|
||||
|
||||
const onLoad = useCallback(() => {
|
||||
if (width && height && containerRef && containerRef.current) {
|
||||
@@ -96,7 +96,7 @@ const oEmbed: FunctionComponent<Props> = ({
|
||||
);
|
||||
}
|
||||
}, 100);
|
||||
}, [iframeRef, iframeRef.current, containerRef.current, width, height]);
|
||||
}, [iframeRef, containerRef, width, height]);
|
||||
|
||||
return (
|
||||
<div className={styles.container} ref={containerRef}>
|
||||
@@ -117,4 +117,4 @@ const oEmbed: FunctionComponent<Props> = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default oEmbed;
|
||||
export default OEmbed;
|
||||
|
||||
@@ -19,13 +19,12 @@ const ReportFlowContainer: FunctionComponent<Props> = ({
|
||||
comment,
|
||||
onClose,
|
||||
}) => {
|
||||
if (!viewer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const onFormClose = useCallback(() => {
|
||||
onClose();
|
||||
}, [onClose]);
|
||||
if (!viewer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <ReportCommentFormContainer comment={comment} onClose={onFormClose} />;
|
||||
};
|
||||
|
||||
@@ -33,20 +33,6 @@ const IgnoredTombstoneOrHideContainer: FunctionComponent<Props> = ({
|
||||
}) => {
|
||||
const deleted = Boolean(!comment.author);
|
||||
|
||||
if (deleted) {
|
||||
return (
|
||||
<>
|
||||
<Tombstone className={CLASSES.deletedTombstone} fullWidth>
|
||||
<Localized id="comments-tombstone-deleted">
|
||||
This comment is no longer available. The commenter has deleted their
|
||||
account.
|
||||
</Localized>
|
||||
</Tombstone>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const ignored = Boolean(
|
||||
comment.author &&
|
||||
viewer &&
|
||||
@@ -66,11 +52,30 @@ const IgnoredTombstoneOrHideContainer: FunctionComponent<Props> = ({
|
||||
if (!tombstone && ignored === true && previouslyIgnored === false) {
|
||||
setTombstone(true);
|
||||
}
|
||||
}, [ignored, previouslyIgnored, tombstone, setTombstone]);
|
||||
}, [
|
||||
ignored,
|
||||
previouslyIgnored,
|
||||
tombstone,
|
||||
setTombstone,
|
||||
singleConversationView,
|
||||
]);
|
||||
|
||||
const onShowComment = useCallback(() => {
|
||||
setForceVisible(true);
|
||||
}, [setForceVisible]);
|
||||
if (deleted) {
|
||||
return (
|
||||
<>
|
||||
<Tombstone className={CLASSES.deletedTombstone} fullWidth>
|
||||
<Localized id="comments-tombstone-deleted">
|
||||
This comment is no longer available. The commenter has deleted their
|
||||
account.
|
||||
</Localized>
|
||||
</Tombstone>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (!ignored || forceVisible) {
|
||||
return <>{children}</>;
|
||||
|
||||
+4
-4
@@ -39,15 +39,15 @@ function callWhenReallyIdle(callback: () => void) {
|
||||
* Show spinner, wait for browser to idle and start rendering.
|
||||
*/
|
||||
const SpinnerWhileRendering: FunctionComponent<Props> = (props) => {
|
||||
// In our tests, we don't actually "render", so just skip this.
|
||||
if (process.env.NODE_ENV === "test") {
|
||||
return <>{props.children}</>;
|
||||
}
|
||||
const [hidden, setHidden] = useState(true);
|
||||
useEffect(() => {
|
||||
// Ensure window has bee
|
||||
return callWhenReallyIdle(() => setHidden(false));
|
||||
}, [setHidden]);
|
||||
// In our tests, we don't actually "render", so just skip this.
|
||||
if (process.env.NODE_ENV === "test") {
|
||||
return <>{props.children}</>;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{hidden && (
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import React, { FunctionComponent } from "react";
|
||||
|
||||
import SpinnerWhileRendering from "./SpinnerWhileRendering";
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const SpinnerWhileRenderingWrapper: FunctionComponent<Props> = (props) => {
|
||||
if (process.env.NODE_ENV === "test") {
|
||||
return <>{props.children}</>;
|
||||
}
|
||||
return <SpinnerWhileRendering {...props} />;
|
||||
};
|
||||
|
||||
export default SpinnerWhileRenderingWrapper;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
export {
|
||||
default,
|
||||
default as SpinnerWhileRendering,
|
||||
} from "./SpinnerWhileRenderingWrapper";
|
||||
+3
-3
@@ -40,14 +40,14 @@ function callWhenReallyIdle(callback: () => void) {
|
||||
*/
|
||||
const SpinnerWhileRendering: FunctionComponent<Props> = (props) => {
|
||||
// In our tests, we don't actually "render", so just skip this.
|
||||
if (process.env.NODE_ENV === "test") {
|
||||
return <>{props.children}</>;
|
||||
}
|
||||
const [hidden, setHidden] = useState(true);
|
||||
useEffect(() => {
|
||||
// Ensure window has bee
|
||||
return callWhenReallyIdle(() => setHidden(false));
|
||||
}, [setHidden]);
|
||||
if (process.env.NODE_ENV === "test") {
|
||||
return <>{props.children}</>;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{hidden && (
|
||||
|
||||
@@ -81,7 +81,7 @@ interface FormProps {
|
||||
password: string;
|
||||
}
|
||||
|
||||
const changeEmailContainer: FunctionComponent<Props> = ({
|
||||
const ChangeEmailContainer: FunctionComponent<Props> = ({
|
||||
viewer,
|
||||
settings,
|
||||
}) => {
|
||||
@@ -508,6 +508,6 @@ const enhanced = withFragmentContainer<Props>({
|
||||
}
|
||||
}
|
||||
`,
|
||||
})(changeEmailContainer);
|
||||
})(ChangeEmailContainer);
|
||||
|
||||
export default enhanced;
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
display: flex;
|
||||
flex-basis: calc(var(--spacing-2) + 14px);
|
||||
justify-content: center;
|
||||
align-items: start;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.title {
|
||||
|
||||
@@ -46,10 +46,6 @@ const CallOut: FunctionComponent<Props> = ({
|
||||
visible = true,
|
||||
onClose,
|
||||
}) => {
|
||||
if (!visible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rootClasses = cn(
|
||||
classes.root,
|
||||
{
|
||||
@@ -86,6 +82,9 @@ const CallOut: FunctionComponent<Props> = ({
|
||||
|
||||
onClose();
|
||||
}, [onClose]);
|
||||
if (!visible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={rootClasses}>
|
||||
|
||||
Reference in New Issue
Block a user