registerUsernameMutation.mutate(data))}>
diff --git a/apps/meteor/client/views/root/MainLayout/TwoFactorAuthSetupCheck.tsx b/apps/meteor/client/views/root/MainLayout/TwoFactorAuthSetupCheck.tsx
index 068288f4b8124..8aa5bdbd64317 100644
--- a/apps/meteor/client/views/root/MainLayout/TwoFactorAuthSetupCheck.tsx
+++ b/apps/meteor/client/views/root/MainLayout/TwoFactorAuthSetupCheck.tsx
@@ -17,7 +17,7 @@ const TwoFactorAuthSetupCheck = ({ children }: TwoFactorAuthSetupCheckProps) =>
if (require2faSetup) {
return (
-
+
diff --git a/apps/meteor/client/views/teams/ChannelDesertionTable/ChannelDesertionTable.tsx b/apps/meteor/client/views/teams/ChannelDesertionTable/ChannelDesertionTable.tsx
index 6015dbc1caaa5..c570f7f42cada 100644
--- a/apps/meteor/client/views/teams/ChannelDesertionTable/ChannelDesertionTable.tsx
+++ b/apps/meteor/client/views/teams/ChannelDesertionTable/ChannelDesertionTable.tsx
@@ -56,12 +56,12 @@ const ChannelDesertionTable = ({
}, [rooms, sortBy, sortDirection]);
return (
-
+
- {t('Channel_name')}
+ {t('Channel_name')}
diff --git a/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx b/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx
index 6f42d89d61e43..ac47ad4518126 100644
--- a/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx
+++ b/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx
@@ -71,7 +71,7 @@ const AddExistingModal = ({ teamId, onClose, reload }: AddExistingModalProps) =>
-
+ {t('Channels')} (
-
+
-
+
{label.name}
diff --git a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItem.tsx b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItem.tsx
index 6d306c6e3a7b9..a15198fa975c1 100644
--- a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItem.tsx
+++ b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItem.tsx
@@ -62,7 +62,7 @@ const TeamsChannelItem = ({ room, mainRoom, onClickView, reload }: TeamsChannelI
{roomCoordinator.getRoomName(room.t, room)}{' '}
{room.teamDefault ? (
-
+ {t('Team_Auto-join')}
) : (
diff --git a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx
index fc2d2a90c5e83..448419f353868 100644
--- a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx
+++ b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx
@@ -95,29 +95,29 @@ const TeamsChannels = ({
onChange={setText}
endAddon={}
/>
-
+
-
+
{loading && (
-
+
)}
{!loading && channels.length === 0 && }
{!loading && channels.length > 0 && (
<>
-
+
{t('Showing')}: {channels.length}
-
+
{t('Total')}: {total}
-
+
-
+
{t('Select_the_teams_channels_you_would_like_to_delete')}
-
+
{t('Notice_that_public_channels_will_be_public_and_visible_to_everyone')}
diff --git a/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/ChannelDeletionTable/ChannelDeletionTable.tsx b/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/ChannelDeletionTable/ChannelDeletionTable.tsx
index 163b1034f3321..2212c74f75c46 100644
--- a/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/ChannelDeletionTable/ChannelDeletionTable.tsx
+++ b/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/ChannelDeletionTable/ChannelDeletionTable.tsx
@@ -43,7 +43,7 @@ const ChannelDeletionTable = ({ rooms, onChangeRoomSelection, selectedRooms, onT
<>
- {t('Channel_name')}
+ {t('Channel_name')}
+ {headers}
diff --git a/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/DeleteTeamChannels.tsx b/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/DeleteTeamChannels.tsx
index d9b2160b4962a..22e689de78a46 100644
--- a/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/DeleteTeamChannels.tsx
+++ b/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/DeleteTeamChannels.tsx
@@ -33,7 +33,7 @@ const DeleteTeamChannels = ({
onClose={onCancel}
confirmText={t('Continue')}
>
-
+
{t('Team_Delete_Channel_modal_content_danger')}{' '}
diff --git a/apps/meteor/client/views/teams/contextualBar/info/TeamsInfo.tsx b/apps/meteor/client/views/teams/contextualBar/info/TeamsInfo.tsx
index 4094b4c6d475d..52b3e66daf400 100644
--- a/apps/meteor/client/views/teams/contextualBar/info/TeamsInfo.tsx
+++ b/apps/meteor/client/views/teams/contextualBar/info/TeamsInfo.tsx
@@ -50,9 +50,9 @@ const TeamsInfo = ({ room, onClickClose, onClickEdit, onClickViewChannels }: Tea
{t('Teams_Info')}
{onClickClose && }
-
+
-
+
@@ -75,7 +75,7 @@ const TeamsInfo = ({ room, onClickClose, onClickEdit, onClickViewChannels }: Tea
{room.archived && (
-
+ {t('Room_archived')}
)}
diff --git a/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersFirstStep.tsx b/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersFirstStep.tsx
index e77dcacb4d265..2f9464be358c9 100644
--- a/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersFirstStep.tsx
+++ b/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersFirstStep.tsx
@@ -41,7 +41,7 @@ const RemoveUsersFirstStep = ({
onConfirm={onConfirm}
{...props}
>
-
+
{t('Select_the_channels_you_want_the_user_to_be_removed_from')}
+ typeof user === 'string' ? user : { _id: user._id, roles: user.roles };
+
export const hasAllPermissionAsync = async (
user: IUser['_id'] | UserWithRoles,
permissions: IPermission['_id'][],
scope?: IRoom['_id'],
-): Promise => Authorization.hasAllPermission(user, permissions, scope);
+): Promise => Authorization.hasAllPermission(toSubject(user), permissions, scope);
export const hasPermissionAsync = async (
user: IUser['_id'] | UserWithRoles,
permissionId: IPermission['_id'],
scope?: IRoom['_id'],
-): Promise => Authorization.hasPermission(user, permissionId, scope);
+): Promise => Authorization.hasPermission(toSubject(user), permissionId, scope);
export const hasAtLeastOnePermissionAsync = async (
user: IUser['_id'] | UserWithRoles,
permissions: IPermission['_id'][],
scope?: IRoom['_id'],
-): Promise => Authorization.hasAtLeastOnePermission(user, permissions, scope);
+): Promise => Authorization.hasAtLeastOnePermission(toSubject(user), permissions, scope);
diff --git a/apps/uikit-playground/src/App.tsx b/apps/uikit-playground/src/App.tsx
index 80655038904da..28240e04b30f1 100644
--- a/apps/uikit-playground/src/App.tsx
+++ b/apps/uikit-playground/src/App.tsx
@@ -31,7 +31,7 @@ function App() {
dispatch(isTabletAction(isTablet));
}, [isTablet, dispatch]);
return (
-
+
diff --git a/apps/uikit-playground/src/Components/ComponentSideBar/ScrollableSideBar.tsx b/apps/uikit-playground/src/Components/ComponentSideBar/ScrollableSideBar.tsx
index 9dfb4681f0ec0..dda8378d3f3c7 100644
--- a/apps/uikit-playground/src/Components/ComponentSideBar/ScrollableSideBar.tsx
+++ b/apps/uikit-playground/src/Components/ComponentSideBar/ScrollableSideBar.tsx
@@ -8,9 +8,9 @@ const ScrollableSideBar = () => (
{
`;
return (
-
+
diff --git a/apps/uikit-playground/src/Components/ComponentSideBar/SliderBtn.tsx b/apps/uikit-playground/src/Components/ComponentSideBar/SliderBtn.tsx
index f5d96319d69cc..7eb02bdb40bf4 100644
--- a/apps/uikit-playground/src/Components/ComponentSideBar/SliderBtn.tsx
+++ b/apps/uikit-playground/src/Components/ComponentSideBar/SliderBtn.tsx
@@ -80,7 +80,7 @@ const SliderBtn = () => {
cursor: pointer;
`}
>
-
+
)}
diff --git a/apps/uikit-playground/src/Components/CreateNewScreen/CreateNewScreenContainer.tsx b/apps/uikit-playground/src/Components/CreateNewScreen/CreateNewScreenContainer.tsx
index 0220e1fb13060..bae2f4a9d4633 100644
--- a/apps/uikit-playground/src/Components/CreateNewScreen/CreateNewScreenContainer.tsx
+++ b/apps/uikit-playground/src/Components/CreateNewScreen/CreateNewScreenContainer.tsx
@@ -31,11 +31,11 @@ const CreateNewScreenContainer = () => {
{
);
return (
-
+
{blocksTree.map((branch: ItemBranch, i: number) => (
{recursiveComponentTree(branch, layer)}
))}
diff --git a/apps/uikit-playground/src/Components/DropDown/Items.tsx b/apps/uikit-playground/src/Components/DropDown/Items.tsx
index 85bcd833007cd..41c6119afecc0 100644
--- a/apps/uikit-playground/src/Components/DropDown/Items.tsx
+++ b/apps/uikit-playground/src/Components/DropDown/Items.tsx
@@ -25,7 +25,7 @@ const Items = ({ label, children, layer, payload }: ItemProps) => {
};
return (
-
+ {
if (!screens[data]) return null;
const { blocks, surface } = screens[data].payload;
return (
-
+
{blocks.map((block, index) => (
-
+
diff --git a/apps/uikit-playground/src/Components/HomeContainer/HomeContainer.tsx b/apps/uikit-playground/src/Components/HomeContainer/HomeContainer.tsx
index 1f05d9ba5148f..1119bba273962 100644
--- a/apps/uikit-playground/src/Components/HomeContainer/HomeContainer.tsx
+++ b/apps/uikit-playground/src/Components/HomeContainer/HomeContainer.tsx
@@ -9,7 +9,7 @@ import CreateNewScreenButton from '../ScreenThumbnail/CreateNewScreenButton';
const HomeContainer = () => {
const { dispatch } = useContext(context);
return (
-
+ {
grid-template-columns: repeat(auto-fill, 200px);
gap: 30px;
`}
- pbe='30px'
+ paddingBlockEnd='30px'
>
{Object.values(projects).map((project) => (
;
+const Divider = () => ;
export default Divider;
diff --git a/apps/uikit-playground/src/Components/NavBar/NavBar.tsx b/apps/uikit-playground/src/Components/NavBar/NavBar.tsx
index 03cf39f3af6f3..7bb25a7e55123 100644
--- a/apps/uikit-playground/src/Components/NavBar/NavBar.tsx
+++ b/apps/uikit-playground/src/Components/NavBar/NavBar.tsx
@@ -31,12 +31,12 @@ const NabBar = () => {
user-select: none;
`}
>
- navigate(routes.home)} mis='20px' small square>
+ navigate(routes.home)} marginInlineStart='20px' small square>
{!isMobile && (
{
diff --git a/apps/uikit-playground/src/Components/NavBar/RightNavBtn.tsx b/apps/uikit-playground/src/Components/NavBar/RightNavBtn.tsx
index def0698b93243..805c8ebe85514 100644
--- a/apps/uikit-playground/src/Components/NavBar/RightNavBtn.tsx
+++ b/apps/uikit-playground/src/Components/NavBar/RightNavBtn.tsx
@@ -8,7 +8,7 @@ const RightNavBtn = () => {
const { state, dispatch } = useContext(context);
return (
- state.isMobile && dispatch(navMenuToggleAction(true))}>
+ state.isMobile && dispatch(navMenuToggleAction(true))}>
{state.isMobile ? : Send to RocketChat}
);
diff --git a/apps/uikit-playground/src/Components/Preview/Display/Surface/ContextualBarSurface.tsx b/apps/uikit-playground/src/Components/Preview/Display/Surface/ContextualBarSurface.tsx
index d432818eb608f..e801faadeeb6b 100644
--- a/apps/uikit-playground/src/Components/Preview/Display/Surface/ContextualBarSurface.tsx
+++ b/apps/uikit-playground/src/Components/Preview/Display/Surface/ContextualBarSurface.tsx
@@ -22,7 +22,7 @@ const ContextualBarSurface = ({ children }: ContextualBarSurfaceProps) => (
-
+ {
};
return (
-
+ {
diff --git a/apps/uikit-playground/src/Components/Preview/Editor/ActionBlockEditor.tsx b/apps/uikit-playground/src/Components/Preview/Editor/ActionBlockEditor.tsx
index 1682703b994dc..2699df30a0339 100644
--- a/apps/uikit-playground/src/Components/Preview/Editor/ActionBlockEditor.tsx
+++ b/apps/uikit-playground/src/Components/Preview/Editor/ActionBlockEditor.tsx
@@ -10,7 +10,7 @@ const ActionBlockEditor = () => (
height='100%'
width='100%'
zIndex={1}
- bg='#f6f9fc'
+ backgroundColor='#f6f9fc'
display='flex'
borderInlineStart='var(--default-border)'
overflow='auto'
diff --git a/apps/uikit-playground/src/Components/Preview/Editor/ActionPreviewEditor.tsx b/apps/uikit-playground/src/Components/Preview/Editor/ActionPreviewEditor.tsx
index 057def4397201..0305a9a396ac7 100644
--- a/apps/uikit-playground/src/Components/Preview/Editor/ActionPreviewEditor.tsx
+++ b/apps/uikit-playground/src/Components/Preview/Editor/ActionPreviewEditor.tsx
@@ -10,7 +10,7 @@ const ActionPreviewEditor = () => (
height='100%'
width='100%'
zIndex={1}
- bg='#f6f9fc'
+ backgroundColor='#f6f9fc'
display='flex'
borderInlineStart='var(--default-border)'
overflow='auto'
diff --git a/apps/uikit-playground/src/Components/Preview/Editor/EditorPanel.tsx b/apps/uikit-playground/src/Components/Preview/Editor/EditorPanel.tsx
index 279629be3d7f5..c5a45994fddf9 100644
--- a/apps/uikit-playground/src/Components/Preview/Editor/EditorPanel.tsx
+++ b/apps/uikit-playground/src/Components/Preview/Editor/EditorPanel.tsx
@@ -77,7 +77,7 @@ const EditorPanel = () => {
className={tabChangeStyle(editorTabsToggle)}
>
{Object.values(tabsItem).map(({ Container: ContainerComponent }, index) => (
- {index === editorTabsToggle ? : }
+ {index === editorTabsToggle ? : }
))}
diff --git a/apps/uikit-playground/src/Components/Preview/NavPanel/NavPanel.tsx b/apps/uikit-playground/src/Components/Preview/NavPanel/NavPanel.tsx
index 1c5e27277fbbe..1d01f00133df5 100644
--- a/apps/uikit-playground/src/Components/Preview/NavPanel/NavPanel.tsx
+++ b/apps/uikit-playground/src/Components/Preview/NavPanel/NavPanel.tsx
@@ -26,15 +26,15 @@ const NavPanel = () => {
alignItems='center'
zIndex={1}
justifyContent={isMobile ? 'flex-end' : 'space-between'}
- bg='alternative'
+ backgroundColor='alternative'
className={css`
user-select: none;
`}
>
{!isMobile && (
-
+
- dispatch(templatesToggleAction(true))}>
+ dispatch(templatesToggleAction(true))}>
Templates
diff --git a/apps/uikit-playground/src/Components/Preview/Preview.tsx b/apps/uikit-playground/src/Components/Preview/Preview.tsx
index 7759bcab99ad2..b2da9c65797f4 100644
--- a/apps/uikit-playground/src/Components/Preview/Preview.tsx
+++ b/apps/uikit-playground/src/Components/Preview/Preview.tsx
@@ -20,11 +20,11 @@ const Preview = () => {
+
{blocks.map((action, id) => (
{
return (
-
+
{isOpen && (
-
-
+
+
-
+
{formatDate(date)}
-
+
diff --git a/apps/uikit-playground/src/Components/ScreenThumbnail/EditableLabel/EditableLabel.tsx b/apps/uikit-playground/src/Components/ScreenThumbnail/EditableLabel/EditableLabel.tsx
index af2d405dc1814..bf81f09bc28f4 100644
--- a/apps/uikit-playground/src/Components/ScreenThumbnail/EditableLabel/EditableLabel.tsx
+++ b/apps/uikit-playground/src/Components/ScreenThumbnail/EditableLabel/EditableLabel.tsx
@@ -16,8 +16,8 @@ const EditableLabel = (props: ComponentProps) => {
setHover(true)}
diff --git a/apps/uikit-playground/src/Components/ScreenThumbnail/ScreenThumbnailWrapper.tsx b/apps/uikit-playground/src/Components/ScreenThumbnail/ScreenThumbnailWrapper.tsx
index b8187af6f8a1f..2267eabe4ce6d 100644
--- a/apps/uikit-playground/src/Components/ScreenThumbnail/ScreenThumbnailWrapper.tsx
+++ b/apps/uikit-playground/src/Components/ScreenThumbnail/ScreenThumbnailWrapper.tsx
@@ -13,11 +13,11 @@ const ScreenThumbnailWrapper = ({
onClick?: ComponentProps['onClick'];
children: ReactNode;
} & ComponentProps) => (
-
-
+
+ {
return (
{
-
+
Use This Template
>
diff --git a/apps/uikit-playground/src/Components/Templates/Container/Section.tsx b/apps/uikit-playground/src/Components/Templates/Container/Section.tsx
index f1b0726eef16b..5f089aac5c2ac 100644
--- a/apps/uikit-playground/src/Components/Templates/Container/Section.tsx
+++ b/apps/uikit-playground/src/Components/Templates/Container/Section.tsx
@@ -6,13 +6,13 @@ import type { templateType } from '../../../utils/templates';
export type SectionProps = { template: templateType; index: number };
const Section = ({ template, index }: SectionProps) => (
-
-
+
+
{template.heading}
-
+ {template.description}
{template.payloads.map((payload, i) => (
diff --git a/apps/uikit-playground/src/Components/Templates/Templates.tsx b/apps/uikit-playground/src/Components/Templates/Templates.tsx
index 50bae43cac74f..d594ab2213ca5 100644
--- a/apps/uikit-playground/src/Components/Templates/Templates.tsx
+++ b/apps/uikit-playground/src/Components/Templates/Templates.tsx
@@ -22,7 +22,7 @@ const Templates = () => {
display='flex'
justifyContent='center'
alignItems='flex-start'
- bg='white'
+ backgroundColor='white'
zIndex={100}
overflow='auto'
className={css`
diff --git a/apps/uikit-playground/src/Components/navMenu/Menu/Wrapper.tsx b/apps/uikit-playground/src/Components/navMenu/Menu/Wrapper.tsx
index 2d7797846ea4b..e4bd6a41b034d 100644
--- a/apps/uikit-playground/src/Components/navMenu/Menu/Wrapper.tsx
+++ b/apps/uikit-playground/src/Components/navMenu/Menu/Wrapper.tsx
@@ -5,8 +5,8 @@ export type WrapperProps = { children: ReactNode };
const Wrapper = ({ children }: WrapperProps) => (
{
position='absolute'
width='min(85%, 280px)'
height='100%'
- bg='default'
+ backgroundColor='default'
className={[basicStyle, toggleStyle]}
onClick={(e) => {
e.stopPropagation();
diff --git a/apps/uikit-playground/src/Components/navMenu/NavMenu.tsx b/apps/uikit-playground/src/Components/navMenu/NavMenu.tsx
index c56459647bb85..b21ccae1e26f7 100644
--- a/apps/uikit-playground/src/Components/navMenu/NavMenu.tsx
+++ b/apps/uikit-playground/src/Components/navMenu/NavMenu.tsx
@@ -30,7 +30,7 @@ const NavMenu = () => {
width='100%'
height='100%'
zIndex={3}
- bg={isOpen ? '#000000cc' : 'transparent'}
+ backgroundColor={isOpen ? '#000000cc' : 'transparent'}
className={css`
user-select: none;
transition: var(--animation-fast);
diff --git a/apps/uikit-playground/src/Pages/FlowDiagram.tsx b/apps/uikit-playground/src/Pages/FlowDiagram.tsx
index da4854d12b409..32b384572abc0 100644
--- a/apps/uikit-playground/src/Pages/FlowDiagram.tsx
+++ b/apps/uikit-playground/src/Pages/FlowDiagram.tsx
@@ -4,7 +4,7 @@ import { ReactFlowProvider } from 'reactflow';
import FlowContainer from '../Components/FlowContainer/FlowContainer';
const FlowDiagram = () => (
-
+
diff --git a/apps/uikit-playground/src/Pages/Home.tsx b/apps/uikit-playground/src/Pages/Home.tsx
index 7d298c42815e4..6a3e24dcb9bcb 100644
--- a/apps/uikit-playground/src/Pages/Home.tsx
+++ b/apps/uikit-playground/src/Pages/Home.tsx
@@ -4,7 +4,7 @@ import HomeContainer from '../Components/HomeContainer/HomeContainer';
const Home = () => {
return (
-
+
diff --git a/apps/uikit-playground/src/Pages/Playground.tsx b/apps/uikit-playground/src/Pages/Playground.tsx
index c88d69284a9ad..6af72c843fbb9 100644
--- a/apps/uikit-playground/src/Pages/Playground.tsx
+++ b/apps/uikit-playground/src/Pages/Playground.tsx
@@ -21,7 +21,14 @@ const Playground = () => {
-
+
diff --git a/apps/uikit-playground/src/Pages/Prototype.tsx b/apps/uikit-playground/src/Pages/Prototype.tsx
index 350b4d0d70f23..e009a50313b52 100644
--- a/apps/uikit-playground/src/Pages/Prototype.tsx
+++ b/apps/uikit-playground/src/Pages/Prototype.tsx
@@ -4,7 +4,7 @@ import PrototypeContainer from '../Components/PtototypeContainer/PrototypeContai
const Prototype = () => {
return (
-
+
);
diff --git a/apps/uikit-playground/src/Pages/SignInSignUp.tsx b/apps/uikit-playground/src/Pages/SignInSignUp.tsx
index 5ca187587b1f7..b4a328ac05571 100644
--- a/apps/uikit-playground/src/Pages/SignInSignUp.tsx
+++ b/apps/uikit-playground/src/Pages/SignInSignUp.tsx
@@ -31,23 +31,23 @@ const SignInSignUp = ({ route }: SignInSignUpProps) => {
};
return (
-
+
-
-
+
+
-
+
{labels[route].header}
-
+
{labels[route].description}
-
-
+
+
{labels[route].button}
-
+
{`${labels[route].footer} `}
Compiled from the internal Confluence page [Guidelines](https://rocketchat.atlassian.net/wiki/spaces/RnD/pages/753532947/Guidelines) (R&D space) and its child pages. These are the guidelines for writing clear, concise, and consistent frontend code.
+
+## Table of contents
+
+- [TypeScript general conventions](#typescript-general-conventions)
+- [Migrating from JavaScript](#migrating-from-javascript)
+- [React](#react)
+- [Building components](#building-components)
+
+---
+
+## TypeScript general conventions
+
+### Don't use CommonJS features
+
+Avoid using CommonJS features such as `require` and `module` alongside ES module constructs like `import` and `export`. The preference is for ES modules due to their enhanced portability and user-friendly nature. However, keep in mind that synchronous conditional imports aren't possible in ES modules.
+
+Example of CommonJS (not recommended):
+
+```ts
+// commonjs.ts
+if (condition) {
+ const foo = require('foo');
+ module.exports = foo;
+} else {
+ module.exports = {};
+}
+```
+
+Invalid ES module pattern:
+
+```ts
+// esmodule.ts
+if (condition) {
+ import foo from 'foo';
+ export default foo;
+} else {
+ export default {};
+}
+```
+
+### Prefer `import type` over `import`
+
+Prioritize using `import type` for type-only imports. While a regular `import` works for both JavaScript and TypeScript, it can include module output code in the bundle. The `import type` construct is specific to TypeScript compilation and avoids unnecessary code inclusion.
+
+```ts
+// Foo.ts
+export class Foo {
+ bar: string;
+
+ constructor(bar: string) {
+ this.bar = bar;
+ }
+}
+
+// Bar.ts
+export class Bar {
+ foo: Foo;
+
+ constructor(foo: Foo) {
+ this.foo = foo;
+ }
+}
+
+// index.ts
+import { Foo } from './Foo';
+import type { Bar } from './Bar';
+
+declare const foo: Foo;
+declare const bar: Bar;
+
+// index.js (transpiled from index.ts)
+import { Foo } from './Foo';
+```
+
+### Know the difference between `type` and `interface`
+
+An `interface` serves as a type declaration similar to a class construct, while a `class` functions as an actual class declaration.
+
+```ts
+interface IThing {
+ prop: string;
+ method(): void;
+}
+
+class Thing implements IThing {
+ public prop = 'foo';
+
+ method(): void {
+ console.log('bar');
+ }
+}
+```
+
+A `type` construct is similar to an interface but offers greater flexibility. The `type` construct permits declaration of union types:
+
+```ts
+type Foo = string | number;
+```
+
+An `interface` can declare generic types:
+
+```ts
+interface IFoo {
+ prop: T;
+}
+```
+
+A `type` also supports generics and conditional types, providing more adaptability:
+
+```ts
+type Foo = T extends string ? { foo: number } : { bar: number };
+```
+
+### Avoid using classes as namespaces
+
+Pattern to avoid:
+
+```ts
+// foo.ts
+class Foo {
+ bar(): void {
+ // ...
+ }
+}
+
+export const foo = new Foo();
+
+// index.ts
+import { foo } from './foo';
+
+foo.bar();
+```
+
+Preferred approach (when no state is needed):
+
+```ts
+// foo.ts
+export function bar(): void {
+ // ...
+}
+
+// index.ts
+import * as foo from './foo';
+
+foo.bar();
+```
+
+Valid use case (when managing state):
+
+```ts
+// foo.ts
+class Foo {
+ baz: number;
+
+ bar(): void {
+ // perform actions referencing and modifying `this.baz`
+ }
+}
+
+export const foo = new Foo();
+
+// index.ts
+import { foo } from './foo';
+
+foo.bar();
+```
+
+Classes are reasonable when they encapsulate state and provide a controlled interface for modification.
+
+### Avoid using the `any` type except when it's used as a constraint
+
+Refrain from using `any` under most circumstances. Instead, follow this model:
+
+- `unknown` serves as the universal type, encompassing all potential values;
+- `any` should not be seen as an actual type, but rather as a means to disable TypeScript's type checking.
+
+Using `any` is discouraged as it indicates unawareness regarding the type being manipulated. Working with `unknown` necessitates type narrowing, leading to more robust code.
+
+```ts
+// Avoid using any
+declare const foo: any;
+foo.bar(); // No compilation error
+
+// Prefer using unknown
+declare const bar: unknown;
+bar.baz(); // Compilation error
+
+const hasBaz = (bar: unknown): bar is { baz(): void } =>
+ typeof bar === 'object' && bar !== null && 'baz' in bar && typeof (bar as { baz: unknown }).baz === 'function';
+
+if (hasBaz(bar)) {
+ bar.baz(); // No compilation error
+}
+```
+
+Exception — generic type constraints:
+
+```ts
+type X = F extends (x: unknown) => void ? true : false;
+type Y = F extends (x: any) => void ? true : false;
+
+type A = X<(x: string) => void>; // `false`, because x is not `unknown`
+type B = Y<(x: string) => void>; // `true`, because x is anything
+```
+
+---
+
+## Migrating from JavaScript
+
+### TypeScript is a superset of JavaScript
+
+TypeScript is an extension of JavaScript, meaning that when transitioning from JavaScript to TypeScript, you can employ the identical syntax used in JavaScript. Many errors flagged by the TypeScript compiler (`tsc`) and ESLint enforce best practices, though some can be disregarded if they don't affect functionality.
+
+### JSDoc
+
+When `allowJs` is enabled in `tsconfig.json`, JSDoc comments can document types within JavaScript code. This is particularly useful during gradual migration when `tsc` struggles with type inference.
+
+Example with `@typedef`:
+
+```js
+// module.js
+
+/**
+ * @typedef {Object} Foo
+ * @property {string} bar
+ * @property {string} qux
+ */
+
+export const foo = { bar: 'baz' };
+
+foo.qux = 'quux';
+```
+
+Alternative using the `@type` tag:
+
+```js
+// module.js
+
+/**
+ * @type {{ bar: string; qux: string }}
+ */
+export const foo = { bar: 'baz' };
+
+foo.qux = 'quux';
+```
+
+Both approaches help ensure TypeScript accurately recognizes the complete type structure.
+
+### Declare a `*.d.ts` file
+
+Creating a `.d.ts` declaration file is strongly recommended when migrating large JavaScript modules. These files manage imports and exports, functioning as a module's interface. This approach is superior to JSDoc for planning and understanding module structure.
+
+```ts
+// hugeModule.d.ts
+export function foo(): void; // maybe it will be placed in another module
+export function bar(): void; // maybe it will be placed in another module
+```
+
+---
+
+## React
+
+> Most of the recommendations here are based on Alex Kondov's [Tao of React](https://alexkondov.com/tao-of-react/).
+
+### Prefer functional components
+
+React initially introduced class components to leverage JavaScript class syntax for managing state and component lifecycles. However, class components have significant drawbacks:
+
+- they tend to be verbose;
+- they often involve a misuse of the inheritance mechanism through `extends` and `super`.
+
+Hooks were introduced to provide an alternative approach to declaring state and effects. They maintain the core concept of the component's render function without the need for classes, streamlining the development process.
+
+### Declare one component per file
+
+While colocation is a commendable concept, it's not consistently followed for React components within a single file. The main reason is that we've noticed people misusing this approach before. It might start with something as straightforward as adding a basic modal component alongside a page component, but it can quickly lead to a confusing jumble of components that becomes difficult to manage.
+
+### Name components
+
+Failing to name a component is a common mistake that can lead to prolonged debugging efforts. It results in less informative error stacks and challenges while navigating components in React Dev Tools. There are two approaches to properly name a component:
+
+1. By writing a non-anonymous function:
+
+```jsx
+const Foo = () => {
+ return
Foo
;
+};
+
+console.log('The component name is:', Foo.name);
+```
+
+2. By using the `displayName` property:
+
+```jsx
+const Foo = memo(() => {
+ return
Foo
;
+});
+
+Foo.displayName = 'Foo'; // `Foo.name` is `undefined`
+
+console.log('The component name is:', Foo.displayName);
+```
+
+### Use default export at the end of file
+
+While named exports are often preferred, using default export enhances code readability, especially when dealing with Higher Order Components (HOCs) like `memo` and `forwardRef`, and it aligns neatly with code splitting using `lazy`.
+
+```tsx
+// Component.tsx
+import { memo } from 'react';
+
+type ComponentProps = {
+ name: string;
+};
+
+// It is NOT an anonymous function
+const Component = (props: ComponentProps) => {
+ return
Hello, {props.name}
;
+};
+
+export default memo(Component); // the component name is preserved
+```
+
+```ts
+// index.ts
+import { lazy } from 'react';
+
+const Component = lazy(() => import('./Component'));
+```
+
+The same example based on named exports is less readable:
+
+```tsx
+// Component.tsx
+import { memo } from 'react';
+
+type ComponentProps = {
+ name: string;
+};
+
+// It is an anonymous function
+export const Component = memo((props: ComponentProps) => {
+ return
Hello, {props.name}
;
+});
+
+Component.displayName = 'Component'; // needed for React Dev Tools
+```
+
+```ts
+// index.ts
+import { lazy } from 'react';
+
+const Component = lazy(async () => {
+ const { Component } = await import('./Component');
+ return { default: Component }; // you need to reconstruct the default export
+});
+```
+
+### Extract helper functions
+
+A drawback associated with the adoption of React Hooks is the tendency for individuals to define helper functions within the component. This is facilitated by the fact that there is no requirement to pass arguments; instead, variables from the encompassing scope can be directly accessed and used.
+
+```jsx
+const Component = () => {
+ const value = useMyHook();
+ const isValueOK = () => value === 'OK';
+ return isValueOK() ? <>OK> : null;
+};
+```
+
+Typically, effective helper functions adhere to the principle of being pure, which makes them simpler to debug. However, when you bind variables into the helper's scope, you're making it impure. Furthermore, with each rendering cycle, the function value gets redefined. While this process is efficient in terms of CPU and memory usage, it can lead to scenarios where you must rely on techniques like `useCallback` to prevent unnecessary re-renders of child components that receive your helper function as a prop.
+
+Here's the ideal case:
+
+```jsx
+const isValueOK = (value) => value === 'OK';
+
+const Component = () => {
+ const value = useMyHook();
+ return isValueOK(value) ? <>OK> : null;
+};
+```
+
+### Do not refer to the `children` prop explicitly
+
+Children should always be actual children, not passed in as a prop. Use the `eslint-plugin-react` rule [`react/no-children-prop`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-children-prop.md) as reference.
+
+❌ Incorrect:
+
+```jsx
+export const MyComponent = () => ;
+```
+
+✅ Correct:
+
+```jsx
+export const MyComponent = () =>
{...}
;
+```
+
+### Declare props type explicitly
+
+Each component named, for instance, `Component` must have an _exported_ type declaration for `ComponentProps`.
+
+```tsx
+export type MyComponentProps = {
+ // ...
+};
+
+const MyComponent = (props: MyComponentProps) => /* ... */;
+
+export default MyComponent;
+```
+
+### Use generic types when appropriate
+
+Generic types are a great way to ensure type safety once they enable us to not fall into the unsoundness of type assertions.
+
+❌ Incorrect:
+
+```tsx
+// MyComponent.tsx
+export type MyComponentProps = {
+ value: unknown;
+ onChange: (newValue: unknown) => void;
+};
+
+const MyComponent = ({ value, onChange }: MyComponentProps) => /* ... */;
+
+export default MyComponent;
+
+// MyApp.tsx
+import MyComponent from './MyComponent';
+
+const MyApp = () => {
+ const [value, setValue] = useState('');
+ const handleChange = (value: unknown) => {
+ setValue(value as string); // unsound type assertion, as unknown can be anything
+ };
+ return ;
+};
+
+export default MyApp;
+```
+
+✅ Correct:
+
+```tsx
+// MyComponent.tsx
+export type MyComponentProps = {
+ value: TValue;
+ onChange: (newValue: TValue) => void;
+};
+
+const MyComponent = ({ value, onChange }: MyComponentProps) => /* ... */;
+
+export default MyComponent;
+
+// MyApp.tsx
+import MyComponent from './MyComponent';
+
+const MyApp = () => {
+ const [value, setValue] = useState('');
+ const handleChange = (value: string) => {
+ setValue(value);
+ };
+ // since `value` is string, `onChange` type will be inferred
+ // as `(value: string) => void`
+ return ;
+};
+
+export default MyApp;
+```
+
+### Avoid naming identifiers with their value type/kind
+
+This is a common programming convention, but it seems easier to violate when working with React concepts. In general, identifiers should not include information about the data structure they refer to.
+
+```ts
+// Examples of bad identifiers
+const amountConst = 123; // instead of "amount"
+let countNumber = 0; // instead of "count"
+function logFunction(lineString: string) {
+ // instead of "log" and "line"
+ console.log(lineString);
+}
+```
+
+Identifiers like this mimic the old-fashioned Hungarian notation. In React, this happens quite often:
+
+```tsx
+// Examples of bad identifiers in React constructs
+function useThingHook() {
+ // ...
+} // instead of "useThing"
+
+const useThingContext = () => useContext(ThingContext);
+// "ThingContext" already exposes itself as a context that provides a "Thing".
+// "useThing" is good enough, since it doesn't need to expose its context dependency.
+
+const MyComponent = () => ;
+// Fine for code examples and components passed by props*, but in general
+// capital cased function names used in JSX already communicate they are of
+// "Component" kind
+
+// * when "Component" is okay as a suffix
+type MyPanelProps = {
+ panelComponent: ElementType<{}>;
+};
+
+function MyPanel({ panelComponent: PanelComponent }: MyPanelProps) {
+ // "PanelComponent" is fine here
+ return (
+
+
+
+ );
+}
+```
+
+---
+
+## Building components
+
+A component is a reusable piece of code that represents a single UI element. Components vary by complexity and type, existing at either the **application** level or the **Fuselage library** level:
+
+- **Application components** remain specific to particular Rocket.Chat applications, without cross-application reusability.
+- **Fuselage library components** are reusable across all Rocket.Chat applications and represent the recommended approach.
+
+### Component rules matrix
+
+| Combination | Fuselage level | Application level |
+| ---------------- | -------------- | ----------------- |
+| Simple & Visual | ✅ | ❌ |
+| Complex & Visual | ✅ | ✅ |
+| Simple & Logical | ❌ | ❌ |
+| Complex & Logical| ❌ | ✅ |
+
+### Simple components
+
+Simple components represent atomic UI elements like buttons or text fields.
+
+#### Prefer variation over styles
+
+Use prop names suggesting component variation rather than style-based props. Instead of `color="blue"`, use `variation="primary"` for improved readability and consistency.
+
+#### Avoid hardcoded values or magic numbers
+
+Preferred:
+
+```jsx
+
+
+
+```
+
+Not recommended:
+
+```jsx
+
+
+
+```
+
+#### Customize via CSS variables
+
+Prioritize CSS variable customization over arbitrary values:
+
+```scss
+$modal-margin: theme('modal-margin', auto);
+
+.rcx-modal {
+ position: static;
+ display: flex;
+ width: 100%;
+ max-height: 100%;
+ margin: $modal-margin;
+}
+```
+
+#### Document variations in Storybook
+
+Display all possible variations with descriptive explanations for non-obvious options.
+
+#### Unit test all behaviors
+
+Comprehensive unit tests ensure reliability across all intended scenarios:
+
+```jsx
+describe('[Menu Component]', () => {
+ const menuOption = screen.queryByText('Make Admin');
+
+ it('should renders without crashing', () => {
+ render();
+ });
+
+ it('should open options when click', async () => {
+ const { getByTestId } = render();
+ const button = getByTestId('menu');
+ userEvent.click(button);
+ expect(await screen.findByText('Make Admin')).toBeInTheDocument();
+ });
+
+ it('should have no options when click twice', async () => {
+ const { getByTestId } = render();
+ const button = getByTestId('menu');
+ userEvent.click(button);
+ userEvent.click(button);
+ expect(menuOption).toBeNull();
+ });
+
+ it('should have no options when click on menu and then elsewhere', async () => {
+ const { getByTestId } = render();
+ const button = getByTestId('menu');
+ userEvent.click(button);
+ userEvent.click(document.body);
+ expect(menuOption).toBeNull();
+ });
+});
+```
+
+#### Avoid "Boxed" components
+
+The `Box` component works as a wildcard primarily for simple or complex components during prototyping. For simple components specifically, construct using HTML tags instead.
+
+### Complex components
+
+Complex components combine multiple simple components for sophisticated UI elements like modals or tables.
+
+#### Visual only, no logic
+
+Concentrate solely on the user interface design, ensuring it is poised to incorporate the required logic seamlessly.
+
+```jsx
+export const Default = () => (
+
+
+
+ Modal Header
+
+
+
+ Modal Body
+
+
+ Cancel
+
+ Submit
+
+
+
+
+);
+```
+
+#### Split components for clarity
+
+Structure components into understandable, logical segments.
+
+#### Develop with Storybook first
+
+Start with Storybook to separate interface from logic:
+
+```tsx
+export const CallingDM: ComponentStory = () => (
+
+
+
+ Calling...
+
+
+ Join
+ Waiting for answer
+
+
+);
+
+export const CallEndedDM: ComponentStory = () => (
+
+
+
+ Call ended
+
+
+ Call Back
+ Call was not answered
+
+
+);
+```
+
+#### Child components must remain scoped
+
+❌ Incorrect:
+
+```tsx
+export const MyComponent: ComponentStory = () => (
+
+