Replug UserDropdown -> SessionDropdown
Signed-off-by: Émile Ré <nemile.re@gmail.com>
This commit is contained in:
@@ -24,7 +24,7 @@ export default function SignInPage() {
|
|||||||
|
|
||||||
const [signIn, isSigningIn] = useMutation<SignInPageMutation>(signInMutation);
|
const [signIn, isSigningIn] = useMutation<SignInPageMutation>(signInMutation);
|
||||||
|
|
||||||
const handlePasswordLogin: FormEventHandler<HTMLFormElement> = async (e) => {
|
const handlePasswordLogin: FormEventHandler<HTMLFormElement> = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const formData = new FormData(e.currentTarget);
|
const formData = new FormData(e.currentTarget);
|
||||||
const emailValue = formData.get("email")?.toString();
|
const emailValue = formData.get("email")?.toString();
|
||||||
@@ -32,7 +32,6 @@ export default function SignInPage() {
|
|||||||
|
|
||||||
if (!emailValue || !passwordValue) return;
|
if (!emailValue || !passwordValue) return;
|
||||||
|
|
||||||
try {
|
|
||||||
signIn({
|
signIn({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
@@ -40,16 +39,17 @@ export default function SignInPage() {
|
|||||||
password: passwordValue,
|
password: passwordValue,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
onCompleted: () => {
|
||||||
|
|
||||||
window.location.href = "/";
|
window.location.href = "/";
|
||||||
} catch (e: unknown) {
|
},
|
||||||
|
onError: (e) => {
|
||||||
toast({
|
toast({
|
||||||
title: __("Error"),
|
title: __("Error"),
|
||||||
description: e instanceof Error ? e.message : __("Failed to login"),
|
description: e instanceof Error ? e.message : __("Failed to login"),
|
||||||
variant: "error",
|
variant: "error",
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -5,12 +5,14 @@ import {
|
|||||||
} from "react-relay";
|
} from "react-relay";
|
||||||
import { organizationLayoutQuery } from "./OrganizationLayoutQuery";
|
import { organizationLayoutQuery } from "./OrganizationLayoutQuery";
|
||||||
import { Outlet } from "react-router";
|
import { Outlet } from "react-router";
|
||||||
import { Layout } from "@probo/ui";
|
import { Layout, Skeleton } from "@probo/ui";
|
||||||
import { Sidebar } from "./_components/Sidebar";
|
import { Sidebar } from "./_components/Sidebar";
|
||||||
import { OrganizationDropdown } from "./_components/OrganizationDropdown";
|
import { OrganizationDropdown } from "./_components/OrganizationDropdown";
|
||||||
import { consoleEnvironment } from "/environments";
|
import { consoleEnvironment } from "/environments";
|
||||||
import type { OrganizationLayoutQuery } from "./__generated__/OrganizationLayoutQuery.graphql";
|
import type { OrganizationLayoutQuery } from "./__generated__/OrganizationLayoutQuery.graphql";
|
||||||
import { PermissionsProvider } from "/providers/PermissionsProvider";
|
import { PermissionsProvider } from "/providers/PermissionsProvider";
|
||||||
|
import { SessionDropdown } from "./_components/SessionDropdown";
|
||||||
|
import { Suspense } from "react";
|
||||||
|
|
||||||
interface OrganizationLayoutProps {
|
interface OrganizationLayoutProps {
|
||||||
queryRef: PreloadedQuery<OrganizationLayoutQuery>;
|
queryRef: PreloadedQuery<OrganizationLayoutQuery>;
|
||||||
@@ -32,9 +34,9 @@ export default function OrganizationLayout(props: OrganizationLayoutProps) {
|
|||||||
<div className="mr-auto">
|
<div className="mr-auto">
|
||||||
<OrganizationDropdown fKey={data.organization} />
|
<OrganizationDropdown fKey={data.organization} />
|
||||||
</div>
|
</div>
|
||||||
{/* <Suspense fallback={<Skeleton className="w-32 h-8" />}>
|
<Suspense fallback={<Skeleton className="w-32 h-8" />}>
|
||||||
<UserDropdown organizationId={organizationId} />
|
<SessionDropdown fKey={data.viewer} />
|
||||||
</Suspense> */}
|
</Suspense>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
sidebar={<Sidebar />}
|
sidebar={<Sidebar />}
|
||||||
|
|||||||
@@ -15,10 +15,11 @@ export const organizationLayoutQuery = graphql`
|
|||||||
...OrganizationDropdownFragment
|
...OrganizationDropdownFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
viewer {
|
viewer @required(action: THROW) {
|
||||||
pendingInvitations {
|
pendingInvitations {
|
||||||
totalCount
|
totalCount
|
||||||
}
|
}
|
||||||
|
...SessionDropdownFragment @arguments(organizationId: $organizationId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<e99ea3ab9f033b6a5384d389dd964f06>>
|
* @generated SignedSource<<1d82d885a77675a330799121edb5cb69>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -21,7 +21,8 @@ export type OrganizationLayoutQuery$data = {
|
|||||||
readonly pendingInvitations: {
|
readonly pendingInvitations: {
|
||||||
readonly totalCount: number | null | undefined;
|
readonly totalCount: number | null | undefined;
|
||||||
} | null | undefined;
|
} | null | undefined;
|
||||||
} | null | undefined;
|
readonly " $fragmentSpreads": FragmentRefs<"SessionDropdownFragment">;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
export type OrganizationLayoutQuery = {
|
export type OrganizationLayoutQuery = {
|
||||||
response: OrganizationLayoutQuery$data;
|
response: OrganizationLayoutQuery$data;
|
||||||
@@ -61,7 +62,14 @@ v2 = {
|
|||||||
],
|
],
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
},
|
},
|
||||||
v3 = {
|
v3 = [
|
||||||
|
{
|
||||||
|
"kind": "Variable",
|
||||||
|
"name": "organizationId",
|
||||||
|
"variableName": "organizationId"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v4 = {
|
||||||
"alias": null,
|
"alias": null,
|
||||||
"args": null,
|
"args": null,
|
||||||
"kind": "ScalarField",
|
"kind": "ScalarField",
|
||||||
@@ -103,6 +111,8 @@ return {
|
|||||||
"action": "THROW"
|
"action": "THROW"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"kind": "RequiredField",
|
||||||
|
"field": {
|
||||||
"alias": null,
|
"alias": null,
|
||||||
"args": null,
|
"args": null,
|
||||||
"concreteType": "Identity",
|
"concreteType": "Identity",
|
||||||
@@ -110,9 +120,16 @@ return {
|
|||||||
"name": "viewer",
|
"name": "viewer",
|
||||||
"plural": false,
|
"plural": false,
|
||||||
"selections": [
|
"selections": [
|
||||||
(v2/*: any*/)
|
(v2/*: any*/),
|
||||||
|
{
|
||||||
|
"args": (v3/*: any*/),
|
||||||
|
"kind": "FragmentSpread",
|
||||||
|
"name": "SessionDropdownFragment"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
|
},
|
||||||
|
"action": "THROW"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"type": "Query",
|
"type": "Query",
|
||||||
@@ -153,7 +170,7 @@ return {
|
|||||||
"type": "Organization",
|
"type": "Organization",
|
||||||
"abstractKey": null
|
"abstractKey": null
|
||||||
},
|
},
|
||||||
(v3/*: any*/)
|
(v4/*: any*/)
|
||||||
],
|
],
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
},
|
},
|
||||||
@@ -166,23 +183,56 @@ return {
|
|||||||
"plural": false,
|
"plural": false,
|
||||||
"selections": [
|
"selections": [
|
||||||
(v2/*: any*/),
|
(v2/*: any*/),
|
||||||
(v3/*: any*/)
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "email",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v3/*: any*/),
|
||||||
|
"concreteType": "IdentityProfile",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "profileFor",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "firstName",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "lastName",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
(v4/*: any*/)
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
(v4/*: any*/)
|
||||||
],
|
],
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"params": {
|
"params": {
|
||||||
"cacheID": "b991c1a406cc9c0df5c67099285c31a8",
|
"cacheID": "0ebb386f89d19888f18a05c8dc573895",
|
||||||
"id": null,
|
"id": null,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"name": "OrganizationLayoutQuery",
|
"name": "OrganizationLayoutQuery",
|
||||||
"operationKind": "query",
|
"operationKind": "query",
|
||||||
"text": "query OrganizationLayoutQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n ...OrganizationDropdownFragment\n }\n id\n }\n viewer {\n pendingInvitations {\n totalCount\n }\n id\n }\n}\n\nfragment OrganizationDropdownFragment on Organization {\n name\n}\n"
|
"text": "query OrganizationLayoutQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n ...OrganizationDropdownFragment\n }\n id\n }\n viewer {\n pendingInvitations {\n totalCount\n }\n ...SessionDropdownFragment_4xMPKw\n id\n }\n}\n\nfragment OrganizationDropdownFragment on Organization {\n name\n}\n\nfragment SessionDropdownFragment_4xMPKw on Identity {\n email\n profileFor(organizationId: $organizationId) {\n firstName\n lastName\n id\n }\n}\n"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
(node as any).hash = "2e8a1c50dc999d218830ab3df10cdeb5";
|
(node as any).hash = "d3d91888eabb36cc450ca585757b21c7";
|
||||||
|
|
||||||
export default node;
|
export default node;
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import {
|
||||||
|
DropdownSeparator,
|
||||||
|
IconArrowBoxLeft,
|
||||||
|
IconCircleQuestionmark,
|
||||||
|
IconKey,
|
||||||
|
IconPageTextLine,
|
||||||
|
UserDropdown,
|
||||||
|
UserDropdownItem,
|
||||||
|
useToast,
|
||||||
|
} from "@probo/ui";
|
||||||
|
import { use } from "react";
|
||||||
|
import { PermissionsContext } from "/providers/PermissionsContext";
|
||||||
|
import { graphql } from "relay-runtime";
|
||||||
|
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||||
|
import { useFragment, useMutation } from "react-relay";
|
||||||
|
import { useTranslate } from "@probo/i18n";
|
||||||
|
import type { SessionDropdownFragment$key } from "./__generated__/SessionDropdownFragment.graphql";
|
||||||
|
|
||||||
|
export const fragment = graphql`
|
||||||
|
fragment SessionDropdownFragment on Identity
|
||||||
|
@argumentDefinitions(organizationId: { type: "ID!" }) {
|
||||||
|
email
|
||||||
|
profileFor(organizationId: $organizationId) {
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const signOutMutation = graphql`
|
||||||
|
mutation SessionDropdownSignOutMutation {
|
||||||
|
signOut {
|
||||||
|
success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function SessionDropdown(props: { fKey: SessionDropdownFragment$key }) {
|
||||||
|
const { fKey } = props;
|
||||||
|
|
||||||
|
const { __ } = useTranslate();
|
||||||
|
const organizationId = useOrganizationId();
|
||||||
|
const { isAuthorized } = use(PermissionsContext);
|
||||||
|
const { toast } = useToast();
|
||||||
|
|
||||||
|
const { email, profileFor: profile } =
|
||||||
|
useFragment<SessionDropdownFragment$key>(fragment, fKey);
|
||||||
|
const [signOut] = useMutation(signOutMutation);
|
||||||
|
|
||||||
|
const handleLogout: React.MouseEventHandler<HTMLAnchorElement> = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
signOut({
|
||||||
|
variables: {},
|
||||||
|
onCompleted: () => {
|
||||||
|
window.location.reload();
|
||||||
|
},
|
||||||
|
onError: (e) => {
|
||||||
|
toast({
|
||||||
|
title: __("Error"),
|
||||||
|
description: e.message as string,
|
||||||
|
variant: "error",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: user should always have a default profile
|
||||||
|
const fullName = profile?.firstName
|
||||||
|
? `${profile.firstName} ${profile.lastName}`
|
||||||
|
: email;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UserDropdown fullName={fullName} email={email}>
|
||||||
|
{isAuthorized("Organization", "deleteOrganization") && (
|
||||||
|
<UserDropdownItem
|
||||||
|
to="/api-keys"
|
||||||
|
icon={IconKey}
|
||||||
|
label={__("API Keys")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{isAuthorized("Organization", "listSignableDocuments") && (
|
||||||
|
<UserDropdownItem
|
||||||
|
to={`/organizations/${organizationId}/employee`}
|
||||||
|
icon={IconPageTextLine}
|
||||||
|
label={__("My Signatures")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<UserDropdownItem
|
||||||
|
to="mailto:support@getprobo.com"
|
||||||
|
icon={IconCircleQuestionmark}
|
||||||
|
label={__("Help")}
|
||||||
|
/>
|
||||||
|
<DropdownSeparator />
|
||||||
|
<UserDropdownItem
|
||||||
|
variant="danger"
|
||||||
|
to="/logout"
|
||||||
|
icon={IconArrowBoxLeft}
|
||||||
|
label="Logout"
|
||||||
|
onClick={handleLogout}
|
||||||
|
/>
|
||||||
|
</UserDropdown>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -32,7 +32,6 @@ export function Sidebar() {
|
|||||||
|
|
||||||
const prefix = `/organizations/${organizationId}`;
|
const prefix = `/organizations/${organizationId}`;
|
||||||
|
|
||||||
console.log(isAuthorized("Organization", "listMeetings"));
|
|
||||||
return (
|
return (
|
||||||
<ul className="space-y-[2px]">
|
<ul className="space-y-[2px]">
|
||||||
{isAuthorized("Organization", "listMeetings") && (
|
{isAuthorized("Organization", "listMeetings") && (
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* @generated SignedSource<<ccb8e318151fff4495fb2eaacc671612>>
|
||||||
|
* @lightSyntaxTransform
|
||||||
|
* @nogrep
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ReaderFragment } from 'relay-runtime';
|
||||||
|
import { FragmentRefs } from "relay-runtime";
|
||||||
|
export type SessionDropdownFragment$data = {
|
||||||
|
readonly email: any;
|
||||||
|
readonly profileFor: {
|
||||||
|
readonly firstName: string | null | undefined;
|
||||||
|
readonly lastName: string | null | undefined;
|
||||||
|
} | null | undefined;
|
||||||
|
readonly " $fragmentType": "SessionDropdownFragment";
|
||||||
|
};
|
||||||
|
export type SessionDropdownFragment$key = {
|
||||||
|
readonly " $data"?: SessionDropdownFragment$data;
|
||||||
|
readonly " $fragmentSpreads": FragmentRefs<"SessionDropdownFragment">;
|
||||||
|
};
|
||||||
|
|
||||||
|
const node: ReaderFragment = {
|
||||||
|
"argumentDefinitions": [
|
||||||
|
{
|
||||||
|
"defaultValue": null,
|
||||||
|
"kind": "LocalArgument",
|
||||||
|
"name": "organizationId"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": null,
|
||||||
|
"name": "SessionDropdownFragment",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "email",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"kind": "Variable",
|
||||||
|
"name": "organizationId",
|
||||||
|
"variableName": "organizationId"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"concreteType": "IdentityProfile",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "profileFor",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "firstName",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "lastName",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Identity",
|
||||||
|
"abstractKey": null
|
||||||
|
};
|
||||||
|
|
||||||
|
(node as any).hash = "de1d0f069e5648898cab6a56a394d86f";
|
||||||
|
|
||||||
|
export default node;
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* @generated SignedSource<<8cb399eb2f38eaf3059531ea4bc3fa30>>
|
||||||
|
* @lightSyntaxTransform
|
||||||
|
* @nogrep
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ConcreteRequest } from 'relay-runtime';
|
||||||
|
export type SessionDropdownSignOutMutation$variables = Record<PropertyKey, never>;
|
||||||
|
export type SessionDropdownSignOutMutation$data = {
|
||||||
|
readonly signOut: {
|
||||||
|
readonly success: boolean;
|
||||||
|
} | null | undefined;
|
||||||
|
};
|
||||||
|
export type SessionDropdownSignOutMutation = {
|
||||||
|
response: SessionDropdownSignOutMutation$data;
|
||||||
|
variables: SessionDropdownSignOutMutation$variables;
|
||||||
|
};
|
||||||
|
|
||||||
|
const node: ConcreteRequest = (function(){
|
||||||
|
var v0 = [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "SignOutPayload",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "signOut",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "success",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
];
|
||||||
|
return {
|
||||||
|
"fragment": {
|
||||||
|
"argumentDefinitions": [],
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": null,
|
||||||
|
"name": "SessionDropdownSignOutMutation",
|
||||||
|
"selections": (v0/*: any*/),
|
||||||
|
"type": "Mutation",
|
||||||
|
"abstractKey": null
|
||||||
|
},
|
||||||
|
"kind": "Request",
|
||||||
|
"operation": {
|
||||||
|
"argumentDefinitions": [],
|
||||||
|
"kind": "Operation",
|
||||||
|
"name": "SessionDropdownSignOutMutation",
|
||||||
|
"selections": (v0/*: any*/)
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"cacheID": "a677190a127d7f75d5c629fab236a7a3",
|
||||||
|
"id": null,
|
||||||
|
"metadata": {},
|
||||||
|
"name": "SessionDropdownSignOutMutation",
|
||||||
|
"operationKind": "mutation",
|
||||||
|
"text": "mutation SessionDropdownSignOutMutation {\n signOut {\n success\n }\n}\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
(node as any).hash = "10c9bdf35ab3961c7488973e052cf978";
|
||||||
|
|
||||||
|
export default node;
|
||||||
Reference in New Issue
Block a user