From b1a7a679f011e11bb521efadf9b33a80a0b5b4a7 Mon Sep 17 00:00:00 2001 From: abias <abias1122@gmail.com> Date: Sat, 20 May 2023 15:39:12 -0400 Subject: [PATCH] Refactor tabs into reuseable component --- src/shared/components/common/tabs.tsx | 54 ++++++++ src/shared/components/home/admin-settings.tsx | 124 +++++++----------- .../components/home/rate-limit-form.tsx | 11 ++ src/shared/components/person/settings.tsx | 61 ++++----- 4 files changed, 134 insertions(+), 116 deletions(-) create mode 100644 src/shared/components/common/tabs.tsx create mode 100644 src/shared/components/home/rate-limit-form.tsx diff --git a/src/shared/components/common/tabs.tsx b/src/shared/components/common/tabs.tsx new file mode 100644 index 0000000..36e1a01 --- /dev/null +++ b/src/shared/components/common/tabs.tsx @@ -0,0 +1,54 @@ +import { Component, InfernoNode, linkEvent } from "inferno"; + +interface TabItem { + key: string; + getNode: () => InfernoNode; + label: string; +} + +interface TabsProps { + tabs: TabItem[]; +} + +interface TabsState { + currentTab: string; +} + +function handleSwitchTab({ ctx, tab }: { ctx: Tabs; tab: string }) { + console.log(tab); + ctx.setState({ currentTab: tab }); +} + +export default class Tabs extends Component<TabsProps, TabsState> { + constructor(props: TabsProps, context) { + super(props, context); + + this.state = { + currentTab: props.tabs.length > 0 ? props.tabs[0].key : "", + }; + } + + render() { + return ( + <div> + <ul className="nav nav-tabs mb-2"> + {this.props.tabs.map(({ key, label }) => ( + <li key={key} className="nav-item"> + <button + className={`nav-link btn${ + this.state?.currentTab === key ? " active" : "" + }`} + onClick={linkEvent({ ctx: this, tab: key }, handleSwitchTab)} + > + {label} + </button> + </li> + ))} + </ul> + {this.props.tabs + .find(tab => tab.key === this.state?.currentTab) + ?.getNode()} + </div> + ); + } +} diff --git a/src/shared/components/home/admin-settings.tsx b/src/shared/components/home/admin-settings.tsx index ab897fe..3a2238b 100644 --- a/src/shared/components/home/admin-settings.tsx +++ b/src/shared/components/home/admin-settings.tsx @@ -28,6 +28,7 @@ import { } from "../../utils"; import { HtmlTags } from "../common/html-tags"; import { Spinner } from "../common/icon"; +import Tabs from "../common/tabs"; import { PersonListing } from "../person/person-listing"; import { EmojiForm } from "./emojis-form"; import { SiteForm } from "./site-form"; @@ -39,7 +40,6 @@ interface AdminSettingsState { banned: PersonView[]; loading: boolean; leaveAdminTeamLoading: boolean; - currentTab: string; } export class AdminSettings extends Component<any, AdminSettingsState> { @@ -51,7 +51,6 @@ export class AdminSettings extends Component<any, AdminSettingsState> { banned: [], loading: true, leaveAdminTeamLoading: false, - currentTab: "site", }; constructor(props: any, context: any) { @@ -119,83 +118,56 @@ export class AdminSettings extends Component<any, AdminSettingsState> { render() { return ( <div className="container-lg"> + <HtmlTags + title={this.documentTitle} + path={this.context.router.route.match.url} + /> {this.state.loading ? ( <h5> <Spinner large /> </h5> ) : ( - <div> - <HtmlTags - title={this.documentTitle} - path={this.context.router.route.match.url} - /> - <ul className="nav nav-tabs mb-2"> - <li className="nav-item"> - <button - className={`nav-link btn ${ - this.state.currentTab == "site" && "active" - }`} - onClick={linkEvent( - { ctx: this, tab: "site" }, - this.handleSwitchTab - )} - > - {i18n.t("site")} - </button> - </li> - <li className="nav-item"> - <button - className={`nav-link btn ${ - this.state.currentTab == "taglines" && "active" - }`} - onClick={linkEvent( - { ctx: this, tab: "taglines" }, - this.handleSwitchTab - )} - > - {i18n.t("taglines")} - </button> - </li> - <li className="nav-item"> - <button - className={`nav-link btn ${ - this.state.currentTab == "emojis" && "active" - }`} - onClick={linkEvent( - { ctx: this, tab: "emojis" }, - this.handleSwitchTab - )} - > - {i18n.t("emojis")} - </button> - </li> - </ul> - {this.state.currentTab == "site" && ( - <div className="row"> - <div className="col-12 col-md-6"> - <SiteForm - siteRes={this.state.siteRes} - instancesRes={this.state.instancesRes} - showLocal={showLocal(this.isoData)} - /> - </div> - <div className="col-12 col-md-6"> - {this.admins()} - {this.bannedUsers()} - </div> - </div> - )} - {this.state.currentTab == "taglines" && ( - <div className="row"> - <TaglineForm siteRes={this.state.siteRes}></TaglineForm> - </div> - )} - {this.state.currentTab == "emojis" && ( - <div className="row"> - <EmojiForm></EmojiForm> - </div> - )} - </div> + <Tabs + tabs={[ + { + key: "site", + label: i18n.t("site"), + getNode: () => ( + <div className="row"> + <div className="col-12 col-md-6"> + <SiteForm + siteRes={this.state.siteRes} + instancesRes={this.state.instancesRes} + showLocal={showLocal(this.isoData)} + /> + </div> + <div className="col-12 col-md-6"> + {this.admins()} + {this.bannedUsers()} + </div> + </div> + ), + }, + { + key: "taglines", + label: i18n.t("taglines"), + getNode: () => ( + <div className="row"> + <TaglineForm siteRes={this.state.siteRes} /> + </div> + ), + }, + { + key: "emojis", + label: i18n.t("emojis"), + getNode: () => ( + <div className="row"> + <EmojiForm /> + </div> + ), + }, + ]} + /> )} </div> ); @@ -247,10 +219,6 @@ export class AdminSettings extends Component<any, AdminSettingsState> { ); } - handleSwitchTab(i: { ctx: AdminSettings; tab: string }) { - i.ctx.setState({ currentTab: i.tab }); - } - handleLeaveAdminTeam(i: AdminSettings) { let auth = myAuth(); if (auth) { diff --git a/src/shared/components/home/rate-limit-form.tsx b/src/shared/components/home/rate-limit-form.tsx new file mode 100644 index 0000000..b99c263 --- /dev/null +++ b/src/shared/components/home/rate-limit-form.tsx @@ -0,0 +1,11 @@ +import { Component } from "inferno"; + +export default class RateLimitForm extends Component { + constructor(props, context) { + super(props, context); + } + + render() { + return <></>; + } +} diff --git a/src/shared/components/person/settings.tsx b/src/shared/components/person/settings.tsx index 95b2590..f6278f7 100644 --- a/src/shared/components/person/settings.tsx +++ b/src/shared/components/person/settings.tsx @@ -54,6 +54,7 @@ import { ListingTypeSelect } from "../common/listing-type-select"; import { MarkdownTextArea } from "../common/markdown-textarea"; import { SearchableSelect } from "../common/searchable-select"; import { SortSelect } from "../common/sort-select"; +import Tabs from "../common/tabs"; import { CommunityLink } from "../community/community-link"; import { PersonListing } from "./person-listing"; @@ -176,6 +177,8 @@ export class Settings extends Component<any, SettingsState> { this.handleBannerUpload = this.handleBannerUpload.bind(this); this.handleBannerRemove = this.handleBannerRemove.bind(this); + this.userSettings = this.userSettings.bind(this); + this.blockCards = this.blockCards.bind(this); this.parseMessage = this.parseMessage.bind(this); this.subscription = wsSubscribe(this.parseMessage); @@ -253,44 +256,26 @@ export class Settings extends Component<any, SettingsState> { render() { return ( <div className="container-lg"> - <> - <HtmlTags - title={this.documentTitle} - path={this.context.router.route.match.url} - description={this.documentTitle} - image={this.state.saveUserSettingsForm.avatar} - /> - <ul className="nav nav-tabs mb-2"> - <li className="nav-item"> - <button - className={`nav-link btn ${ - this.state.currentTab == "settings" && "active" - }`} - onClick={linkEvent( - { ctx: this, tab: "settings" }, - this.handleSwitchTab - )} - > - {i18n.t("settings")} - </button> - </li> - <li className="nav-item"> - <button - className={`nav-link btn ${ - this.state.currentTab == "blocks" && "active" - }`} - onClick={linkEvent( - { ctx: this, tab: "blocks" }, - this.handleSwitchTab - )} - > - {i18n.t("blocks")} - </button> - </li> - </ul> - {this.state.currentTab == "settings" && this.userSettings()} - {this.state.currentTab == "blocks" && this.blockCards()} - </> + <HtmlTags + title={this.documentTitle} + path={this.context.router.route.match.url} + description={this.documentTitle} + image={this.state.saveUserSettingsForm.avatar} + /> + <Tabs + tabs={[ + { + key: "settings", + label: i18n.t("settings"), + getNode: this.userSettings, + }, + { + key: "blocks", + label: i18n.t("blocks"), + getNode: this.blockCards, + }, + ]} + /> </div> ); } -- 2.44.1