Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ then also click __"Continue"__ a couple time to navigate to __"Scopes"__.
and here we need to __"+ Add"__ the following scopes:

* Meeting
* View all user meetings (*meeting:read:admin*)
* View and manage all user meetings (*meeting:write:admin*)
* View all user meetings (*meeting:read:meeting:admin*, *meeting:read:list_meetings:admin*)
* View and manage all user meetings (*meeting:write:meeting:admin*, *meeting:delete:meeting:admin*)
* User
* View all user information (*user:read:admin*)
* View all user information (*user:read:user:admin*)

Ok, head back to Deskpro and enter your __Client ID__ and __Client secret__ into the app settings form.

Expand Down
17 changes: 15 additions & 2 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,31 @@
"hasDevMode": true,
"serveUrl": "https://apps-cdn.deskpro-service.com/__name__/__version__",
"targets": [{ "target": "ticket_sidebar", "entrypoint": "index.html" }],
"secrets": "SMEkhJoGvqgiXxPNDne4o+YHmr6X/fsKwQ8Gbzs6gGZAlnyql+HGxW7rqIg7flz0+bU+tdKnt40l3SnK1acmdySlaTlBI/Jvt/cHTsp56lxaArYy44PG2FrgxMcrk6EXUZHWORVHDZ6kcg1PwiAb5bBsOw8DH4tvn+Rm9WVewyaQPlVXnzKhqU/HrFE8KJjTKnfVyBprx3KBxoc/1Y3GBwsMs40Q51NjTnKMj2b3X+o+srknWcU/c4VvYGE8lIYYb6erBLYFGs5koa4UysmKigk2V4FUTpHTYWdS3hI/jQuvtpIj7/Zy1XXrBtLEt12st1iD8MO3vBYcYPR4bsopgSnBHIr8qXkNPLSlJe41NLwp3O4ctJcTY56yulOtjntYtYVWyLfUNioACnqUZujwbQiZeuxCD/nyRBZ0kV+/UmunQG+FDBxLhRfF5M6Ns5cF8ZkGu7eSfwURzLWPx14T7Poqdbs1AKwpO8NVVqKS+pchXWZucA2uP/LlXxJS430uOGjGRphli/FpwgX3Or2XAoOWAGMOUsOvttHD/V7PeGDkR8CpDJoVmkn+yyboj7kXh6foJf5o7v64jd5nNAVy0FYW518OOp/r3eGybcGqgxFI7bX9rhP62cALDc4ajFe5hoL64e4gLP3orn2EkejFbjG1BWfudZYhhgjlF8IywxI=",
"settings": {
"use_advanced_connect": {
"title": "Advanced Connect",
"description": "Follow the setup guide and use your credentials to connect the app to Deskpro.",
"type": "boolean",
"default": false,
"isRequired": false,
"isBackendOnly": false,
"order": 5
},
"client_id": {
"title": "Client ID",
"type": "string",
"isRequired": true,
"isRequired": false,
"isBackendOnly": false,
"condition": "settings.use_advanced_connect != false",
"order": 10
},
"client_secret": {
"title": "Client secret",
"type": "string",
"isRequired": true,
"isRequired": false,
"isBackendOnly": true,
"condition": "settings.use_advanced_connect != false",
"order": 20
},
"callback_url": {
Expand All @@ -30,6 +42,7 @@
"options": { "entrypoint": "#/admin/callback", "height": "75px" },
"isRequired": false,
"isBackendOnly": true,
"condition": "settings.use_advanced_connect != false",
"order": 30
}
},
Expand Down
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"license": "BSD-3-Clause",
"scripts": {
"start": "vite",
"build": "rimraf ./dist/* && tsc && vite build",
"build": "rm -rf ./dist/ && tsc && vite build",
"build:package": "pnpm run build && pnpm run package",
"package": "rimraf ./build/* && node ./bin/package.js",
"package": "rm -rf ./build/ && node ./bin/package.js",
"serve": "vite preview",
"lint": "eslint --max-warnings 0 --ext ts,tsx ./src",
"test": "cross-env NODE_OPTIONS=--max-old-space-size=1024 jest --maxWorkers=75%",
Expand All @@ -15,7 +15,7 @@
"bumpManifestVer": "node ./bin/bumpManifestVer.js"
},
"dependencies": {
"@deskpro/app-sdk": "^5.1.1",
"@deskpro/app-sdk": "^6.0.3",
"@deskpro/deskpro-ui": "^8.2.0",
"@heroicons/react": "1.0.6",
"@hookform/resolvers": "^3.0.1",
Expand Down Expand Up @@ -68,7 +68,6 @@
"jest-environment-jsdom": "^29.7.0",
"node-fetch": "^3.3.0",
"prettier": "^2.8.8",
"rimraf": "^3.0.2",
"rollup-plugin-copy": "3.4.0",
"slugify": "^1.6.5",
"ts-jest": "^27.1.5",
Expand Down
21 changes: 9 additions & 12 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 17 additions & 9 deletions src/pages/AdminPage/AdminPage.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useState, useMemo } from "react";
import { useState } from "react";
import styled from "styled-components";
import { v4 as uuidv4 } from "uuid";
import { P1 } from "@deskpro/deskpro-ui";
import {
LoadingSpinner,
useInitialisedDeskproAppClient,
} from "@deskpro/app-sdk";
import { CopyToClipboardInput } from "@/components/common";
import type { FC } from "react";
import type { OAuth2Result } from "@deskpro/app-sdk";

const Description = styled(P1)`
margin-top: 8px;
Expand All @@ -17,14 +17,22 @@ const Description = styled(P1)`

const AdminPage: FC = () => {
const [callbackUrl, setCallbackUrl] = useState<string|null>(null);
const key = useMemo(() => uuidv4(), []);

useInitialisedDeskproAppClient(async (client) => {
const oauth2 = await client.startOauth2Local(
({ state, callbackUrl }) => `https://zoom.us/oauth/authorize?response_type=code&client_id=xxx&state=${state}&redirect_uri=${callbackUrl}`,
/code=(?<code>[0-9a-f]+)/,
async (): Promise<OAuth2Result> => ({ data: { access_token: "", refresh_token: "" } })
);

useInitialisedDeskproAppClient((client) => {
client.oauth2()
.getAdminGenericCallbackUrl(key, /code=(?<token>[0-9a-f]+)/, /state=(?<key>.+)/)
.then(({ callbackUrl }) => setCallbackUrl(callbackUrl));
}, [key]);
// Extract the callback URL from the authorization URL
const url = new URL(oauth2.authorizationUrl);
const redirectUri = url.searchParams.get("redirect_uri");

if (redirectUri) {
setCallbackUrl(redirectUri);
}
});

if (!callbackUrl) {
return (<LoadingSpinner/>);
Expand All @@ -38,4 +46,4 @@ const AdminPage: FC = () => {
);
};

export { AdminPage };
export { AdminPage };
37 changes: 13 additions & 24 deletions src/pages/LoginPage/LoginPage.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { H3 } from "@deskpro/deskpro-ui";
import { Title, useDeskproElements } from "@deskpro/app-sdk";
import { useSetTitle } from "@/hooks";
import { AnchorButton } from "@/components/common";
import { ErrorBlock } from "@/components";
import { H3, Stack } from "@deskpro/deskpro-ui";
import { useDeskproElements } from "@deskpro/app-sdk";
import { useLogin } from "./hooks";
import { Container, AnchorButton } from "@/components/common";
import { useSetTitle } from "@/hooks";
import type { FC } from "react";

const LoginPage: FC = () => {
const navigate = useNavigate();
const {
isAuth,
authLink,
onSignIn,
isLoading,
} = useLogin();
const { onSignIn, authUrl, isLoading, error } = useLogin();

useSetTitle("Zoom Meetings");

Expand All @@ -23,25 +16,21 @@ const LoginPage: FC = () => {
registerElement("refresh", { type: "refresh_button" });
});

useEffect(() => {
if (isAuth) {
navigate("/home");
}
}, [isAuth, navigate]);

return (
<Container>
<Title as={H3} title="Log into your Zoom Account" />
<Stack padding={12} vertical gap={12} role="alert">
<H3>Log into your Zoom Account.</H3>
<AnchorButton
intent="secondary"
text="Log In"
target="_blank"
href={authLink}
href={authUrl ?? "#"}
onClick={onSignIn}
loading={isLoading}
disabled={isLoading}
disabled={!authUrl || isLoading}
/>
</Container>

{error && (<div style={{ width: "100%" }}><ErrorBlock text={error} /></div>)}
</Stack>
);
};

Expand Down
29 changes: 5 additions & 24 deletions src/pages/LoginPage/__tests__/LoginPage.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { useNavigate } from "react-router-dom";
import { act, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { LoginPage } from "../LoginPage";
import { render } from "@/testing";
import { useLogin } from "../hooks";
import userEvent from "@testing-library/user-event";

jest.mock("react-router-dom", () => ({
...jest.requireActual("react-router-dom"),
Expand All @@ -15,12 +14,11 @@ describe("LoginPage", () => {
test("render", async () => {
(useLogin as jest.Mock).mockImplementation(() => ({
error: null,
isAuth: false,
authLink: "https://call-back.url/?code=123",
authUrl: "https://call-back.url/?code=123",
onSignIn: jest.fn(),
isLoading: false,
}));
const { findByRole } = render(<LoginPage/>, { wrappers: { theme: true }});
const { findByRole } = render(<LoginPage />, { wrappers: { theme: true } });
const loginButton = await findByRole("link", { name: /Log In/i });

await waitFor(() => {
Expand All @@ -32,12 +30,11 @@ describe("LoginPage", () => {
const onSignIn = jest.fn();
(useLogin as jest.Mock).mockImplementation(() => ({
error: null,
isAuth: false,
isLoading: false,
authLink: "https://call-back.url/?code=123",
authUrl: "https://call-back.url/?code=123",
onSignIn,
}));
const { findByRole } = render(<LoginPage/>, { wrappers: { theme: true }});
const { findByRole } = render(<LoginPage />, { wrappers: { theme: true } });

const loginButton = await findByRole("link", { name: /Log In/i });

Expand All @@ -47,20 +44,4 @@ describe("LoginPage", () => {

expect(onSignIn).toHaveBeenCalledTimes(1);
});

test("should navigate to /home after auth", async () => {
const navigate = jest.fn();
(useLogin as jest.Mock).mockImplementation(() => ({
error: null,
isAuth: true,
isLoading: false,
authLink: "https://call-back.url/?code=123",
onSignIn: jest.fn(),
}));
(useNavigate as jest.Mock).mockImplementation(() => navigate);
render(<LoginPage/>, { wrappers: { theme: true }});

expect(navigate).toHaveBeenCalledTimes(1);
expect(navigate).toHaveBeenCalledWith("/home");
});
});
Loading
Loading