diff --git a/jams-react-client/package.json b/jams-react-client/package.json index fb6bc9626f11b6a47e3bc8d115990bf039ddad52..62dce8f551394158335b1a46a00ab43db4d8b3f8 100644 --- a/jams-react-client/package.json +++ b/jams-react-client/package.json @@ -46,9 +46,9 @@ "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject", "install:clean": "rm -rf node_modules/ && rm -rf package-lock.json && npm install && npm start", - "format": "prettier --write --loglevel warn 'src/**/*.js'", - "lint:check": "eslint . --ext=js,jsx; exit 0", - "lint:fix": "eslint . --ext=js,jsx --fix; exit 0", + "format": "prettier --write --loglevel warn 'src/**/*.{js,jsx,ts,tsx}'", + "lint:check": "eslint . --ext=js,jsx,ts,tsx; exit 0", + "lint:fix": "eslint . --ext=js,jsx,ts,tsx --fix; exit 0", "build-package-css": "cp src/assets/css/material-dashboard-react.css dist/material-dashboard-react.css", "build-package": "npm run build-package-css && babel src --out-dir dist" }, diff --git a/jams-react-client/src/components/CustomUiPreview/CustomUiPreview.tsx b/jams-react-client/src/components/CustomUiPreview/CustomUiPreview.tsx index cc339aa248cabb4e3d1b48ff34ea4d1e57f634c3..598aa8afb506d993fa69bc22e767c9bbe11704b9 100644 --- a/jams-react-client/src/components/CustomUiPreview/CustomUiPreview.tsx +++ b/jams-react-client/src/components/CustomUiPreview/CustomUiPreview.tsx @@ -1,16 +1,16 @@ -import React from "react"; +import React, { FC } from "react"; import { makeStyles } from "@mui/styles"; import backgroundImage from "assets/img/BG-ID_Jami.png"; import logoImage from "assets/img/favicon_jami.png"; -import TipBox from "./TipBox"; -import JamiIdCard from "./JamiIdCard"; +import { TipBox } from "./TipBox"; +import { JamiIdCard } from "./JamiIdCard"; import i18next from "i18next"; -import { url_path } from "../../globalUrls"; -import { url_port } from "../../globalUrls"; +import { url_path, url_port } from "../../globalUrls"; import { luma } from "./luma"; +import { UiCustomization } from "views/Blueprint/policyData.constants"; const styles = { root: { @@ -102,11 +102,17 @@ const styles = { const useStyles = makeStyles(styles); -export default function CustomUiPreview({ +interface CustomUiPreviewProps { + isOldPreview: boolean; + opacity: number; + uiCustomization: UiCustomization; +} + +export const CustomUiPreview: FC<CustomUiPreviewProps> = ({ isOldPreview, opacity, uiCustomization, -}) { +}) => { let { hasTitle, title, @@ -199,4 +205,4 @@ export default function CustomUiPreview({ </div> </div> ); -} +}; diff --git a/jams-react-client/src/components/CustomUiPreview/JamiIdCard.tsx b/jams-react-client/src/components/CustomUiPreview/JamiIdCard.tsx index 0b13fee765e70283ec3ba7853120a5136ea1f954..67e92474363972ae172bb9951475153038d73557 100644 --- a/jams-react-client/src/components/CustomUiPreview/JamiIdCard.tsx +++ b/jams-react-client/src/components/CustomUiPreview/JamiIdCard.tsx @@ -1,11 +1,10 @@ -import React from "react"; +import React, { FC } from "react"; import { makeStyles } from "@mui/styles"; import jamiIdImage from "assets/img/jami_id.svg"; import copySvg from "assets/img/BTN_Copy.svg"; import shareSvg from "assets/img/BTN_Share.svg"; -import { infoColor } from "assets/jss/material-dashboard-react"; import { luma } from "./luma"; const styles = { @@ -59,7 +58,15 @@ const styles = { const useStyles = makeStyles(styles); -export default function JamiIdCard({ color, isCompactDisplay }) { +interface JamiIdCardProps { + color: string; + isCompactDisplay: boolean; +} + +export const JamiIdCard: FC<JamiIdCardProps> = ({ + color, + isCompactDisplay, +}) => { const classes = useStyles({ color, isCompactDisplay }); return ( @@ -74,4 +81,4 @@ export default function JamiIdCard({ color, isCompactDisplay }) { </div> </div> ); -} +}; diff --git a/jams-react-client/src/components/CustomUiPreview/TipBox.tsx b/jams-react-client/src/components/CustomUiPreview/TipBox.tsx index d3961cee4e182c3d0c5bf802b10fa1e8f24e6a56..bd6061c1235103747521d47dc6efe9bd3c5f7277 100644 --- a/jams-react-client/src/components/CustomUiPreview/TipBox.tsx +++ b/jams-react-client/src/components/CustomUiPreview/TipBox.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { FC } from "react"; import { makeStyles } from "@mui/styles"; import tipLightBulbImage from "assets/img/tip_light_bulb.svg"; @@ -30,7 +30,12 @@ const styles = { const useStyles = makeStyles(styles); -export default function TipBox({ color, text }) { +interface TipBoxProps { + color: string; + text: string; +} + +export const TipBox: FC<TipBoxProps> = ({ color, text }) => { const fontColor = luma(color) ? "#ffffff" : "#000000"; const classes = useStyles({ color, fontColor }); @@ -42,4 +47,4 @@ export default function TipBox({ color, text }) { <p className={classes.text}>{text}</p> </div> ); -} +}; diff --git a/jams-react-client/src/components/CustomUiPreview/luma.tsx b/jams-react-client/src/components/CustomUiPreview/luma.tsx index f91d3e228e6d3db6c3ae06db129316a8d599dfcb..34de2d09df76c91a01d51482fe41fe7c898817c5 100644 --- a/jams-react-client/src/components/CustomUiPreview/luma.tsx +++ b/jams-react-client/src/components/CustomUiPreview/luma.tsx @@ -1,4 +1,4 @@ -export const luma = (color) => { +export const luma = (color: string) => { const r = parseInt(color.slice(1, 3), 16); const g = parseInt(color.slice(3, 5), 16); const b = parseInt(color.slice(5, 7), 16); diff --git a/jams-react-client/src/components/Snackbar/BlueprintSnackbar.tsx b/jams-react-client/src/components/Snackbar/BlueprintSnackbar.tsx index 35b586fd4bcb18c857adc72b557abe0b361c8802..454d521e8ccdd90c6781ed8c90c4beb8e9684c0d 100644 --- a/jams-react-client/src/components/Snackbar/BlueprintSnackbar.tsx +++ b/jams-react-client/src/components/Snackbar/BlueprintSnackbar.tsx @@ -1,9 +1,9 @@ -import React from "react"; -import PropTypes from "prop-types"; +import React, { Dispatch, FC, SetStateAction } from "react"; import MuiAlert from "@mui/material/Alert"; import Snackbar from "@mui/material/Snackbar"; import Slide from "@mui/material/Slide"; +import { SnackbarProps } from "views/Blueprint/PolicyDataContext"; // https://stackoverflow.com/a/67961603 const Alert = React.forwardRef(function Alert(props, ref) { @@ -14,7 +14,15 @@ const SlideTransition = React.forwardRef(function SlideTransition(props, ref) { return <Slide ref={ref} {...props} direction="left" />; }); -export default function BlueprintSnackbar({ snackbar, setSnackbar }) { +interface BlueprintSnackbarProps { + snackbar: SnackbarProps; + setSnackbar: Dispatch<SetStateAction<SnackbarProps>>; +} + +export const BlueprintSnackbar: FC<BlueprintSnackbarProps> = ({ + snackbar, + setSnackbar, +}) => { const snackbarRef = React.createRef(null); const handleClose = () => { @@ -36,9 +44,4 @@ export default function BlueprintSnackbar({ snackbar, setSnackbar }) { </Alert> </Snackbar> ); -} - -BlueprintSnackbar.propTypes = { - snackbar: PropTypes.object, - setSnackbar: PropTypes.func, }; diff --git a/jams-react-client/src/routes/BlueprintRoute.tsx b/jams-react-client/src/routes/BlueprintRoute.tsx index cc9834d959772a0e61684ba53985a80decac05cc..33e3394b0b76e1b5a248896a5298afd08af3451b 100644 --- a/jams-react-client/src/routes/BlueprintRoute.tsx +++ b/jams-react-client/src/routes/BlueprintRoute.tsx @@ -1,7 +1,7 @@ import React from "react"; import BaseLayout from "layouts/BaseLayout"; -import Blueprint from "views/Blueprint/Blueprint"; +import { Blueprint } from "views/Blueprint/Blueprint"; export default function BlueprintRoute(props) { return ( diff --git a/jams-react-client/src/views/Blueprint/Blueprint.tsx b/jams-react-client/src/views/Blueprint/Blueprint.tsx index 441a2f4331ae820d9cb11ffb503c0849b816c443..d8d64f0b84690264f2dac8e6fd24a8c29df2d2e6 100644 --- a/jams-react-client/src/views/Blueprint/Blueprint.tsx +++ b/jams-react-client/src/views/Blueprint/Blueprint.tsx @@ -1,6 +1,5 @@ -import React, { useState } from "react"; +import React, { FC, useState } from "react"; -import PropTypes from "prop-types"; import AppBar from "@mui/material/AppBar"; import Tabs from "@mui/material/Tabs"; import Tab from "@mui/material/Tab"; @@ -14,9 +13,13 @@ import { PolicyDataContextProvider } from "./PolicyDataContext"; import i18next from "i18next"; -function TabPanel(props) { - const { children, value, index, ...other } = props; +interface TabPanelProps { + children?: React.ReactNode; + index: number; + value: number; +} +const TabPanel: FC<TabPanelProps> = ({ children, value, index, ...other }) => { return ( <div role="tabpanel" @@ -32,15 +35,9 @@ function TabPanel(props) { )} </div> ); -} - -TabPanel.propTypes = { - children: PropTypes.node, - index: PropTypes.any.isRequired, - value: PropTypes.any.isRequired, }; -const a11yProps = (value, index) => { +const a11yProps = (value: number, index: number) => { return { id: `simple-tab-${index}`, "aria-controls": `simple-tabpanel-${index}`, @@ -48,10 +45,14 @@ const a11yProps = (value, index) => { }; }; -export default function Blueprint({ blueprintName }) { +interface BlueprintProps { + blueprintName: string; +} + +export const Blueprint: FC<BlueprintProps> = ({ blueprintName }) => { const [openedTab, setOpenedTab] = useState(0); - const handleChange = (event, newValue) => { + const handleChange = (event, newValue: number) => { setOpenedTab(newValue); }; @@ -93,4 +94,4 @@ export default function Blueprint({ blueprintName }) { </PolicyDataContextProvider> </div> ); -} +}; diff --git a/jams-react-client/src/views/Blueprint/EditBlueprintConfiguration.tsx b/jams-react-client/src/views/Blueprint/EditBlueprintConfiguration.tsx index 2fc0d60c4260be4a9119c25c6be53a3937a04202..869dc68c97a497d22ee082764c8ff1bb2c7ca3df 100644 --- a/jams-react-client/src/views/Blueprint/EditBlueprintConfiguration.tsx +++ b/jams-react-client/src/views/Blueprint/EditBlueprintConfiguration.tsx @@ -38,7 +38,7 @@ import i18next from "i18next"; import dashboardStyle from "assets/jss/material-dashboard-react/views/dashboardStyle"; import { hexToRgb, blackColor } from "assets/jss/material-dashboard-react"; -import BlueprintSnackbar from "components/Snackbar/BlueprintSnackbar"; +import { BlueprintSnackbar } from "components/Snackbar/BlueprintSnackbar"; import CustomPopupState from "components/CustomPopupState/CustomPopupState"; import { PolicyDataContext } from "./PolicyDataContext"; diff --git a/jams-react-client/src/views/Blueprint/EditBlueprintPermissions.tsx b/jams-react-client/src/views/Blueprint/EditBlueprintPermissions.tsx index 9ab64a98d57e2959ada789fa8dcaf791177d4e3e..0b0b0632cc7c89c17f9b95c43e057441be2b4a1f 100644 --- a/jams-react-client/src/views/Blueprint/EditBlueprintPermissions.tsx +++ b/jams-react-client/src/views/Blueprint/EditBlueprintPermissions.tsx @@ -22,7 +22,7 @@ import TableCell from "@mui/material/TableCell"; import AddCircleOutlineIcon from "@mui/icons-material/AddCircleOutline"; import PriorityHighOutlinedIcon from "@mui/icons-material/PriorityHighOutlined"; -import BlueprintSnackbar from "components/Snackbar/BlueprintSnackbar"; +import { BlueprintSnackbar } from "components/Snackbar/BlueprintSnackbar"; import Button from "components/CustomButtons/Button"; import Card from "components/Card/Card"; import CardBody from "components/Card/CardBody"; diff --git a/jams-react-client/src/views/Blueprint/EditBlueprintUi.tsx b/jams-react-client/src/views/Blueprint/EditBlueprintUi.tsx index 82c0b8a8677c07f6822daaa292b8f2c42be14b9d..1d62ef66cc1057f13b2bc3d9e12f3ac6cf2d0787 100644 --- a/jams-react-client/src/views/Blueprint/EditBlueprintUi.tsx +++ b/jams-react-client/src/views/Blueprint/EditBlueprintUi.tsx @@ -4,7 +4,7 @@ import { makeStyles } from "@mui/styles"; import Grid from "@mui/material/Grid"; import SettingsIcon from "@mui/icons-material/Settings"; -import BlueprintSnackbar from "components/Snackbar/BlueprintSnackbar"; +import { BlueprintSnackbar } from "components/Snackbar/BlueprintSnackbar"; import Card from "components/Card/Card"; import CardHeader from "components/Card/CardHeader"; import CardIcon from "components/Card/CardIcon"; @@ -25,7 +25,7 @@ import dashboardStyle from "assets/jss/material-dashboard-react/views/dashboardS import i18next from "i18next"; -import CustomUiPreview from "components/CustomUiPreview/CustomUiPreview"; +import { CustomUiPreview } from "components/CustomUiPreview/CustomUiPreview"; import EditBlueprintUiForm from "./EditBlueprintUiForm"; import { DEFAULT_UI_CUSTOMIZATION } from "./policyData.constants"; import { PolicyDataContext } from "./PolicyDataContext"; @@ -109,7 +109,7 @@ export default function EditBlueprintUi({ blueprintName }) { const [oldUiCustomization, setOldUiCustomization] = useState(uiCustomization); const [opacity, setOpacity] = useState(0); - const handleUpdateUi = (field, value) => { + const handleUpdateUi = (field: string, value: any) => { let newUiCustomization; if (typeof field === "object") { @@ -146,7 +146,7 @@ export default function EditBlueprintUi({ blueprintName }) { updatePolicyData("uiCustomization", newUiCustomization); }; - const handleImgDrop = (acceptedFiles, imgType) => { + const handleImgDrop = (acceptedFiles: string[], imgType: string) => { const formData = new FormData(); formData.append("file", acceptedFiles[0]); diff --git a/jams-react-client/src/views/Blueprint/PolicyDataContext.tsx b/jams-react-client/src/views/Blueprint/PolicyDataContext.tsx index 131db22a65d9030d40fa4d6d34e1949f45582a25..3a642e6fac3111a98a9df3eea2217fe456819de1 100644 --- a/jams-react-client/src/views/Blueprint/PolicyDataContext.tsx +++ b/jams-react-client/src/views/Blueprint/PolicyDataContext.tsx @@ -1,4 +1,10 @@ -import React, { createContext, useEffect, useState } from "react"; +import React, { + FC, + ReactNode, + createContext, + useEffect, + useState, +} from "react"; import axios from "axios"; @@ -6,11 +12,32 @@ import configApiCall from "../../api"; import { api_path_blueprints } from "../../globalUrls"; import { parsePolicyData } from "./parsePolicyData"; import { _updatePolicyData } from "./updatePolicyData"; -import { DEFAULT_POLICY_DATA } from "./policyData.constants"; +import { DEFAULT_POLICY_DATA, PolicyData } from "./policyData.constants"; -export const PolicyDataContext = createContext(null); +export interface SnackbarProps { + open: boolean; + severity: "success" | "error"; + message: string; +} -export const PolicyDataContextProvider = ({ blueprintName, children }) => { +interface PolicyDataProp { + policyData: PolicyData; + updatePolicyData: (field: string, value: string) => void; + snackbar: SnackbarProps; + setSnackbar: (snackbar: SnackbarProps) => void; +} + +export const PolicyDataContext = createContext<PolicyDataProp>(null); + +interface Props { + blueprintName: string; + children: ReactNode; +} + +export const PolicyDataContextProvider: FC<Props> = ({ + blueprintName, + children, +}) => { const [policyData, setPolicyData] = useState(DEFAULT_POLICY_DATA); const [snackbar, setSnackbar] = useState({ open: false, @@ -40,7 +67,7 @@ export const PolicyDataContextProvider = ({ blueprintName, children }) => { }); }, [blueprintName]); - const updatePolicyData = (field, value) => { + const updatePolicyData = (field: string, value: string) => { _updatePolicyData( blueprintName, policyData, diff --git a/jams-react-client/src/views/Blueprint/ServerUiCustomization.tsx b/jams-react-client/src/views/Blueprint/ServerUiCustomization.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c72714181806214557b9e6d2d1e67a841883011a --- /dev/null +++ b/jams-react-client/src/views/Blueprint/ServerUiCustomization.tsx @@ -0,0 +1,26 @@ +export interface ServerUiCustomization { + /** if the title is undefined, we show the default title */ + title?: string; + /** if the description is undefined, we show the default description */ + description?: string; + areTipsEnabled: boolean; + + backgroundType: "color" | "image" | "default"; + /** only defined if backgroundType !== "default" */ + backgroundColorOrUrl?: string; + /** + * if this field is undefined, we show the default value + * The color is in argb format + */ + tipBoxAndIdColor?: string; + + /** + * if this field is undefined, we show the default value + * The color is in argb format + */ + mainBoxColor?: string; + + logoUrl?: string; + /** The logo size from 0 to 100. 100% if left undefined */ + logoSize?: number; +} diff --git a/jams-react-client/src/views/Blueprint/parsePolicyData.tsx b/jams-react-client/src/views/Blueprint/parsePolicyData.tsx index 25b5e1a72a779003aa26f65ad0e1f75dad9e541d..dde06e90354f3518561df3eea2181292270c5b6a 100644 --- a/jams-react-client/src/views/Blueprint/parsePolicyData.tsx +++ b/jams-react-client/src/views/Blueprint/parsePolicyData.tsx @@ -5,9 +5,9 @@ import { api_path_get_ns_name_from_addr, api_path_get_user_profile, } from "../../globalUrls"; -import { DEFAULT_UI_CUSTOMIZATION } from "./policyData.constants"; +import { DEFAULT_UI_CUSTOMIZATION, PolicyData } from "./policyData.constants"; -const getModerators = async (defaultModerators) => { +const getModerators = async (defaultModerators: string) => { const moderators = []; const ids = defaultModerators.split("/").filter((id) => id !== ""); @@ -60,7 +60,7 @@ const setConfigurationSettings = (policyData) => { return policyData; }; -const convertArgbToRgba = (argb) => { +const convertArgbToRgba = (argb: string) => { if (argb.length === 7) { return argb; } @@ -114,7 +114,7 @@ const setCustomizationSettings = (policyData) => { return policyData; }; -export const parsePolicyData = async (data) => { +export const parsePolicyData = async (data: string): Promise<PolicyData> => { let policyData = JSON.parse(data); policyData = await setPermissionsSettings(policyData); diff --git a/jams-react-client/src/views/Blueprint/policyData.constants.tsx b/jams-react-client/src/views/Blueprint/policyData.constants.tsx index e90b9b0bbfb14e040a1f8d3e571412c17af28078..9e204d59af4178b3c6b079067c786671b4c692e0 100644 --- a/jams-react-client/src/views/Blueprint/policyData.constants.tsx +++ b/jams-react-client/src/views/Blueprint/policyData.constants.tsx @@ -19,6 +19,8 @@ export const DEFAULT_UI_CUSTOMIZATION = { logoSize: 100, }; +export type UiCustomization = typeof DEFAULT_UI_CUSTOMIZATION; + export const DEFAULT_POLICY_DATA = { videoEnabled: true, publicInCalls: false, @@ -42,3 +44,5 @@ export const DEFAULT_POLICY_DATA = { uiCustomization: DEFAULT_UI_CUSTOMIZATION, }; + +export type PolicyData = typeof DEFAULT_POLICY_DATA; diff --git a/jams-react-client/src/views/Blueprint/updatePolicyData.tsx b/jams-react-client/src/views/Blueprint/updatePolicyData.tsx index 6b6368bf57b3534529a4b03014dd5faec7df49db..85df6b6a2e4cb327ddec3d46aa029dbe266ecdb8 100644 --- a/jams-react-client/src/views/Blueprint/updatePolicyData.tsx +++ b/jams-react-client/src/views/Blueprint/updatePolicyData.tsx @@ -4,9 +4,12 @@ import i18next from "i18next"; import configApiCall from "api"; import { api_path_blueprints } from "globalUrls"; import { debounce } from "lodash"; -import { DEFAULT_UI_CUSTOMIZATION } from "./policyData.constants"; +import { DEFAULT_UI_CUSTOMIZATION, PolicyData } from "./policyData.constants"; +import { Dispatch, SetStateAction } from "react"; +import { SnackbarProps } from "./PolicyDataContext"; +import { ServerUiCustomization } from "./ServerUiCustomization"; -const updatePerms = (data, field, value) => { +const updatePerms = (data, field: string, value: any) => { data.defaultModerators = data.blueprintModerators .map((moderator) => moderator.id) .join("/"); @@ -51,7 +54,7 @@ const updateConfig = (data) => { return data; }; -const convertRgbaToArgb = (rgba) => { +const convertRgbaToArgb = (rgba: string) => { if (rgba.length === 7) { return rgba; } @@ -59,7 +62,7 @@ const convertRgbaToArgb = (rgba) => { throw new Error(`Invalid rgba value: "${rgba}}"`); } - return "#" + rgba.substr(7, 2) + rgba.substr(1, 6); + return "#" + rgba.substring(7, 9) + rgba.substring(1, 7); }; const updateUiCustomization = (data) => { @@ -135,7 +138,11 @@ const updateUiCustomization = (data) => { return data; }; -const sendPutRequest = (blueprintName, data, setSnackbar) => { +const sendPutRequest = ( + blueprintName: string, + data: ServerUiCustomization, + setSnackbar: (snackbar: SnackbarProps) => void +) => { console.log("PUT", data); axios( @@ -175,21 +182,23 @@ const debouncedSendPutRequest = debounce(sendPutRequest, 200, { }); export const _updatePolicyData = ( - blueprintName, - policyData, - setPolicyData, - field, - value, - setSnackbar + blueprintName: string, + policyData: PolicyData, + setPolicyData: Dispatch<SetStateAction<PolicyData>>, + field: string, + value: string, + setSnackbar: (snackbar: any) => void ) => { setPolicyData((state) => ({ ...state, [field]: value })); - let data = { ...policyData, [field]: value }; + let data: any = { ...policyData, [field]: value }; data = updatePerms(data, field, value); data = updateConfig(data); data = updateUiCustomization(data); + const ui: ServerUiCustomization = data; + console.log("updatePolicyData", { field, value }); - debouncedSendPutRequest(blueprintName, data, setSnackbar); + debouncedSendPutRequest(blueprintName, ui, setSnackbar); };