Fix more build errors
This commit is contained in:
parent
1bdc1e60db
commit
30ce47826f
61 changed files with 1161 additions and 541 deletions
|
|
@ -6,7 +6,6 @@ module.exports = {
|
|||
"eslint-config-link/profile/typescript",
|
||||
"eslint-config-link/profile/jest",
|
||||
"next",
|
||||
"unicorn/filename-case",
|
||||
],
|
||||
parserOptions: { tsconfigRootDir: __dirname },
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,22 +4,21 @@ import { signIn, signOut, getSession } from "next-auth/react";
|
|||
import { useLogin, useTranslate } from "react-admin";
|
||||
|
||||
export const authProvider = {
|
||||
login: (o: any) => {
|
||||
login(o: any) {
|
||||
if (o.ok) return Promise.resolve();
|
||||
return Promise.reject();
|
||||
},
|
||||
logout: async () => {
|
||||
async logout() {
|
||||
const session = await getSession();
|
||||
if (session) {
|
||||
await signOut();
|
||||
}
|
||||
},
|
||||
checkError: (e: any) => {
|
||||
checkError(e: any) {
|
||||
if (e.graphQLErrors && e.graphQLErrors.length > 0) {
|
||||
const permDenied =
|
||||
e.graphQLErrors.filter((e: any) =>
|
||||
e.message.match(/.*permission denied.*/)
|
||||
).length > 0;
|
||||
const permDenied = e.graphQLErrors.some((e: any) =>
|
||||
e.message.match(/.*permission denied.*/)
|
||||
);
|
||||
if (permDenied)
|
||||
// eslint-disable-next-line prefer-promise-reject-errors
|
||||
return Promise.reject({ message: "auth.permissionDenied" });
|
||||
|
|
@ -31,17 +30,15 @@ export const authProvider = {
|
|||
|
||||
return Promise.resolve();
|
||||
},
|
||||
checkAuth: async () => {
|
||||
async checkAuth() {
|
||||
const session = await getSession();
|
||||
if (!session) {
|
||||
return Promise.reject();
|
||||
throw new Error("Invalid session");
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
},
|
||||
getIdentity: async () => {
|
||||
async getIdentity() {
|
||||
const session = await getSession();
|
||||
if (!session) return Promise.reject(new Error("Invalid session"));
|
||||
if (!session) throw new Error("Invalid session");
|
||||
|
||||
return {
|
||||
id: session.user?.email,
|
||||
|
|
@ -59,10 +56,10 @@ export const AdminLogin: FC = () => {
|
|||
useEffect(() => {
|
||||
(async () => {
|
||||
const session = await getSession();
|
||||
if (!session) {
|
||||
signIn();
|
||||
} else {
|
||||
if (session) {
|
||||
reactAdminLogin({ ok: true });
|
||||
} else {
|
||||
signIn();
|
||||
}
|
||||
})();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export const Auth: FC = ({ children }) => {
|
|||
if (!session && !loading) {
|
||||
router.push("/login");
|
||||
}
|
||||
}, [session, loading]);
|
||||
}, [session, loading, router]);
|
||||
|
||||
if (loading) {
|
||||
return <CircularProgress />;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable react/display-name */
|
||||
import { forwardRef } from "react";
|
||||
import useDigitInput, { InputAttributes } from "react-digit-input";
|
||||
import styles from "./DigitInput.module.css";
|
||||
|
|
@ -7,36 +8,35 @@ const DigitInputElement = forwardRef<
|
|||
Omit<InputAttributes, "ref"> & {
|
||||
autoFocus?: boolean;
|
||||
}
|
||||
>(({ ...props }, ref) => {
|
||||
return (
|
||||
<>
|
||||
<input
|
||||
aria-label="verification code"
|
||||
className={styles.input}
|
||||
{...props}
|
||||
ref={ref}
|
||||
inputMode="decimal"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
>(({ ...props }, ref) => (
|
||||
<>
|
||||
<input
|
||||
aria-label="verification code"
|
||||
className={styles.input}
|
||||
{...props}
|
||||
ref={ref}
|
||||
inputMode="decimal"
|
||||
/>
|
||||
</>
|
||||
));
|
||||
|
||||
const DigitSeparator = forwardRef<
|
||||
HTMLInputElement,
|
||||
Omit<InputAttributes, "ref"> & {
|
||||
autoFocus?: boolean;
|
||||
}
|
||||
>(({ ...props }, ref) => {
|
||||
return (
|
||||
>(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
({ ...props }, ref) => (
|
||||
<>
|
||||
<span className={styles.hyphen} ref={ref} />
|
||||
</>
|
||||
);
|
||||
});
|
||||
)
|
||||
);
|
||||
|
||||
export const SixDigitInput = ({ value, onChange }: any) => {
|
||||
const digits = useDigitInput({
|
||||
acceptedCharacters: /^[0-9]$/,
|
||||
acceptedCharacters: /^\d$/,
|
||||
length: 6,
|
||||
value,
|
||||
onChange,
|
||||
|
|
|
|||
|
|
@ -18,11 +18,10 @@ import voiceProviders from "./voice/providers";
|
|||
import webhooks from "./webhooks";
|
||||
import { AdminLogin, authProvider } from "./AdminLogin";
|
||||
|
||||
const i18nProvider = polyglotI18nProvider((_locale) => {
|
||||
return englishMessages;
|
||||
}, "en");
|
||||
const i18nProvider = polyglotI18nProvider((_locale) => englishMessages, "en");
|
||||
|
||||
const MetamigoAdmin: FC = () => {
|
||||
// eslint-disable-next-line unicorn/no-null
|
||||
const [dataProvider, setDataProvider] = useState(null);
|
||||
const client = useApolloClient();
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ const AccountEditToolbar: FC<AccountEditToolbarProps> = (props: any) => {
|
|||
|
||||
const AccountTitle = ({ record }: { record?: any }) => {
|
||||
let title = "";
|
||||
if (record) title = record.name ? record.name : record.email;
|
||||
if (record) title = record.name ?? record.email;
|
||||
return <span>Account {title}</span>;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/* eslint-disable import/no-named-as-default */
|
||||
/* eslint-disable import/no-anonymous-default-export */
|
||||
import AccountIcon from "@material-ui/icons/AccountTree";
|
||||
import AccountList from "./AccountList";
|
||||
import AccountEdit from "./AccountEdit";
|
||||
|
||||
// eslint-disable-next-line import/no-anonymous-default-export
|
||||
export default {
|
||||
list: AccountList,
|
||||
edit: AccountEdit,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ const useStyles = makeStyles({
|
|||
},
|
||||
});
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const ConfigurationMenu = forwardRef<any, any>((props, ref) => {
|
||||
const translate = useTranslate();
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable import/no-named-as-default */
|
||||
import { Layout as RaLayout, LayoutProps, Sidebar } from "react-admin";
|
||||
import AppBar from "./AppBar";
|
||||
import Menu from "./Menu";
|
||||
|
|
@ -5,17 +6,15 @@ import { theme } from "./themes";
|
|||
|
||||
const CustomSidebar = (props: any) => <Sidebar {...props} size={200} />;
|
||||
|
||||
const Layout = (props: LayoutProps) => {
|
||||
return (
|
||||
<RaLayout
|
||||
{...props}
|
||||
appBar={AppBar}
|
||||
menu={Menu}
|
||||
sidebar={CustomSidebar}
|
||||
// @ts-ignore
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
const Layout = (props: LayoutProps) => (
|
||||
<RaLayout
|
||||
{...props}
|
||||
appBar={AppBar}
|
||||
menu={Menu}
|
||||
sidebar={CustomSidebar}
|
||||
// @ts-ignore
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
|
||||
export default Layout;
|
||||
|
|
|
|||
|
|
@ -1,106 +1,104 @@
|
|||
import { SVGProps } from "react";
|
||||
|
||||
const Logo = (props: SVGProps<SVGSVGElement>) => {
|
||||
return (
|
||||
<svg width="220.001" height="43.659" {...props}>
|
||||
<path d="M59.39 24.586h4.6v8.512c-1.058.2-3.743.57-5.742.57-6.398 0-7.74-3.77-7.74-11.452 0-7.827 1.4-11.54 7.797-11.54 3.627 0 8.597.828 8.597.828l.115-2.542s-4.885-1.056-9.083-1.056c-8.312 0-10.626 5.112-10.626 14.31 0 8.968 2.228 14.167 10.711 14.167 3.028 0 8.17-.8 8.998-.971V21.816H59.39zm13.14 11.397h2.998V21.302s3.514-1.943 7.284-2.714V15.56c-3.828.743-7.312 3.142-7.312 3.142v-2.713h-2.97zm27.962-13.967c0-4.342-1.913-6.427-6.455-6.427-3.427 0-7.826.885-7.826.885l.114 2.285s4.77-.542 7.57-.542c2.4 0 3.598 1 3.598 3.799v1.742l-6.284.6c-4.113.4-6.112 2.056-6.112 5.912 0 4.028 2 6.113 5.627 6.113 3.6 0 7.198-1.6 7.198-1.6 1.2 1.2 2.656 1.6 4.77 1.6l.114-2.37c-1.285-.144-2.228-.6-2.314-1.743zm-2.999 3.998v6.599s-3.313 1.256-6.284 1.256c-2.028 0-3.027-1.37-3.027-3.684 0-2.2.942-3.37 3.4-3.6zm17.738-10.425c-2.828 0-5.855 1.4-5.855 1.4V7.277h-2.97v28.677s4.283.429 6.683.429c7.283 0 9.425-2.77 9.425-10.711 0-7.198-1.828-10.083-7.283-10.083zm-2.2 18.109c-1.056 0-3.655-.2-3.655-.2V19.416s2.8-1.142 5.54-1.142c3.514 0 4.57 2.228 4.57 7.398 0 5.598-.97 8.026-6.454 8.026zm28.535-11.682c0-4.342-1.942-6.427-6.455-6.427-3.428 0-7.826.885-7.826.885l.114 2.285s4.77-.542 7.57-.542c2.4 0 3.598 1 3.598 3.799v1.742l-6.284.6c-4.113.4-6.112 2.056-6.112 5.912 0 4.028 2 6.113 5.626 6.113 3.6 0 7.198-1.6 7.198-1.6 1.2 1.2 2.628 1.6 4.77 1.6l.115-2.37c-1.286-.144-2.257-.6-2.314-1.743zm-3 3.998v6.599s-3.34 1.256-6.283 1.256c-2.057 0-3.056-1.37-3.056-3.684 0-2.2.97-3.37 3.4-3.6zm24.25-18.737h-2.94v8.826c-.6-.114-3.2-.514-4.914-.514-6.084 0-8.369 3.513-8.369 10.568 0 8.626 3.285 10.226 7.198 10.226 3 0 6.084-1.771 6.084-1.771v1.37h2.942zm-8.654 26.42c-2.37 0-4.484-1.084-4.484-7.54 0-5.198 1.228-7.97 5.427-7.97 1.657 0 4.113.373 4.77.487v13.539s-2.885 1.485-5.713 1.485zM176.3 15.59c-6.313 0-8.54 3.285-8.54 10.168 0 7.255 1.827 10.626 8.54 10.626 6.77 0 8.57-3.37 8.57-10.626 0-6.883-2.2-10.168-8.57-10.168zm0 18.195c-4.713 0-5.484-2.371-5.484-8.027 0-5.57 1.256-7.57 5.484-7.57 4.284 0 5.484 2 5.484 7.57 0 5.656-.714 8.027-5.484 8.027zm13.453 2.199h3V21.303s3.512-1.943 7.254-2.714V15.56c-3.828.743-7.312 3.142-7.312 3.142V15.99h-2.942zm27.934-13.967c0-4.342-1.913-6.427-6.426-6.427-3.456 0-7.855.885-7.855.885l.143 2.285s4.741-.542 7.54-.542c2.4 0 3.6 1 3.6 3.799v1.742l-6.285.6c-4.113.4-6.112 2.056-6.112 5.912 0 4.028 2 6.113 5.655 6.113 3.6 0 7.198-1.6 7.198-1.6 1.2 1.2 2.628 1.6 4.742 1.6l.114-2.37c-1.257-.144-2.228-.6-2.314-1.743zm-2.999 3.998v6.599s-3.313 1.256-6.284 1.256c-2.028 0-3.027-1.37-3.027-3.684 0-2.2.97-3.37 3.4-3.6z" />
|
||||
<defs>
|
||||
<linearGradient
|
||||
gradientTransform="rotate(25)"
|
||||
id="a"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0%" stopColor="#8C48D2" />
|
||||
<stop offset="100%" stopColor="#CF705A" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
xlinkHref="#a"
|
||||
id="c"
|
||||
gradientTransform="scale(.7746 1.291)"
|
||||
x1="15.492"
|
||||
y1="4.648"
|
||||
x2="23.238"
|
||||
y2="4.648"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
/>
|
||||
<linearGradient
|
||||
xlinkHref="#a"
|
||||
id="d"
|
||||
gradientTransform="scale(1.27 .7874)"
|
||||
x1="7.874"
|
||||
y1="15.24"
|
||||
x2="15.748"
|
||||
y2="15.24"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
/>
|
||||
<linearGradient
|
||||
xlinkHref="#a"
|
||||
id="e"
|
||||
gradientTransform="scale(.91287 1.09545)"
|
||||
x1="10.954"
|
||||
y1="7.303"
|
||||
x2="21.909"
|
||||
y2="7.303"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
/>
|
||||
<linearGradient
|
||||
xlinkHref="#a"
|
||||
id="f"
|
||||
gradientTransform="scale(1.13606 .88024)"
|
||||
x1="3.521"
|
||||
y1="13.576"
|
||||
x2="22.886"
|
||||
y2="13.576"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
/>
|
||||
<linearGradient
|
||||
xlinkHref="#a"
|
||||
id="g"
|
||||
gradientTransform="scale(1.029 .97183)"
|
||||
x1="5.831"
|
||||
y1="1.029"
|
||||
x2="23.324"
|
||||
y2="1.029"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
/>
|
||||
<linearGradient
|
||||
xlinkHref="#a"
|
||||
id="b"
|
||||
gradientTransform="scale(.88647 1.12807)"
|
||||
x1="4.512"
|
||||
y1=".886"
|
||||
x2="29.33"
|
||||
y2=".886"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
/>
|
||||
</defs>
|
||||
<g transform="translate(-6.238 -1.56) scale(1.55946)" fill="url(#b)">
|
||||
<path
|
||||
d="M12 9v4a3 3 0 006 0V9a3 3 0 00-6 0zm3-2a2 2 0 012 2v4a2 2 0 11-4 0V9a2 2 0 012-2z"
|
||||
fill="url(#c)"
|
||||
/>
|
||||
<path
|
||||
d="M10 13.2a5 5 0 0010 0v-.7a.5.5 0 10-1 0v.7a4 4 0 11-8 0v-.7a.5.5 0 10-1 0z"
|
||||
fill="url(#d)"
|
||||
/>
|
||||
<path
|
||||
d="M19.5 13a.5.5 0 100-1h-9a.5.5 0 100 1zm-3 6a.5.5 0 110 1h-3a.5.5 0 110-1h1v-1h1v1zm-3-10a.5.5 0 000-1h-1v1zm0 2a.5.5 0 000-1h-1v1zm3 0a.5.5 0 110-1h1v1zm0-2a.5.5 0 110-1h1v1z"
|
||||
fill="url(#e)"
|
||||
/>
|
||||
<path
|
||||
d="M25.947 14.272a.51.51 0 01.053.23v13.994a.5.5 0 01-.5.5h-21a.5.5 0 01-.5-.5V14.502a.502.502 0 01.2-.406L7 11.95v1.26l-2 1.533v1.253l6.667 5h6.666l6.667-5v-1.253l-2-1.533v-1.26l2.8 2.146a.502.502 0 01.147.176zM10.739 21.55L5 27.29V17.245l5.739 4.304zm.968.446h6.586l6 6H5.707zm7.554-.446L25 17.246V27.29l-5.739-5.739z"
|
||||
fill="url(#f)"
|
||||
/>
|
||||
<path
|
||||
d="M24 6.2a.5.5 0 00-.146-.354l-4.7-4.7A.5.5 0 0018.8 1H6.5a.5.5 0 00-.5.5V18h1V2h11v4.5a.5.5 0 00.5.5H23v11h1zM19 6V2.41L22.59 6z"
|
||||
fill="url(#g)"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
const Logo = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg width="220.001" height="43.659" {...props}>
|
||||
<path d="M59.39 24.586h4.6v8.512c-1.058.2-3.743.57-5.742.57-6.398 0-7.74-3.77-7.74-11.452 0-7.827 1.4-11.54 7.797-11.54 3.627 0 8.597.828 8.597.828l.115-2.542s-4.885-1.056-9.083-1.056c-8.312 0-10.626 5.112-10.626 14.31 0 8.968 2.228 14.167 10.711 14.167 3.028 0 8.17-.8 8.998-.971V21.816H59.39zm13.14 11.397h2.998V21.302s3.514-1.943 7.284-2.714V15.56c-3.828.743-7.312 3.142-7.312 3.142v-2.713h-2.97zm27.962-13.967c0-4.342-1.913-6.427-6.455-6.427-3.427 0-7.826.885-7.826.885l.114 2.285s4.77-.542 7.57-.542c2.4 0 3.598 1 3.598 3.799v1.742l-6.284.6c-4.113.4-6.112 2.056-6.112 5.912 0 4.028 2 6.113 5.627 6.113 3.6 0 7.198-1.6 7.198-1.6 1.2 1.2 2.656 1.6 4.77 1.6l.114-2.37c-1.285-.144-2.228-.6-2.314-1.743zm-2.999 3.998v6.599s-3.313 1.256-6.284 1.256c-2.028 0-3.027-1.37-3.027-3.684 0-2.2.942-3.37 3.4-3.6zm17.738-10.425c-2.828 0-5.855 1.4-5.855 1.4V7.277h-2.97v28.677s4.283.429 6.683.429c7.283 0 9.425-2.77 9.425-10.711 0-7.198-1.828-10.083-7.283-10.083zm-2.2 18.109c-1.056 0-3.655-.2-3.655-.2V19.416s2.8-1.142 5.54-1.142c3.514 0 4.57 2.228 4.57 7.398 0 5.598-.97 8.026-6.454 8.026zm28.535-11.682c0-4.342-1.942-6.427-6.455-6.427-3.428 0-7.826.885-7.826.885l.114 2.285s4.77-.542 7.57-.542c2.4 0 3.598 1 3.598 3.799v1.742l-6.284.6c-4.113.4-6.112 2.056-6.112 5.912 0 4.028 2 6.113 5.626 6.113 3.6 0 7.198-1.6 7.198-1.6 1.2 1.2 2.628 1.6 4.77 1.6l.115-2.37c-1.286-.144-2.257-.6-2.314-1.743zm-3 3.998v6.599s-3.34 1.256-6.283 1.256c-2.057 0-3.056-1.37-3.056-3.684 0-2.2.97-3.37 3.4-3.6zm24.25-18.737h-2.94v8.826c-.6-.114-3.2-.514-4.914-.514-6.084 0-8.369 3.513-8.369 10.568 0 8.626 3.285 10.226 7.198 10.226 3 0 6.084-1.771 6.084-1.771v1.37h2.942zm-8.654 26.42c-2.37 0-4.484-1.084-4.484-7.54 0-5.198 1.228-7.97 5.427-7.97 1.657 0 4.113.373 4.77.487v13.539s-2.885 1.485-5.713 1.485zM176.3 15.59c-6.313 0-8.54 3.285-8.54 10.168 0 7.255 1.827 10.626 8.54 10.626 6.77 0 8.57-3.37 8.57-10.626 0-6.883-2.2-10.168-8.57-10.168zm0 18.195c-4.713 0-5.484-2.371-5.484-8.027 0-5.57 1.256-7.57 5.484-7.57 4.284 0 5.484 2 5.484 7.57 0 5.656-.714 8.027-5.484 8.027zm13.453 2.199h3V21.303s3.512-1.943 7.254-2.714V15.56c-3.828.743-7.312 3.142-7.312 3.142V15.99h-2.942zm27.934-13.967c0-4.342-1.913-6.427-6.426-6.427-3.456 0-7.855.885-7.855.885l.143 2.285s4.741-.542 7.54-.542c2.4 0 3.6 1 3.6 3.799v1.742l-6.285.6c-4.113.4-6.112 2.056-6.112 5.912 0 4.028 2 6.113 5.655 6.113 3.6 0 7.198-1.6 7.198-1.6 1.2 1.2 2.628 1.6 4.742 1.6l.114-2.37c-1.257-.144-2.228-.6-2.314-1.743zm-2.999 3.998v6.599s-3.313 1.256-6.284 1.256c-2.028 0-3.027-1.37-3.027-3.684 0-2.2.97-3.37 3.4-3.6z" />
|
||||
<defs>
|
||||
<linearGradient
|
||||
gradientTransform="rotate(25)"
|
||||
id="a"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0%" stopColor="#8C48D2" />
|
||||
<stop offset="100%" stopColor="#CF705A" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
xlinkHref="#a"
|
||||
id="c"
|
||||
gradientTransform="scale(.7746 1.291)"
|
||||
x1="15.492"
|
||||
y1="4.648"
|
||||
x2="23.238"
|
||||
y2="4.648"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
/>
|
||||
<linearGradient
|
||||
xlinkHref="#a"
|
||||
id="d"
|
||||
gradientTransform="scale(1.27 .7874)"
|
||||
x1="7.874"
|
||||
y1="15.24"
|
||||
x2="15.748"
|
||||
y2="15.24"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
/>
|
||||
<linearGradient
|
||||
xlinkHref="#a"
|
||||
id="e"
|
||||
gradientTransform="scale(.91287 1.09545)"
|
||||
x1="10.954"
|
||||
y1="7.303"
|
||||
x2="21.909"
|
||||
y2="7.303"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
/>
|
||||
<linearGradient
|
||||
xlinkHref="#a"
|
||||
id="f"
|
||||
gradientTransform="scale(1.13606 .88024)"
|
||||
x1="3.521"
|
||||
y1="13.576"
|
||||
x2="22.886"
|
||||
y2="13.576"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
/>
|
||||
<linearGradient
|
||||
xlinkHref="#a"
|
||||
id="g"
|
||||
gradientTransform="scale(1.029 .97183)"
|
||||
x1="5.831"
|
||||
y1="1.029"
|
||||
x2="23.324"
|
||||
y2="1.029"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
/>
|
||||
<linearGradient
|
||||
xlinkHref="#a"
|
||||
id="b"
|
||||
gradientTransform="scale(.88647 1.12807)"
|
||||
x1="4.512"
|
||||
y1=".886"
|
||||
x2="29.33"
|
||||
y2=".886"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
/>
|
||||
</defs>
|
||||
<g transform="translate(-6.238 -1.56) scale(1.55946)" fill="url(#b)">
|
||||
<path
|
||||
d="M12 9v4a3 3 0 006 0V9a3 3 0 00-6 0zm3-2a2 2 0 012 2v4a2 2 0 11-4 0V9a2 2 0 012-2z"
|
||||
fill="url(#c)"
|
||||
/>
|
||||
<path
|
||||
d="M10 13.2a5 5 0 0010 0v-.7a.5.5 0 10-1 0v.7a4 4 0 11-8 0v-.7a.5.5 0 10-1 0z"
|
||||
fill="url(#d)"
|
||||
/>
|
||||
<path
|
||||
d="M19.5 13a.5.5 0 100-1h-9a.5.5 0 100 1zm-3 6a.5.5 0 110 1h-3a.5.5 0 110-1h1v-1h1v1zm-3-10a.5.5 0 000-1h-1v1zm0 2a.5.5 0 000-1h-1v1zm3 0a.5.5 0 110-1h1v1zm0-2a.5.5 0 110-1h1v1z"
|
||||
fill="url(#e)"
|
||||
/>
|
||||
<path
|
||||
d="M25.947 14.272a.51.51 0 01.053.23v13.994a.5.5 0 01-.5.5h-21a.5.5 0 01-.5-.5V14.502a.502.502 0 01.2-.406L7 11.95v1.26l-2 1.533v1.253l6.667 5h6.666l6.667-5v-1.253l-2-1.533v-1.26l2.8 2.146a.502.502 0 01.147.176zM10.739 21.55L5 27.29V17.245l5.739 4.304zm.968.446h6.586l6 6H5.707zm7.554-.446L25 17.246V27.29l-5.739-5.739z"
|
||||
fill="url(#f)"
|
||||
/>
|
||||
<path
|
||||
d="M24 6.2a.5.5 0 00-.146-.354l-4.7-4.7A.5.5 0 0018.8 1H6.5a.5.5 0 00-.5.5V18h1V2h11v4.5a.5.5 0 00.5.5H23v11h1zM19 6V2.41L22.59 6z"
|
||||
fill="url(#g)"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default Logo;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import VoiceIcon from "@material-ui/icons/PhoneInTalk";
|
|||
import { Box } from "@material-ui/core";
|
||||
import { useTheme } from "@material-ui/core/styles";
|
||||
import useMediaQuery from "@material-ui/core/useMediaQuery";
|
||||
import { useTranslate, MenuItemLink, MenuProps } from "react-admin";
|
||||
import { useTranslate, MenuItemLink } from "react-admin";
|
||||
import users from "../users";
|
||||
import accounts from "../accounts";
|
||||
import webhooks from "../webhooks";
|
||||
|
|
@ -33,9 +33,7 @@ export const Menu: FC = ({ onMenuClick, logout, dense = false }: any) => {
|
|||
setState((state) => ({ ...state, [menu]: !state[menu] }));
|
||||
};
|
||||
|
||||
return <div />;
|
||||
};
|
||||
/*
|
||||
return (
|
||||
<Box mt={1}>
|
||||
<MenuItemLink
|
||||
to={`/whatsappbots`}
|
||||
|
|
@ -129,5 +127,5 @@ export const Menu: FC = ({ onMenuClick, logout, dense = false }: any) => {
|
|||
</Box>
|
||||
);
|
||||
};
|
||||
*/
|
||||
|
||||
export default Menu;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import AppBar from "./AppBar";
|
||||
import Layout from "./Layout";
|
||||
import Menu from "./Menu";
|
||||
|
||||
export { AppBar, Layout, Menu };
|
||||
export {default as AppBar} from "./AppBar";
|
||||
export {default as Layout} from "./Layout";
|
||||
export {default as Menu} from "./Menu";
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ const VerificationCodeRequest = ({
|
|||
onFailure,
|
||||
});
|
||||
})();
|
||||
}, []);
|
||||
}, [data.id, onFailure, onSuccess, verifyMode]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -409,7 +409,7 @@ const VerificationCodeDialog = (props: any) => {
|
|||
);
|
||||
};
|
||||
|
||||
const SignalBotShowActions = ({ basePath, data }: any) => {
|
||||
const SignalBotShowActions = ({ data }: any) => {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [verifyMode, setVerifyMode] = React.useState("");
|
||||
const refresh = useRefresh();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable react/display-name */
|
||||
import {
|
||||
SelectInput,
|
||||
required,
|
||||
|
|
@ -6,19 +7,21 @@ import {
|
|||
TextField,
|
||||
} from "react-admin";
|
||||
|
||||
export const SignalBotSelectInput = (source: string) => () => (
|
||||
<ReferenceInput
|
||||
label="Signal Bot"
|
||||
source={source}
|
||||
reference="signalBots"
|
||||
validate={[required()]}
|
||||
>
|
||||
<SelectInput optionText="phoneNumber" />
|
||||
</ReferenceInput>
|
||||
);
|
||||
export const SignalBotSelectInput = (source: string) => () =>
|
||||
(
|
||||
<ReferenceInput
|
||||
label="Signal Bot"
|
||||
source={source}
|
||||
reference="signalBots"
|
||||
validate={[required()]}
|
||||
>
|
||||
<SelectInput optionText="phoneNumber" />
|
||||
</ReferenceInput>
|
||||
);
|
||||
|
||||
export const SignalBotField = (source: string) => () => (
|
||||
<ReferenceField label="Signal Bot" reference="signalBots" source={source}>
|
||||
<TextField source="phoneNumber" />
|
||||
</ReferenceField>
|
||||
);
|
||||
export const SignalBotField = (source: string) => () =>
|
||||
(
|
||||
<ReferenceField label="Signal Bot" reference="signalBots" source={source}>
|
||||
<TextField source="phoneNumber" />
|
||||
</ReferenceField>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ const UserEditToolbar = (props: any) => {
|
|||
<Toolbar className={classes.defaultToolbar} {...props}>
|
||||
<SaveButton
|
||||
label="save"
|
||||
mutationOptions={{ onSuccess: (response) => redirect("/users") }}
|
||||
mutationOptions={{ onSuccess: () => redirect("/users") }}
|
||||
/>
|
||||
<DeleteButton disabled={props.session.user.id === props.record.id} />
|
||||
</Toolbar>
|
||||
|
|
@ -39,7 +39,7 @@ const UserEditToolbar = (props: any) => {
|
|||
|
||||
const UserTitle = ({ record }: { record?: any }) => {
|
||||
let title = "";
|
||||
if (record) title = record.name ? record.name : record.email;
|
||||
if (record) title = record.name ?? record.email;
|
||||
return <span>User {title}</span>;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -7,27 +7,25 @@ import {
|
|||
} from "react-admin";
|
||||
import { ProviderKindInput } from "./shared";
|
||||
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
// import TextField from "@material-ui/core/TextField";
|
||||
|
||||
const TwilioCredentialsInput = () => (
|
||||
/* const TwilioCredentialsInput = () => (
|
||||
<span>
|
||||
<TextField name="accountSid" label="Account Sid" />
|
||||
<TextField name="authToken" label="Auth Token" />
|
||||
</span>
|
||||
); */
|
||||
|
||||
const ProviderCreate = (props: CreateProps) => (
|
||||
<Create {...props} title="Create Providers">
|
||||
<SimpleForm>
|
||||
<ProviderKindInput />
|
||||
<TextInput source="name" />
|
||||
<TextInput source="credentials.accountSid" />
|
||||
<TextInput source="credentials.apiKeySid" />
|
||||
<PasswordInput source="credentials.apiKeySecret" />
|
||||
</SimpleForm>
|
||||
</Create>
|
||||
);
|
||||
|
||||
const ProviderCreate = (props: CreateProps) => {
|
||||
return (
|
||||
<Create {...props} title="Create Providers">
|
||||
<SimpleForm>
|
||||
<ProviderKindInput />
|
||||
<TextInput source="name" />
|
||||
<TextInput source="credentials.accountSid" />
|
||||
<TextInput source="credentials.apiKeySid" />
|
||||
<PasswordInput source="credentials.apiKeySecret" />
|
||||
</SimpleForm>
|
||||
</Create>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProviderCreate;
|
||||
|
|
|
|||
|
|
@ -9,23 +9,21 @@ import { ProviderKindInput } from "./shared";
|
|||
|
||||
const ProviderTitle = ({ record }: { record?: any }) => {
|
||||
let title = "";
|
||||
if (record) title = record.name ? record.name : record.email;
|
||||
if (record) title = record.name ?? record.email;
|
||||
return <span>Provider {title}</span>;
|
||||
};
|
||||
|
||||
const ProviderEdit = (props: EditProps) => {
|
||||
return (
|
||||
<Edit title={<ProviderTitle />} {...props}>
|
||||
<SimpleForm>
|
||||
<TextInput disabled source="id" />
|
||||
<ProviderKindInput disabled />
|
||||
<TextInput source="name" />
|
||||
<TextInput source="credentials.accountSid" />
|
||||
<TextInput source="credentials.apiKeySid" />
|
||||
<PasswordInput source="credentials.apiKeySecret" />
|
||||
</SimpleForm>
|
||||
</Edit>
|
||||
);
|
||||
};
|
||||
const ProviderEdit = (props: EditProps) => (
|
||||
<Edit title={<ProviderTitle />} {...props}>
|
||||
<SimpleForm>
|
||||
<TextInput disabled source="id" />
|
||||
<ProviderKindInput disabled />
|
||||
<TextInput source="name" />
|
||||
<TextInput source="credentials.accountSid" />
|
||||
<TextInput source="credentials.apiKeySid" />
|
||||
<PasswordInput source="credentials.apiKeySecret" />
|
||||
</SimpleForm>
|
||||
</Edit>
|
||||
);
|
||||
|
||||
export default ProviderEdit;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable import/no-anonymous-default-export */
|
||||
import ProviderIcon from "@material-ui/icons/Business";
|
||||
import ProviderList from "./ProviderList";
|
||||
import ProviderEdit from "./ProviderEdit";
|
||||
|
|
|
|||
|
|
@ -8,14 +8,13 @@ import { makeStyles, useTheme } from "@material-ui/core/styles";
|
|||
import AudioPlayer from "material-ui-audio-player";
|
||||
import { useStopwatch } from "react-timer-hook";
|
||||
import style from "./MicInput.module.css";
|
||||
//import type { ReactMicProps } from "react-mic";
|
||||
// import type { ReactMicProps } from "react-mic";
|
||||
|
||||
const ReactMic = dynamic<any>(
|
||||
// eslint-disable-next-line promise/prefer-await-to-then
|
||||
() => {
|
||||
throw new Error(
|
||||
"MIC INPUT FEATURE IS DISABLED"
|
||||
); /*return import("react-mic").then((mod) => mod.ReactMic);*/
|
||||
); /* return import("react-mic").then((mod) => mod.ReactMic); */
|
||||
},
|
||||
{ ssr: false }
|
||||
);
|
||||
|
|
@ -58,7 +57,7 @@ const MicInput = (props: any) => {
|
|||
field: { value, onChange },
|
||||
} = useInput(props);
|
||||
|
||||
let [record, setRecorder] = useState({ record: false });
|
||||
const [record, setRecorder] = useState({ record: false });
|
||||
const decodedValue = resultToDataUri(value);
|
||||
const startRecording = () => {
|
||||
setRecorder({ record: true });
|
||||
|
|
@ -71,7 +70,9 @@ const MicInput = (props: any) => {
|
|||
pause();
|
||||
};
|
||||
|
||||
async function onData(recordedBlob: any) {}
|
||||
async function onData(recordedBlob: any) {
|
||||
console.log({ recordedBlob });
|
||||
}
|
||||
|
||||
async function onStop(recordedBlob: any) {
|
||||
const result = await blobToResult(recordedBlob.blob);
|
||||
|
|
@ -84,16 +85,14 @@ const MicInput = (props: any) => {
|
|||
.toString()
|
||||
.padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
|
||||
|
||||
const useStyles = makeStyles((theme) => {
|
||||
return {
|
||||
volumeIcon: {
|
||||
display: "none",
|
||||
},
|
||||
mainSlider: {
|
||||
display: "none",
|
||||
},
|
||||
};
|
||||
});
|
||||
const useStyles = makeStyles(() => ({
|
||||
volumeIcon: {
|
||||
display: "none",
|
||||
},
|
||||
mainSlider: {
|
||||
display: "none",
|
||||
},
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className="MuiFormControl-marginDense RaFormInput-input-40">
|
||||
|
|
|
|||
|
|
@ -17,38 +17,36 @@ import {
|
|||
} from "./shared";
|
||||
import MicInput from "./MicInput";
|
||||
|
||||
const VoiceLineCreate = (props: CreateProps) => {
|
||||
return (
|
||||
<Create {...props} title="Create Voice Line" transform={populateNumber}>
|
||||
<SimpleForm>
|
||||
<ReferenceInput
|
||||
label="Provider"
|
||||
source="providerId"
|
||||
reference="voiceProviders"
|
||||
validate={[required()]}
|
||||
>
|
||||
<SelectInput optionText={(p) => `${p.kind}: ${p.name}`} />
|
||||
</ReferenceInput>
|
||||
<FormDataConsumer subscription={{ values: true }}>
|
||||
{AvailableNumbersInput}
|
||||
</FormDataConsumer>
|
||||
<SelectInput
|
||||
source="language"
|
||||
choices={TwilioLanguages.languages}
|
||||
validate={[required()]}
|
||||
/>
|
||||
<FormDataConsumer subscription={{ values: true }}>
|
||||
{VoiceInput}
|
||||
</FormDataConsumer>
|
||||
const VoiceLineCreate = (props: CreateProps) => (
|
||||
<Create {...props} title="Create Voice Line" transform={populateNumber}>
|
||||
<SimpleForm>
|
||||
<ReferenceInput
|
||||
label="Provider"
|
||||
source="providerId"
|
||||
reference="voiceProviders"
|
||||
validate={[required()]}
|
||||
>
|
||||
<SelectInput optionText={(p) => `${p.kind}: ${p.name}`} />
|
||||
</ReferenceInput>
|
||||
<FormDataConsumer subscription={{ values: true }}>
|
||||
{AvailableNumbersInput}
|
||||
</FormDataConsumer>
|
||||
<SelectInput
|
||||
source="language"
|
||||
choices={TwilioLanguages.languages}
|
||||
validate={[required()]}
|
||||
/>
|
||||
<FormDataConsumer subscription={{ values: true }}>
|
||||
{VoiceInput}
|
||||
</FormDataConsumer>
|
||||
|
||||
<FormDataConsumer subscription={{ values: true }}>
|
||||
{PromptInput}
|
||||
</FormDataConsumer>
|
||||
<BooleanInput source="audioPromptEnabled" />
|
||||
<MicInput source="promptAudio" />
|
||||
</SimpleForm>
|
||||
</Create>
|
||||
);
|
||||
};
|
||||
<FormDataConsumer subscription={{ values: true }}>
|
||||
{PromptInput}
|
||||
</FormDataConsumer>
|
||||
<BooleanInput source="audioPromptEnabled" />
|
||||
<MicInput source="promptAudio" />
|
||||
</SimpleForm>
|
||||
</Create>
|
||||
);
|
||||
|
||||
export default VoiceLineCreate;
|
||||
|
|
|
|||
|
|
@ -15,37 +15,35 @@ import MicInput from "./MicInput";
|
|||
|
||||
const VoiceLineTitle = ({ record }: { record?: any }) => {
|
||||
let title = "";
|
||||
if (record) title = record.name ? record.name : record.email;
|
||||
if (record) title = record.name ?? record.email;
|
||||
return <span>VoiceLine {title}</span>;
|
||||
};
|
||||
|
||||
const VoiceLineEdit = (props: EditProps) => {
|
||||
return (
|
||||
<Edit title={<VoiceLineTitle />} {...props}>
|
||||
<SimpleForm>
|
||||
<ReferenceInput
|
||||
disabled
|
||||
label="Provider"
|
||||
source="providerId"
|
||||
reference="providers"
|
||||
validate={[required()]}
|
||||
>
|
||||
<SelectInput optionText={(p) => `${p.kind}: ${p.name}`} />
|
||||
</ReferenceInput>
|
||||
<TextInput disabled source="providerLineSid" />
|
||||
<TextInput disabled source="number" />
|
||||
<SelectInput source="language" choices={TwilioLanguages.languages} />
|
||||
<FormDataConsumer subscription={{ values: true }}>
|
||||
{VoiceInput}
|
||||
</FormDataConsumer>
|
||||
<FormDataConsumer subscription={{ values: true }}>
|
||||
{PromptInput}
|
||||
</FormDataConsumer>
|
||||
<BooleanInput source="audioPromptEnabled" />
|
||||
<MicInput source="promptAudio" />
|
||||
</SimpleForm>
|
||||
</Edit>
|
||||
);
|
||||
};
|
||||
const VoiceLineEdit = (props: EditProps) => (
|
||||
<Edit title={<VoiceLineTitle />} {...props}>
|
||||
<SimpleForm>
|
||||
<ReferenceInput
|
||||
disabled
|
||||
label="Provider"
|
||||
source="providerId"
|
||||
reference="providers"
|
||||
validate={[required()]}
|
||||
>
|
||||
<SelectInput optionText={(p) => `${p.kind}: ${p.name}`} />
|
||||
</ReferenceInput>
|
||||
<TextInput disabled source="providerLineSid" />
|
||||
<TextInput disabled source="number" />
|
||||
<SelectInput source="language" choices={TwilioLanguages.languages} />
|
||||
<FormDataConsumer subscription={{ values: true }}>
|
||||
{VoiceInput}
|
||||
</FormDataConsumer>
|
||||
<FormDataConsumer subscription={{ values: true }}>
|
||||
{PromptInput}
|
||||
</FormDataConsumer>
|
||||
<BooleanInput source="audioPromptEnabled" />
|
||||
<MicInput source="promptAudio" />
|
||||
</SimpleForm>
|
||||
</Edit>
|
||||
);
|
||||
|
||||
export default VoiceLineEdit;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable react/display-name */
|
||||
import React, { useState, useEffect } from "react";
|
||||
import PlayIcon from "@material-ui/icons/PlayCircleFilled";
|
||||
import {
|
||||
|
|
@ -25,7 +26,7 @@ const tts = async (providerId: any): Promise<TTSProvider> => {
|
|||
return (voice, language, prompt): Promise<void> =>
|
||||
new Promise((resolve) => {
|
||||
if (!voice || !language || !prompt) resolve();
|
||||
const Device = twilioClient.Device;
|
||||
const { Device } = twilioClient;
|
||||
const device = new Device();
|
||||
const silence = `${absoluteUrl().origin}/static/silence.mp3`;
|
||||
device.setup(token, {
|
||||
|
|
@ -39,7 +40,7 @@ const tts = async (providerId: any): Promise<TTSProvider> => {
|
|||
outgoing: silence,
|
||||
},
|
||||
});
|
||||
device.on("ready", function (device: any) {
|
||||
device.on("ready", (device: any) => {
|
||||
device.connect({ language, voice, prompt });
|
||||
});
|
||||
device.on("disconnect", () => resolve());
|
||||
|
|
@ -69,14 +70,14 @@ export const TextToSpeechButton = ({ form }: any) => {
|
|||
useEffect(() => {
|
||||
(async () => {
|
||||
setPlayText({
|
||||
func: async () => {
|
||||
async func() {
|
||||
setLoading(true);
|
||||
if (ttsProvider) await ttsProvider.provider(voice, language, prompt);
|
||||
setLoading(false);
|
||||
},
|
||||
});
|
||||
})();
|
||||
}, [prompt, language, voice, ttsProvider?.provider]);
|
||||
}, [prompt, language, voice, ttsProvider, ttsProvider?.provider]);
|
||||
|
||||
const disabled = !(providerId && prompt?.length >= 2 && voice && language);
|
||||
/* TODO add this back to IconButtonwhen we know how to extend MUI theme and appease typescript
|
||||
|
|
@ -90,19 +91,17 @@ export const TextToSpeechButton = ({ form }: any) => {
|
|||
);
|
||||
};
|
||||
|
||||
export const PromptInput = (form: any, ...rest: any[]) => {
|
||||
return (
|
||||
<TextInput
|
||||
source="promptText"
|
||||
multiline
|
||||
options={{ fullWidth: true }}
|
||||
InputProps={{ endAdornment: <TextToSpeechButton form={form} /> }}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
};
|
||||
export const PromptInput = (form: any, ...rest: any[]) => (
|
||||
<TextInput
|
||||
source="promptText"
|
||||
multiline
|
||||
options={{ fullWidth: true }}
|
||||
InputProps={{ endAdornment: <TextToSpeechButton form={form} /> }}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
|
||||
const validateVoice = (args: any, values: any) => {
|
||||
const validateVoice = (_args: any, values: any) => {
|
||||
if (!values.language) return "validation.language";
|
||||
if (!values.voice) return "validation.voice";
|
||||
// @ts-expect-error
|
||||
|
|
@ -145,25 +144,20 @@ const getAvailableNumbers = async (providerId: string) => {
|
|||
}
|
||||
};
|
||||
|
||||
const sidToNumber = (sid: any) => {
|
||||
return availableNumbers
|
||||
.filter(({ id }) => id === sid)
|
||||
.map(({ name }) => name)[0];
|
||||
};
|
||||
const sidToNumber = (sid: any) =>
|
||||
availableNumbers.filter(({ id }) => id === sid).map(({ name }) => name)[0];
|
||||
|
||||
export const populateNumber = (data: any) => {
|
||||
return {
|
||||
...data,
|
||||
number: sidToNumber(data.providerLineSid),
|
||||
};
|
||||
};
|
||||
export const populateNumber = (data: any) => ({
|
||||
...data,
|
||||
number: sidToNumber(data.providerLineSid),
|
||||
});
|
||||
|
||||
const hasNumbers = (
|
||||
args: any,
|
||||
value: any,
|
||||
values: any,
|
||||
translate: any,
|
||||
...props: any[]
|
||||
_args: any,
|
||||
_value: any,
|
||||
_values: any,
|
||||
_translate: any,
|
||||
..._props: any[]
|
||||
) => {
|
||||
if (noAvailableNumbers) return "validation.noAvailableNumbers";
|
||||
|
||||
|
|
@ -197,7 +191,7 @@ export const AvailableNumbersInput = (form: any, ...rest: any[]) => {
|
|||
notify("validation.noAvailableNumbers", { type: "error" });
|
||||
setLoading(false);
|
||||
}
|
||||
}, [form && form.formData ? form.formData.providerId : undefined]);
|
||||
}, [form, notify, translate]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -22,35 +22,30 @@ import { BackendTypeInput, BackendIdInput, HttpMethodInput } from "./shared";
|
|||
<SelectInput optionText="number" />
|
||||
</ReferenceInput>
|
||||
*/
|
||||
const WebhookCreate = (props: CreateProps) => {
|
||||
return (
|
||||
<Create {...props} title="Create Webhooks">
|
||||
<SimpleForm>
|
||||
<TextInput source="name" validate={[required()]} />
|
||||
<BackendTypeInput />
|
||||
<FormDataConsumer subscription={{ values: true }}>
|
||||
{BackendIdInput}
|
||||
</FormDataConsumer>
|
||||
<TextInput
|
||||
source="endpointUrl"
|
||||
validate={[required(), regex(/^https?:\/\/[^/]+/, "validation.url")]}
|
||||
/>
|
||||
<HttpMethodInput />
|
||||
<ArrayInput source="headers">
|
||||
<SimpleFormIterator>
|
||||
<TextInput
|
||||
source="header"
|
||||
validate={[
|
||||
required(),
|
||||
regex(/^[\w-]+$/, "validation.headerName"),
|
||||
]}
|
||||
/>
|
||||
<TextInput source="value" validate={[required()]} />
|
||||
</SimpleFormIterator>
|
||||
</ArrayInput>
|
||||
</SimpleForm>
|
||||
</Create>
|
||||
);
|
||||
};
|
||||
const WebhookCreate = (props: CreateProps) => (
|
||||
<Create {...props} title="Create Webhooks">
|
||||
<SimpleForm>
|
||||
<TextInput source="name" validate={[required()]} />
|
||||
<BackendTypeInput />
|
||||
<FormDataConsumer subscription={{ values: true }}>
|
||||
{BackendIdInput}
|
||||
</FormDataConsumer>
|
||||
<TextInput
|
||||
source="endpointUrl"
|
||||
validate={[required(), regex(/^https?:\/\/[^/]+/, "validation.url")]}
|
||||
/>
|
||||
<HttpMethodInput />
|
||||
<ArrayInput source="headers">
|
||||
<SimpleFormIterator>
|
||||
<TextInput
|
||||
source="header"
|
||||
validate={[required(), regex(/^[\w-]+$/, "validation.headerName")]}
|
||||
/>
|
||||
<TextInput source="value" validate={[required()]} />
|
||||
</SimpleFormIterator>
|
||||
</ArrayInput>
|
||||
</SimpleForm>
|
||||
</Create>
|
||||
);
|
||||
|
||||
export default WebhookCreate;
|
||||
|
|
|
|||
|
|
@ -13,39 +13,34 @@ import { BackendTypeInput, BackendIdInput, HttpMethodInput } from "./shared";
|
|||
|
||||
const WebhookTitle = ({ record }: any) => {
|
||||
let title = "";
|
||||
if (record) title = record.name ? record.name : record.email;
|
||||
if (record) title = record.name ?? record.email;
|
||||
return <span>Webhook {title}</span>;
|
||||
};
|
||||
|
||||
const WebhookEdit = (props: EditProps) => {
|
||||
return (
|
||||
<Edit title={<WebhookTitle />} {...props}>
|
||||
<SimpleForm>
|
||||
<TextInput source="name" validate={[required()]} />
|
||||
<BackendTypeInput />
|
||||
<FormDataConsumer subscription={{ values: true }}>
|
||||
{BackendIdInput}
|
||||
</FormDataConsumer>
|
||||
<TextInput
|
||||
source="endpointUrl"
|
||||
validate={[required(), regex(/^https?:\/\/[^/]+/, "validation.url")]}
|
||||
/>
|
||||
<HttpMethodInput />
|
||||
<ArrayInput source="headers">
|
||||
<SimpleFormIterator>
|
||||
<TextInput
|
||||
source="header"
|
||||
validate={[
|
||||
required(),
|
||||
regex(/^[\w-]+$/, "validation.headerName"),
|
||||
]}
|
||||
/>
|
||||
<TextInput source="value" validate={[required()]} />
|
||||
</SimpleFormIterator>
|
||||
</ArrayInput>
|
||||
</SimpleForm>
|
||||
</Edit>
|
||||
);
|
||||
};
|
||||
const WebhookEdit = (props: EditProps) => (
|
||||
<Edit title={<WebhookTitle />} {...props}>
|
||||
<SimpleForm>
|
||||
<TextInput source="name" validate={[required()]} />
|
||||
<BackendTypeInput />
|
||||
<FormDataConsumer subscription={{ values: true }}>
|
||||
{BackendIdInput}
|
||||
</FormDataConsumer>
|
||||
<TextInput
|
||||
source="endpointUrl"
|
||||
validate={[required(), regex(/^https?:\/\/[^/]+/, "validation.url")]}
|
||||
/>
|
||||
<HttpMethodInput />
|
||||
<ArrayInput source="headers">
|
||||
<SimpleFormIterator>
|
||||
<TextInput
|
||||
source="header"
|
||||
validate={[required(), regex(/^[\w-]+$/, "validation.headerName")]}
|
||||
/>
|
||||
<TextInput source="value" validate={[required()]} />
|
||||
</SimpleFormIterator>
|
||||
</ArrayInput>
|
||||
</SimpleForm>
|
||||
</Edit>
|
||||
);
|
||||
|
||||
export default WebhookEdit;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,4 @@
|
|||
import {
|
||||
List,
|
||||
Datagrid,
|
||||
DateField,
|
||||
TextField,
|
||||
ReferenceField,
|
||||
ListProps,
|
||||
} from "react-admin";
|
||||
import { List, Datagrid, DateField, TextField, ListProps } from "react-admin";
|
||||
import { BackendIdField } from "./shared";
|
||||
|
||||
const WebhookList = (props: ListProps) => (
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ const WhatsappBotShow = (props: ShowProps) => {
|
|||
}, 10000);
|
||||
return () => clearInterval(interval);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}, [refresh, data]);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable react/display-name */
|
||||
import {
|
||||
SelectInput,
|
||||
required,
|
||||
|
|
@ -6,19 +7,25 @@ import {
|
|||
TextField,
|
||||
} from "react-admin";
|
||||
|
||||
export const WhatsAppBotSelectInput = (source: string) => () => (
|
||||
<ReferenceInput
|
||||
label="WhatsApp Bot"
|
||||
reference="whatsappBots"
|
||||
source={source}
|
||||
validate={[required()]}
|
||||
>
|
||||
<SelectInput optionText="phoneNumber" />
|
||||
</ReferenceInput>
|
||||
);
|
||||
export const WhatsAppBotSelectInput = (source: string) => () =>
|
||||
(
|
||||
<ReferenceInput
|
||||
label="WhatsApp Bot"
|
||||
reference="whatsappBots"
|
||||
source={source}
|
||||
validate={[required()]}
|
||||
>
|
||||
<SelectInput optionText="phoneNumber" />
|
||||
</ReferenceInput>
|
||||
);
|
||||
|
||||
export const WhatsAppBotField = (source: string) => () => (
|
||||
<ReferenceField label="WhatsApp Bot" reference="whatsappBots" source={source}>
|
||||
<TextField source="phoneNumber" />
|
||||
</ReferenceField>
|
||||
);
|
||||
export const WhatsAppBotField = (source: string) => () =>
|
||||
(
|
||||
<ReferenceField
|
||||
label="WhatsApp Bot"
|
||||
reference="whatsappBots"
|
||||
source={source}
|
||||
>
|
||||
<TextField source="phoneNumber" />
|
||||
</ReferenceField>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { IncomingMessage } from "http";
|
||||
import { IncomingMessage } from "node:http";
|
||||
|
||||
function absoluteUrl(
|
||||
req?: IncomingMessage,
|
||||
|
|
|
|||
|
|
@ -36,5 +36,5 @@ export const apolloClient = new ApolloClient({
|
|||
fetchPolicy: "no-cache",
|
||||
errorPolicy: "all",
|
||||
},
|
||||
},*/
|
||||
}, */
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { promisify } from "util";
|
||||
import { promisify } from "node:util";
|
||||
import jwt from "jsonwebtoken";
|
||||
import jwksClient from "jwks-rsa";
|
||||
import * as Boom from "@hapi/boom";
|
||||
import * as Wreck from "@hapi/wreck";
|
||||
import Providers from "next-auth/providers";
|
||||
import Credentials from "next-auth/providers/credentials";
|
||||
import type { Adapter } from "next-auth/adapters";
|
||||
import type { IncomingMessage } from "http";
|
||||
import type { IncomingMessage } from "node:http";
|
||||
|
||||
const CF_JWT_HEADER_NAME = "cf-access-jwt-assertion";
|
||||
const CF_JWT_ALGOS = ["RS256"];
|
||||
|
|
@ -30,7 +30,7 @@ export const cfVerifier = (audience: string, domain: string): VerifyFn => {
|
|||
|
||||
return async (token) => {
|
||||
const getKey = (header: any, callback: any) => {
|
||||
client.getSigningKey(header.kid, function (err: any, key: any) {
|
||||
client.getSigningKey(header.kid, (err: any, key: any) => {
|
||||
if (err)
|
||||
throw Boom.serverUnavailable(
|
||||
"failed to fetch cloudflare access jwks"
|
||||
|
|
@ -201,8 +201,8 @@ export const CloudflareAccessProvider = (
|
|||
req: IncomingMessage
|
||||
) => {
|
||||
const verifier = cfVerifier(audience, domain);
|
||||
// @ts-expect-error
|
||||
return Providers.Credentials({
|
||||
|
||||
return Credentials({
|
||||
id: cloudflareAccountProvider,
|
||||
name: "Cloudflare Access",
|
||||
credentials: {},
|
||||
|
|
|
|||
|
|
@ -2,16 +2,14 @@ import pgDataProvider from "ra-postgraphile";
|
|||
import schema from "./graphql-schema.json";
|
||||
|
||||
export const metamigoDataProvider = async (client: any) => {
|
||||
const graphqlDataProvider = await pgDataProvider(
|
||||
const graphqlDataProvider: any = await pgDataProvider(
|
||||
client,
|
||||
// @ts-expect-error: Missing property
|
||||
{},
|
||||
{ introspection: { schema: schema.data.__schema } }
|
||||
);
|
||||
|
||||
const dataProvider = async (type: any, resource: any, params: any) => {
|
||||
return graphqlDataProvider(type, resource, params);
|
||||
};
|
||||
const dataProvider = async (type: any, resource: any, params: any) => graphqlDataProvider(type, resource, params);
|
||||
|
||||
return dataProvider;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export interface Session {
|
|||
|
||||
// from https://github.com/nextauthjs/next-auth/blob/main/src/lib/errors.js
|
||||
class UnknownError extends Error {
|
||||
constructor(message) {
|
||||
constructor(message: any) {
|
||||
super(message);
|
||||
this.name = "UnknownError";
|
||||
this.message = message;
|
||||
|
|
@ -48,14 +48,14 @@ class UnknownError extends Error {
|
|||
}
|
||||
|
||||
class CreateUserError extends UnknownError {
|
||||
constructor(message) {
|
||||
constructor(message: any) {
|
||||
super(message);
|
||||
this.name = "CreateUserError";
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
||||
const basicHeader = (secret) =>
|
||||
const basicHeader = (secret: any) =>
|
||||
"Basic " + Buffer.from(secret + ":", "utf8").toString("base64");
|
||||
|
||||
export const MetamigoAdapter = (config: IAppConfig): Adapter => {
|
||||
|
|
@ -155,7 +155,7 @@ export const MetamigoAdapter = (config: IAppConfig): Adapter => {
|
|||
await wreck.put("linkAccount", {
|
||||
payload,
|
||||
});
|
||||
} catch (error) {
|
||||
} catch {
|
||||
throw new Error("LINK_ACCOUNT_ERROR");
|
||||
}
|
||||
}
|
||||
|
|
@ -208,7 +208,7 @@ export const MetamigoAdapter = (config: IAppConfig): Adapter => {
|
|||
}
|
||||
}
|
||||
|
||||
return Promise.resolve({
|
||||
return {
|
||||
createUser,
|
||||
getUser,
|
||||
getUserByEmail,
|
||||
|
|
@ -222,7 +222,7 @@ export const MetamigoAdapter = (config: IAppConfig): Adapter => {
|
|||
updateSession,
|
||||
deleteSession,
|
||||
// @ts-expect-error: Type error
|
||||
} as AdapterInstance<Profile, User, Session, unknown>);
|
||||
} as AdapterInstance<Profile, User, Session, unknown>;
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -4,14 +4,12 @@ export const E164Regex = /^\+[1-9]\d{1,14}$/;
|
|||
/**
|
||||
* Returns true if the number is a valid E164 number
|
||||
*/
|
||||
export const isValidE164Number = (phoneNumber) => {
|
||||
return E164Regex.test(phoneNumber);
|
||||
};
|
||||
export const isValidE164Number = (phoneNumber: string) => E164Regex.test(phoneNumber);
|
||||
|
||||
/**
|
||||
* Given a phone number approximation, will clean out whitespace and punctuation.
|
||||
*/
|
||||
export const sanitizeE164Number = (phoneNumber) => {
|
||||
export const sanitizeE164Number = (phoneNumber: string) => {
|
||||
if (!phoneNumber) return "";
|
||||
if (!phoneNumber.trim()) return "";
|
||||
const sanitized = phoneNumber
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
module.exports = {
|
||||
experimental: { esmExternals: "loose" },
|
||||
async redirects() {
|
||||
return [{ source: "/", destination: "/admin", permanent: true }];
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { SessionProvider } from "next-auth/react";
|
|||
|
||||
function MetamigoStarter({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
<SessionProvider session={pageProps.session}>
|
||||
<SessionProvider session={(pageProps as any).session}>
|
||||
<Component {...pageProps} />
|
||||
</SessionProvider>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import Google from "next-auth/providers/google";
|
|||
import GitHub from "next-auth/providers/github";
|
||||
import GitLab from "next-auth/providers/gitlab";
|
||||
import Cognito from "next-auth/providers/cognito";
|
||||
import { loadConfig, IAppConfig } from "config";
|
||||
import { loadConfig, IAppConfig } from "@digiresilience/metamigo-config";
|
||||
import { MetamigoAdapter } from "../../../lib/nextauth-adapter";
|
||||
import { CloudflareAccessProvider } from "../../../lib/cloudflare";
|
||||
|
||||
|
|
@ -72,12 +72,12 @@ const nextAuthOptions = (config: IAppConfig, req: NextApiRequest) => {
|
|||
providers,
|
||||
adapter,
|
||||
callbacks: {
|
||||
session: async (session: any, token: any) => {
|
||||
async session(session: any, token: any) {
|
||||
// make the user id available in the react client
|
||||
session.user.id = token.userId;
|
||||
return session;
|
||||
},
|
||||
jwt: async (token: any, user: any) => {
|
||||
async jwt(token: any, user: any) {
|
||||
const isSignIn = Boolean(user);
|
||||
// Add auth_time to token on signin in
|
||||
if (isSignIn) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ export default createProxyMiddleware({
|
|||
changeOrigin: true,
|
||||
pathRewrite: { "^/graphql": "/graphql" },
|
||||
xfwd: true,
|
||||
onProxyReq: function (proxyReq, req, _res) {
|
||||
onProxyReq(proxyReq, req, _res) {
|
||||
const auth = proxyReq.getHeader("authorization");
|
||||
if (auth) {
|
||||
// pass along user provided authorization header
|
||||
|
|
@ -20,8 +20,8 @@ export default createProxyMiddleware({
|
|||
let token = req.cookies["__Secure-next-auth.session-token"];
|
||||
if (!token) token = req.cookies["next-auth.session-token"];
|
||||
|
||||
//console.log(req.body);
|
||||
//if (req.body.query) console.log(req.body.query);
|
||||
// console.log(req.body);
|
||||
// if (req.body.query) console.log(req.body.query);
|
||||
if (token) {
|
||||
proxyReq.setHeader("authorization", `Bearer ${token}`);
|
||||
proxyReq.removeHeader("cookie");
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ export default createProxyMiddleware({
|
|||
changeOrigin: true,
|
||||
pathRewrite: { "^/api/v1": "/api" },
|
||||
xfwd: true,
|
||||
onProxyReq: function (proxyReq, req, res) {
|
||||
onProxyReq(proxyReq, req) {
|
||||
const auth = proxyReq.getHeader("authorization");
|
||||
if (auth) {
|
||||
// pass along user provided authorization header
|
||||
|
|
@ -17,7 +17,7 @@ export default createProxyMiddleware({
|
|||
|
||||
// Else extract the session token from the cookie and pass
|
||||
// as bearer token to the proxy target
|
||||
//const token = req.cookies["next-auth.session-token"];
|
||||
// const token = req.cookies["next-auth.session-token"];
|
||||
let token = req.cookies["__Secure-next-auth.session-token"];
|
||||
if (!token) token = req.cookies["next-auth.session-token"];
|
||||
|
||||
|
|
@ -27,7 +27,6 @@ export default createProxyMiddleware({
|
|||
} else {
|
||||
console.error("no token found. proxied request to backend will fail.");
|
||||
}
|
||||
return;
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { NextPage } from "next";
|
||||
import { Typography, Box, Button, Grid, Link } from "@material-ui/core";
|
||||
import { FC, PropsWithChildren, useEffect } from "react";
|
||||
import { FC, useEffect } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
export const RedirectToAdmin: FC = ({ children }) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { FC } from "react";
|
||||
import { Button } from "@material-ui/core";
|
||||
import { signIn, signOut, useSession } from "next-auth/react";
|
||||
|
||||
export default function myComponent() {
|
||||
const MyComponent: FC = () => {
|
||||
const { data: session } = useSession();
|
||||
|
||||
return (
|
||||
|
|
@ -24,4 +25,6 @@ export default function myComponent() {
|
|||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default MyComponent;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue