2022-11-19 14:21:26 +00:00
|
|
|
// React
|
|
|
|
import React, { useState } from "react";
|
|
|
|
// next
|
|
|
|
import Link from "next/link";
|
|
|
|
import useSWR from "swr";
|
2022-12-07 04:45:57 +00:00
|
|
|
// hooks
|
2022-11-19 14:21:26 +00:00
|
|
|
import useUser from "lib/hooks/useUser";
|
|
|
|
// Services
|
|
|
|
import projectService from "lib/services/project.service";
|
2022-12-07 04:45:57 +00:00
|
|
|
// fetch keys
|
|
|
|
import { PROJECT_MEMBERS } from "constants/fetch-keys";
|
|
|
|
// commons
|
|
|
|
import { renderShortNumericDateFormat } from "constants/common";
|
2022-11-19 14:21:26 +00:00
|
|
|
// icons
|
|
|
|
import {
|
|
|
|
CalendarDaysIcon,
|
|
|
|
CheckIcon,
|
|
|
|
EyeIcon,
|
|
|
|
MinusIcon,
|
|
|
|
PencilIcon,
|
|
|
|
PlusIcon,
|
|
|
|
TrashIcon,
|
|
|
|
} from "@heroicons/react/24/outline";
|
2022-12-07 04:45:57 +00:00
|
|
|
// types
|
|
|
|
import type { IProject } from "types";
|
|
|
|
type Props = {
|
|
|
|
project: IProject;
|
|
|
|
slug: string;
|
|
|
|
invitationsRespond: string[];
|
|
|
|
handleInvitation: (project_invitation: any, action: "accepted" | "withdraw") => void;
|
2022-12-12 08:38:11 +00:00
|
|
|
setDeleteProject: (id: string | null) => void;
|
2022-12-07 04:45:57 +00:00
|
|
|
};
|
2022-11-19 14:21:26 +00:00
|
|
|
|
2022-12-07 04:45:57 +00:00
|
|
|
const ProjectMemberInvitations: React.FC<Props> = ({
|
2022-11-19 14:21:26 +00:00
|
|
|
project,
|
|
|
|
slug,
|
|
|
|
invitationsRespond,
|
|
|
|
handleInvitation,
|
|
|
|
setDeleteProject,
|
2022-12-07 04:45:57 +00:00
|
|
|
}) => {
|
2022-11-19 14:21:26 +00:00
|
|
|
const { user } = useUser();
|
2022-12-07 04:45:57 +00:00
|
|
|
|
|
|
|
const { data: members } = useSWR<any[]>(PROJECT_MEMBERS(project.id), () =>
|
2022-11-19 14:21:26 +00:00
|
|
|
projectService.projectMembers(slug, project.id)
|
|
|
|
);
|
|
|
|
|
2022-12-07 04:45:57 +00:00
|
|
|
const isMember = members?.some((item: any) => item.member.id === (user as any)?.id);
|
2022-11-19 14:21:26 +00:00
|
|
|
|
|
|
|
const [selected, setSelected] = useState<any>(false);
|
|
|
|
|
2022-12-07 04:45:57 +00:00
|
|
|
if (!members) {
|
|
|
|
return (
|
|
|
|
<div className="w-full h-36 flex flex-col px-4 py-3 rounded-md bg-white">
|
|
|
|
<div className="w-full h-full bg-gray-50 animate-pulse" />
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-11-19 14:21:26 +00:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<div
|
2022-11-29 14:19:39 +00:00
|
|
|
className={`w-full h-full flex flex-col px-4 py-3 rounded-md bg-white ${
|
2022-11-19 14:21:26 +00:00
|
|
|
selected ? "ring-2 ring-indigo-400" : ""
|
|
|
|
}`}
|
|
|
|
>
|
|
|
|
<div className="flex justify-between items-center">
|
|
|
|
<div className="font-medium text-lg flex gap-2">
|
|
|
|
{!isMember ? (
|
|
|
|
<input
|
|
|
|
id={project.id}
|
|
|
|
className="h-3 w-3 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 mt-2 hidden"
|
|
|
|
aria-describedby="workspaces"
|
|
|
|
name={project.id}
|
|
|
|
checked={invitationsRespond.includes(project.id)}
|
|
|
|
value={project.name}
|
|
|
|
onChange={(e) => {
|
|
|
|
setSelected(e.target.checked);
|
|
|
|
handleInvitation(
|
|
|
|
project,
|
|
|
|
invitationsRespond.includes(project.id) ? "withdraw" : "accepted"
|
|
|
|
);
|
|
|
|
}}
|
|
|
|
type="checkbox"
|
|
|
|
/>
|
|
|
|
) : null}
|
|
|
|
<Link href={`/projects/${project.id}/issues`}>
|
|
|
|
<a className="flex flex-col">
|
|
|
|
{project.name}
|
|
|
|
<span className="text-xs">({project.identifier})</span>
|
|
|
|
</a>
|
|
|
|
</Link>
|
|
|
|
</div>
|
|
|
|
{isMember ? (
|
|
|
|
<div className="flex">
|
|
|
|
<Link href={`/projects/${project.id}/settings`}>
|
|
|
|
<a className="h-7 w-7 p-1 grid place-items-center rounded hover:bg-gray-200 duration-300 cursor-pointer">
|
|
|
|
<PencilIcon className="h-4 w-4" />
|
|
|
|
</a>
|
|
|
|
</Link>
|
|
|
|
<button
|
|
|
|
type="button"
|
|
|
|
className="h-7 w-7 p-1 grid place-items-center rounded hover:bg-gray-200 duration-300 outline-none"
|
2022-12-12 08:38:11 +00:00
|
|
|
onClick={() => setDeleteProject(project.id)}
|
2022-11-19 14:21:26 +00:00
|
|
|
>
|
|
|
|
<TrashIcon className="h-4 w-4 text-red-500" />
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
) : null}
|
|
|
|
</div>
|
|
|
|
<div className="mt-2">
|
|
|
|
<p className="text-sm">{project.description}</p>
|
|
|
|
</div>
|
|
|
|
<div className="mt-3 h-full flex justify-between items-end">
|
|
|
|
<div className="flex gap-2">
|
|
|
|
{!isMember ? (
|
|
|
|
<label
|
|
|
|
htmlFor={project.id}
|
|
|
|
className="flex items-center gap-1 text-xs font-medium bg-blue-200 hover:bg-blue-300 p-2 rounded duration-300 cursor-pointer"
|
|
|
|
>
|
|
|
|
{selected ? (
|
|
|
|
<>
|
|
|
|
<MinusIcon className="h-3 w-3" />
|
|
|
|
Remove
|
|
|
|
</>
|
|
|
|
) : (
|
|
|
|
<>
|
|
|
|
<PlusIcon className="h-3 w-3" />
|
|
|
|
Select to Join
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</label>
|
|
|
|
) : (
|
|
|
|
<span className="flex items-center gap-1 text-xs bg-green-200 p-2 rounded">
|
|
|
|
<CheckIcon className="h-3 w-3" />
|
|
|
|
Member
|
|
|
|
</span>
|
|
|
|
)}
|
|
|
|
<Link href={`/projects/${project.id}/issues`}>
|
|
|
|
<a className="flex items-center gap-1 text-xs font-medium bg-blue-200 hover:bg-blue-300 p-2 rounded duration-300">
|
|
|
|
<EyeIcon className="h-3 w-3" />
|
|
|
|
View
|
|
|
|
</a>
|
|
|
|
</Link>
|
|
|
|
</div>
|
|
|
|
<div className="flex items-center gap-1 text-xs mb-1">
|
|
|
|
<CalendarDaysIcon className="h-4 w-4" />
|
|
|
|
{renderShortNumericDateFormat(project.created_at)}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default ProjectMemberInvitations;
|