mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
126 lines
4.6 KiB
TypeScript
126 lines
4.6 KiB
TypeScript
"use client";
|
|
|
|
import { FC, Fragment, useEffect, useState } from "react";
|
|
import { observer } from "mobx-react-lite";
|
|
import Link from "next/link";
|
|
import { usePathname, useSearchParams } from "next/navigation";
|
|
import { usePopper } from "react-popper";
|
|
import { LogOut } from "lucide-react";
|
|
import { Popover, Transition } from "@headlessui/react";
|
|
import { Avatar, Button } from "@plane/ui";
|
|
// helpers
|
|
import { API_BASE_URL } from "@/helpers/common.helper";
|
|
import { queryParamGenerator } from "@/helpers/query-param-generator";
|
|
// hooks
|
|
import { useUser } from "@/hooks/store";
|
|
// services
|
|
import { AuthService } from "@/services/auth.service";
|
|
|
|
const authService = new AuthService();
|
|
|
|
export const UserAvatar: FC = observer(() => {
|
|
const pathName = usePathname();
|
|
const searchParams = useSearchParams();
|
|
// query params
|
|
const board = searchParams.get("board") || undefined;
|
|
const labels = searchParams.get("labels") || undefined;
|
|
const state = searchParams.get("state") || undefined;
|
|
const priority = searchParams.get("priority") || undefined;
|
|
const peekId = searchParams.get("peekId") || undefined;
|
|
// hooks
|
|
const { data: currentUser, signOut } = useUser();
|
|
// states
|
|
const [csrfToken, setCsrfToken] = useState<string | undefined>(undefined);
|
|
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
|
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (csrfToken === undefined)
|
|
authService.requestCSRFToken().then((data) => data?.csrf_token && setCsrfToken(data.csrf_token));
|
|
}, [csrfToken]);
|
|
|
|
const { styles, attributes } = usePopper(referenceElement, popperElement, {
|
|
placement: "bottom-end",
|
|
modifiers: [
|
|
{
|
|
name: "offset",
|
|
options: {
|
|
offset: [0, 40],
|
|
},
|
|
},
|
|
],
|
|
});
|
|
|
|
// derived values
|
|
const { queryParam } = queryParamGenerator({ peekId, board, state, priority, labels });
|
|
|
|
return (
|
|
<div className="relative mr-2">
|
|
{currentUser?.id ? (
|
|
<div>
|
|
<Popover as="div">
|
|
<Popover.Button as={Fragment}>
|
|
<button
|
|
ref={setReferenceElement}
|
|
className="flex items-center gap-2 rounded border border-custom-border-200 p-2"
|
|
>
|
|
<Avatar
|
|
name={currentUser?.display_name}
|
|
src={currentUser?.avatar ?? undefined}
|
|
shape="square"
|
|
size="sm"
|
|
showTooltip={false}
|
|
/>
|
|
<h6 className="text-xs font-medium">
|
|
{currentUser?.display_name ||
|
|
`${currentUser?.first_name} ${currentUser?.first_name}` ||
|
|
currentUser?.email ||
|
|
"User"}
|
|
</h6>
|
|
</button>
|
|
</Popover.Button>
|
|
<Transition
|
|
as={Fragment}
|
|
enter="transition ease-out duration-200"
|
|
enterFrom="opacity-0 translate-y-1"
|
|
enterTo="opacity-100 translate-y-0"
|
|
leave="transition ease-in duration-150"
|
|
leaveFrom="opacity-100 translate-y-0"
|
|
leaveTo="opacity-0 translate-y-1"
|
|
>
|
|
<Popover.Panel>
|
|
<div
|
|
className="z-10 overflow-hidden rounded border border-custom-border-200 bg-custom-background-100 shadow-custom-shadow-rg p-1"
|
|
ref={setPopperElement}
|
|
style={styles.popper}
|
|
{...attributes.popper}
|
|
>
|
|
{csrfToken && (
|
|
<form method="POST" action={`${API_BASE_URL}/auth/spaces/sign-out/`} onSubmit={signOut}>
|
|
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} />
|
|
<input type="hidden" name="next_path" value={`${pathName}?${queryParam}`} />
|
|
<button
|
|
type="submit"
|
|
className="flex items-center gap-2 rounded p-2 whitespace-nowrap hover:bg-custom-background-80 text-sm min-w-36 cursor-pointer"
|
|
>
|
|
<LogOut size={12} className="flex-shrink-0 text-red-500" />
|
|
<div>Sign out</div>
|
|
</button>
|
|
</form>
|
|
)}
|
|
</div>
|
|
</Popover.Panel>
|
|
</Transition>
|
|
</Popover>
|
|
</div>
|
|
) : (
|
|
<div className="flex-shrink-0">
|
|
<Link href={`/?next_path=${pathName}?${queryParam}`}>
|
|
<Button variant="outline-primary">Sign in</Button>
|
|
</Link>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
});
|