mirror of
https://github.com/jambonz/jambonz-webapp.git
synced 2025-12-19 05:37:43 +00:00
263 lines
7.0 KiB
TypeScript
263 lines
7.0 KiB
TypeScript
import React, { useEffect, useState, useMemo } from "react";
|
|
import { classNames, M, Icon, Button } from "@jambonz/ui-kit";
|
|
import { Link, useLocation, useNavigate } from "react-router-dom";
|
|
|
|
import { Icons, ModalForm } from "src/components";
|
|
import { naviTop, naviByo } from "./items";
|
|
import { UserMe } from "../user-me";
|
|
import {
|
|
useSelectState,
|
|
useDispatch,
|
|
toastSuccess,
|
|
toastError,
|
|
} from "src/store";
|
|
import { getActiveSP, setActiveSP } from "src/store/localStore";
|
|
import { postServiceProviders } from "src/api";
|
|
|
|
import type { NaviItem } from "./items";
|
|
|
|
import "./styles.scss";
|
|
import { ScopedAccess } from "src/components/scoped-access";
|
|
import { Scope, UserData } from "src/store/types";
|
|
import { USER_ADMIN } from "src/api/constants";
|
|
import { ROUTE_LOGIN } from "src/router/routes";
|
|
import { Lcr } from "src/api/types";
|
|
|
|
type CommonProps = {
|
|
handleMenu: () => void;
|
|
};
|
|
|
|
type NaviProps = CommonProps & {
|
|
mobile: boolean;
|
|
className: string;
|
|
handleLogout: () => void;
|
|
};
|
|
|
|
type ItemProps = CommonProps & {
|
|
item: NaviItem;
|
|
user?: UserData;
|
|
lcr?: Lcr;
|
|
};
|
|
|
|
const Item = ({ item, user, lcr, handleMenu }: ItemProps) => {
|
|
const location = useLocation();
|
|
const active = location.pathname.includes(item.route(user));
|
|
|
|
return (
|
|
<li>
|
|
<Link
|
|
to={item.route(user, lcr)}
|
|
className={classNames({ navi__link: true, "txt--jean": true, active })}
|
|
onClick={handleMenu}
|
|
>
|
|
<item.icon />
|
|
<span>{item.label}</span>
|
|
</Link>
|
|
</li>
|
|
);
|
|
};
|
|
|
|
export const Navi = ({
|
|
mobile,
|
|
className,
|
|
handleMenu,
|
|
handleLogout,
|
|
}: NaviProps) => {
|
|
const dispatch = useDispatch();
|
|
const navigate = useNavigate();
|
|
const user = useSelectState("user");
|
|
const lcr = useSelectState("lcr");
|
|
const accessControl = useSelectState("accessControl");
|
|
const serviceProviders = useSelectState("serviceProviders");
|
|
const currentServiceProvider = useSelectState("currentServiceProvider");
|
|
const [sid, setSid] = useState("");
|
|
const [modal, setModal] = useState(false);
|
|
const [name, setName] = useState("");
|
|
|
|
const naviByoFiltered = useMemo(() => {
|
|
return naviByo.filter(
|
|
(item) => !item.acl || (item.acl && accessControl[item.acl]),
|
|
);
|
|
}, [accessControl, currentServiceProvider]);
|
|
|
|
const naviTopFiltered = useMemo(() => {
|
|
return naviTop.filter((item) => {
|
|
if (item.scope === undefined) {
|
|
return true;
|
|
} else if (user) {
|
|
if (item.restrict) {
|
|
return user.access === item.scope;
|
|
}
|
|
|
|
return user.access >= item.scope;
|
|
}
|
|
});
|
|
}, [user]);
|
|
|
|
const handleSubmit = () => {
|
|
postServiceProviders({ name })
|
|
.then(({ json }) => {
|
|
toastSuccess(
|
|
<>
|
|
Added new service provider <strong>{name}</strong>
|
|
</>,
|
|
);
|
|
dispatch({ type: "serviceProviders" });
|
|
setSid(json.sid);
|
|
setActiveSP(json.sid);
|
|
setName("");
|
|
setModal(false);
|
|
})
|
|
.catch((error) => {
|
|
toastError(error.msg);
|
|
});
|
|
};
|
|
|
|
const handleCancel = () => {
|
|
setName("");
|
|
setModal(false);
|
|
};
|
|
|
|
/** Subscribe to change events on the service provider <select> */
|
|
useEffect(() => {
|
|
setSid(getActiveSP());
|
|
if (sid) {
|
|
const serviceProvider = serviceProviders.find(
|
|
(sp) => sp.service_provider_sid === sid,
|
|
);
|
|
|
|
if (serviceProvider) {
|
|
dispatch({ type: "currentServiceProvider", payload: serviceProvider });
|
|
}
|
|
}
|
|
}, [serviceProviders, sid]);
|
|
|
|
/** Fetch service providers */
|
|
useEffect(() => {
|
|
dispatch({ type: "user" });
|
|
dispatch({ type: "serviceProviders" });
|
|
dispatch({ type: "lcr" });
|
|
}, []);
|
|
|
|
return (
|
|
<>
|
|
<nav className={className}>
|
|
{mobile && (
|
|
<div className="navi__top">
|
|
<Icon subStyle="white" onClick={handleMenu}>
|
|
<Icons.X />
|
|
</Icon>
|
|
<UserMe />
|
|
<Button
|
|
small
|
|
mainStyle="hollow"
|
|
subStyle="white"
|
|
onClick={handleLogout}
|
|
>
|
|
Sign out
|
|
</Button>
|
|
</div>
|
|
)}
|
|
<div className="navi__sps">
|
|
<div className="smsel smsel--navi">
|
|
<div>
|
|
<select
|
|
value={sid || currentServiceProvider?.service_provider_sid}
|
|
onChange={(e) => {
|
|
setSid(e.target.value);
|
|
setActiveSP(e.target.value);
|
|
navigate(ROUTE_LOGIN);
|
|
}}
|
|
disabled={user?.scope !== USER_ADMIN}
|
|
>
|
|
{currentServiceProvider ? (
|
|
serviceProviders.map((serviceProvider) => {
|
|
return (
|
|
<option
|
|
value={serviceProvider.service_provider_sid}
|
|
key={serviceProvider.service_provider_sid}
|
|
>
|
|
{serviceProvider.name}
|
|
</option>
|
|
);
|
|
})
|
|
) : (
|
|
<option> </option>
|
|
)}
|
|
</select>
|
|
<span>
|
|
<Icons.ChevronUp />
|
|
<Icons.ChevronDown />
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<ScopedAccess scope={Scope.admin} user={user}>
|
|
<button
|
|
type="button"
|
|
onClick={() => setModal(true)}
|
|
title="Add service provider"
|
|
className="btnty"
|
|
>
|
|
<Icons.PlusCircle />
|
|
</button>
|
|
</ScopedAccess>
|
|
</div>
|
|
<div className="navi__routes">
|
|
<ul>
|
|
{naviTopFiltered.map((item) => {
|
|
return (
|
|
<Item
|
|
key={item.label}
|
|
user={user}
|
|
item={item}
|
|
handleMenu={handleMenu}
|
|
/>
|
|
);
|
|
})}
|
|
</ul>
|
|
</div>
|
|
<div className="navi__byo">
|
|
<M>BYO Services:</M>
|
|
</div>
|
|
<div className="navi__routes">
|
|
<ul>
|
|
{naviByoFiltered.map((item) => (
|
|
<Item
|
|
key={item.label}
|
|
user={user}
|
|
lcr={lcr}
|
|
item={item}
|
|
handleMenu={handleMenu}
|
|
/>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
<div className="navi__logo">
|
|
<img
|
|
src="/svg/jambonz--light.svg"
|
|
width="128"
|
|
height="42"
|
|
alt="jambonz"
|
|
/>
|
|
</div>
|
|
</nav>
|
|
{modal && (
|
|
<ModalForm handleSubmit={handleSubmit} handleCancel={handleCancel}>
|
|
<fieldset>
|
|
<label htmlFor="name">Add new service provider</label>
|
|
<input
|
|
id="name"
|
|
required
|
|
type="text"
|
|
name="name"
|
|
placeholder="Service provider name"
|
|
value={name}
|
|
onChange={(e) => setName(e.target.value)}
|
|
/>
|
|
</fieldset>
|
|
</ModalForm>
|
|
)}
|
|
</>
|
|
);
|
|
};
|