Skip to content

Commit

Permalink
Merge pull request #52 from tchapgouv/feat/46_create_room
Browse files Browse the repository at this point in the history
Create Room
  • Loading branch information
estellecomment authored Apr 25, 2022
2 parents fb5eb1d + dc19b62 commit 5ed99d7
Show file tree
Hide file tree
Showing 15 changed files with 685 additions and 4 deletions.
6 changes: 5 additions & 1 deletion config.preprod.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@
"accent": "#162d58",
"primary-color": "#368bd6",
"warning-color": "#ff4b55",
"private-color": "#eb5757",
"external-color": "#f07a12",
"forum-color": "#27ae60",
"sidebar-color": "#27303a",
"roomlist-background-color": "#f3f8fd",
"roomlist-text-color": "#2e2f32",
Expand All @@ -76,7 +79,8 @@
"timeline-background-color": "#ffffff",
"timeline-text-color": "#2e2f32",
"timeline-text-secondary-color": "#61708b",
"timeline-highlights-color": "#f3f8fd"
"timeline-highlights-color": "#f3f8fd",
"togglesw-off-color": "#c1c9d6"
}
}
]
Expand Down
6 changes: 5 additions & 1 deletion config.prod.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@
"accent": "#162d58",
"primary-color": "#368bd6",
"warning-color": "#ff4b55",
"private-color": "#eb5757",
"external-color": "#f07a12",
"forum-color": "#27ae60",
"sidebar-color": "#27303a",
"roomlist-background-color": "#f3f8fd",
"roomlist-text-color": "#2e2f32",
Expand All @@ -160,7 +163,8 @@
"timeline-background-color": "#ffffff",
"timeline-text-color": "#2e2f32",
"timeline-text-secondary-color": "#61708b",
"timeline-highlights-color": "#f3f8fd"
"timeline-highlights-color": "#f3f8fd",
"togglesw-off-color": "#c1c9d6"
}
}
]
Expand Down
5 changes: 5 additions & 0 deletions customisations.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"src/@types/tchap.ts": "src/@types/tchap.ts",
"src/components/views/dialogs/CreateRoomDialog.tsx": "src/components/views/dialogs/TchapCreateRoomDialog.tsx",
"src/components/views/elements/TchapRoomTypeSelector.tsx": "src/components/views/elements/TchapRoomTypeSelector.tsx"
}
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,7 @@
"RecorderWorklet": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/empty.js"
},
"transformIgnorePatterns": [
"/node_modules/(?!matrix-js-sdk).+$",
"/node_modules/(?!matrix-react-sdk).+$"
"/node_modules/(?!matrix-js-sdk|matrix-react-sdk).+$"
]
}
}
96 changes: 96 additions & 0 deletions res/css/views/elements/_TchapRoomTypeSelector.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
.tc_TchapRoomTypeSelector {
display: flex;
flex-direction: column;
gap: 24px;

>.tc_TchapRoomTypeSelector_RadioButton {
flex-grow: 0;
flex-shrink: 1;
display: flex;
flex-direction: column;
padding: 10px;

border-width: 3px;
border-style: solid;
border-color: transparent;
border-radius: 10px;

.tc_TchapRoomTypeSelector_RadioButton_title {
font-weight: bold;
}
}

.tc_TchapRoomTypeSelector_private {
.tc_TchapRoomTypeSelector_RadioButton_title {
color: var(--private-color);
&::before {
width: 12px;
height: 16px;
content: "";
display: inline-block;
vertical-align: sub;
background-image: url("../../../img/tchap/padlock-private.svg");
background-repeat: no-repeat;
background-size: 100%;
margin-right: 4px;
}
}

&.tc_TchapRoomTypeSelector_RadioButton_selected {
border-color: var(--private-color);
}
}

.tc_TchapRoomTypeSelector_external {
.tc_TchapRoomTypeSelector_RadioButton_title {
color: var(--external-color);
&::before {
width: 12px;
height: 16px;
content: "";
display: inline-block;
vertical-align: sub;
background-image: url("../../../img/tchap/padlock-external.svg");
background-repeat: no-repeat;
background-size: 100%;
margin-right: 4px;
}
}

&.tc_TchapRoomTypeSelector_RadioButton_selected {
border-color: var(--external-color);
}

}

.tc_TchapRoomTypeSelector_forum {
.tc_TchapRoomTypeSelector_RadioButton_title {
color: var(--forum-color);
&::before {
width: 12px;
height: 16px;
content: "";
display: inline-block;
vertical-align: sub;
background-image: url("../../../img/tchap/padlock-forum.svg");
background-repeat: no-repeat;
background-size: 100%;
margin-right: 4px;
}
}

&.tc_TchapRoomTypeSelector_RadioButton_selected {
border-color: var(--forum-color);
}

.mx_SettingsFlag {
flex-direction: row;
display: flex;
align-items: center;
margin-top: 10px;
.mx_SettingsFlag_label {
padding-top: 0px;
}
}
}
}
4 changes: 4 additions & 0 deletions res/img/tchap/padlock-external.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions res/img/tchap/padlock-forum.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions res/img/tchap/padlock-private.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions src/@types/tchap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export enum TchapRoomType {
Direct = "direct",
Private = "private",
External = "external",
Forum = "forum",
}

export enum TchapRoomAccessRule {
Unrestricted = "unrestricted", // accessible to externals
Restricted = "restricted" // not accessible to externals
}
185 changes: 185 additions & 0 deletions src/components/views/dialogs/TchapCreateRoomDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/*
Copyright 2022 DINUM
Replaces CreateRoomDialog.tsx
Tchap has 3 types of rooms only : private, private open to externs, and public (forum).
Tchap does not support spaces for now, so there are no settings dependent on spaces (for example "Visible to space
members"). Element uses JoinRule.Restricted for this.
When/if Tchap supports spaces, we can decide on more specific settings if needed.
Note on imports : because this file will be copied to a different directory by the customisations
mechanism, imports must use absolute paths.
Except when importing from other customisation files. Then imports must use relative paths.
*/
import React, { ChangeEvent, createRef, KeyboardEvent } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import withValidation, { IFieldState } from 'matrix-react-sdk/src/components/views/elements/Validation';
import { _t } from 'matrix-react-sdk/src/languageHandler';
import { IOpts } from "matrix-react-sdk/src/createRoom";
import { getKeyBindingsManager } from "matrix-react-sdk/src/KeyBindingsManager";
import { KeyBindingAction } from "matrix-react-sdk/src/accessibility/KeyboardShortcuts";
import * as sdk from 'matrix-react-sdk/src/index';
import Field from "matrix-react-sdk/src/components/views/elements/Field";

import TchapUtils from '../../../util/TchapUtils';
import TchapRoomTypeSelector from "./../elements/TchapRoomTypeSelector";
import { TchapRoomType } from "../../../@types/tchap";
import roomCreateOptions from "../../../lib/createTchapRoom";

// We leave the same props as Element's version, to avoid unknown props warnings.
interface IProps {
defaultPublic?: boolean; // unused for Tchap version
defaultName?: string;
parentSpace?: Room; // unused for Tchap version
defaultEncrypted?: boolean; // unused for Tchap version
onFinished(proceed: boolean, opts?: IOpts): void;
}

interface IState {
name: string;
nameIsValid: boolean;
tchapRoomType: TchapRoomType;
isFederated: boolean;
showFederateSwitch: boolean;
}

export default class TchapCreateRoomDialog extends React.Component<IProps, IState> {
private nameField = createRef<Field>();

constructor(props) {
super(props);

const federationOptions = TchapUtils.getRoomFederationOptions();

This comment has been minimized.

Copy link
@odelcroi

odelcroi Apr 26, 2022

Member

Move getRoomFederationOptions to a TchapConfig class? I would reserve TchapUtils for code that contains no business logic.


this.state = {
name: this.props.defaultName || "",
nameIsValid: false,
tchapRoomType: TchapRoomType.Private,
isFederated: federationOptions.roomFederationDefault,
showFederateSwitch: federationOptions.showRoomFederationOption,
};
}

componentDidMount() {
// move focus to first field when showing dialog
this.nameField.current.focus();
}

componentWillUnmount() {
}

private onCancel = () => {
this.props.onFinished(false);
};

private onFederatedChange = (isFederated: boolean) => {
this.setState({ isFederated: isFederated });
};

private onTchapRoomTypeChange = (tchapRoomType: TchapRoomType) => {
this.setState({ tchapRoomType: tchapRoomType });
};

private onNameChange = (ev: ChangeEvent<HTMLInputElement>) => {
this.setState({ name: ev.target.value });
};

private onNameValidate = async (fieldState: IFieldState) => {
const result = await TchapCreateRoomDialog.validateRoomName(fieldState);
this.setState({ nameIsValid: result.valid });
return result;
};

private static validateRoomName = withValidation({
rules: [
{
key: "required",
test: async ({ value }) => !!value,
invalid: () => _t("Please enter a name for the room"),
},
],
});

private onKeyDown = (event: KeyboardEvent) => {
const action = getKeyBindingsManager().getAccessibilityAction(event);
switch (action) {
case KeyBindingAction.Enter:
this.onOk();
event.preventDefault();
event.stopPropagation();
break;
}
};

private onOk = async () => {
const activeElement = document.activeElement as HTMLElement;
if (activeElement) {
activeElement.blur();
}
await this.nameField.current.validate({ allowEmpty: false });
// Validation and state updates are async, so we need to wait for them to complete
// first. Queue a `setState` callback and wait for it to resolve.
await new Promise<void>(resolve => this.setState({}, resolve));
if (this.state.nameIsValid) {
this.props.onFinished(true, roomCreateOptions(
this.state.name,
this.state.tchapRoomType,
this.state.isFederated));
} else {
let field;
if (!this.state.nameIsValid) {
field = this.nameField.current;
}
if (field) {
field.focus();
field.validate({ allowEmpty: false, focused: true });
}
}
};

render() {
const Field = sdk.getComponent("elements.Field");
const DialogButtons = sdk.getComponent("elements.DialogButtons");
const BaseDialog = sdk.getComponent("dialogs.BaseDialog");

const shortDomain: string = TchapUtils.getShortDomain();

const title = _t("Create a room");

return (
<BaseDialog
className="tc_TchapCreateRoomDialog"
onFinished={this.props.onFinished}
title={title}
screenName="CreateRoom"
>
<form onSubmit={this.onOk} onKeyDown={this.onKeyDown}>
<div className="mx_Dialog_content">
<Field
ref={this.nameField}
label={_t('Name')}
onChange={this.onNameChange}
onValidate={this.onNameValidate}
value={this.state.name}
/>

<TchapRoomTypeSelector
onChange={this.onTchapRoomTypeChange}
value={this.state.tchapRoomType}
label={_t("Type of room")}
showFederateSwitch={this.state.showFederateSwitch}
shortDomain={shortDomain}
isFederated={this.state.isFederated}
onFederatedChange={this.onFederatedChange}
/>

</div>
</form>
<DialogButtons primaryButton={_t('Create Room')}
onPrimaryButtonClick={this.onOk}
onCancel={this.onCancel} />
</BaseDialog>
);
}
}
Loading

0 comments on commit 5ed99d7

Please sign in to comment.