mirror of
https://github.com/hex248/sprint.git
synced 2026-02-08 02:33:01 +00:00
ProjectSelect component
This commit is contained in:
@@ -3,11 +3,11 @@ import type { IssueResponse, OrganisationResponse, ProjectResponse, UserRecord }
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { CreateIssue } from "@/components/create-issue";
|
import { CreateIssue } from "@/components/create-issue";
|
||||||
import { CreateProject } from "@/components/create-project";
|
|
||||||
import { IssueDetailPane } from "@/components/issue-detail-pane";
|
import { IssueDetailPane } from "@/components/issue-detail-pane";
|
||||||
import { IssuesTable } from "@/components/issues-table";
|
import { IssuesTable } from "@/components/issues-table";
|
||||||
import LogOutButton from "@/components/log-out-button";
|
import LogOutButton from "@/components/log-out-button";
|
||||||
import { OrganisationSelect } from "@/components/organisation-select";
|
import { OrganisationSelect } from "@/components/organisation-select";
|
||||||
|
import { ProjectSelect } from "@/components/project-select";
|
||||||
import SmallUserDisplay from "@/components/small-user-display";
|
import SmallUserDisplay from "@/components/small-user-display";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
@@ -17,16 +17,7 @@ import {
|
|||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import {
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectSeparator,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from "@/components/ui/select";
|
|
||||||
import { getAuthHeaders } from "@/lib/utils";
|
import { getAuthHeaders } from "@/lib/utils";
|
||||||
import { Button } from "./components/ui/button";
|
|
||||||
import { ResizablePanel, ResizablePanelGroup, ResizableSeparator } from "./components/ui/resizable";
|
import { ResizablePanel, ResizablePanelGroup, ResizableSeparator } from "./components/ui/resizable";
|
||||||
|
|
||||||
function Index() {
|
function Index() {
|
||||||
@@ -39,7 +30,6 @@ function Index() {
|
|||||||
const [selectedOrganisation, setSelectedOrganisation] = useState<OrganisationResponse | null>(null);
|
const [selectedOrganisation, setSelectedOrganisation] = useState<OrganisationResponse | null>(null);
|
||||||
|
|
||||||
const [projects, setProjects] = useState<ProjectResponse[]>([]);
|
const [projects, setProjects] = useState<ProjectResponse[]>([]);
|
||||||
const [projectSelectOpen, setProjectSelectOpen] = useState(false);
|
|
||||||
const [selectedProject, setSelectedProject] = useState<ProjectResponse | null>(null);
|
const [selectedProject, setSelectedProject] = useState<ProjectResponse | null>(null);
|
||||||
|
|
||||||
const [issues, setIssues] = useState<IssueResponse[]>([]);
|
const [issues, setIssues] = useState<IssueResponse[]>([]);
|
||||||
@@ -171,62 +161,21 @@ function Index() {
|
|||||||
|
|
||||||
{/* project selection - only shown when organisation is selected */}
|
{/* project selection - only shown when organisation is selected */}
|
||||||
{selectedOrganisation && (
|
{selectedOrganisation && (
|
||||||
<Select
|
<ProjectSelect
|
||||||
value={`${selectedProject?.Project.id}`}
|
projects={projects}
|
||||||
onValueChange={(value) => {
|
selectedProject={selectedProject}
|
||||||
if (value === "NONE") {
|
organisationId={selectedOrganisation?.Organisation.id}
|
||||||
setSelectedProject(null);
|
onSelectedProjectChange={(project) => {
|
||||||
setSelectedIssue(null);
|
|
||||||
setIssues([]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const project = projects.find((p) => p.Project.id === Number(value));
|
|
||||||
if (!project) {
|
|
||||||
console.error(`NO PROJECT FOUND FOR ID: ${value}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setSelectedProject(project);
|
setSelectedProject(project);
|
||||||
setSelectedIssue(null);
|
setSelectedIssue(null);
|
||||||
}}
|
}}
|
||||||
onOpenChange={setProjectSelectOpen}
|
onCreateProject={async (projectId) => {
|
||||||
>
|
if (!selectedOrganisation) return;
|
||||||
<SelectTrigger className="text-sm" isOpen={projectSelectOpen}>
|
await refetchProjects(selectedOrganisation.Organisation.id, {
|
||||||
<SelectValue
|
selectProjectId: projectId,
|
||||||
placeholder={
|
});
|
||||||
selectedProject
|
}}
|
||||||
? `P: ${selectedProject.Project.name}`
|
/>
|
||||||
: "Select Project"
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent side="bottom" position="popper" align={"start"}>
|
|
||||||
{projects.map((project) => (
|
|
||||||
<SelectItem key={project.Project.id} value={`${project.Project.id}`}>
|
|
||||||
{project.Project.name}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
{projects.length > 0 && <SelectSeparator />}
|
|
||||||
<CreateProject
|
|
||||||
organisationId={selectedOrganisation?.Organisation.id}
|
|
||||||
trigger={
|
|
||||||
<Button
|
|
||||||
size={"sm"}
|
|
||||||
variant="ghost"
|
|
||||||
className={"w-full"}
|
|
||||||
disabled={!selectedOrganisation?.Organisation.id}
|
|
||||||
>
|
|
||||||
Create Project
|
|
||||||
</Button>
|
|
||||||
}
|
|
||||||
completeAction={async (projectId) => {
|
|
||||||
if (!selectedOrganisation) return;
|
|
||||||
await refetchProjects(selectedOrganisation.Organisation.id, {
|
|
||||||
selectProjectId: projectId,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
)}
|
)}
|
||||||
{selectedOrganisation && selectedProject && (
|
{selectedOrganisation && selectedProject && (
|
||||||
<CreateIssue
|
<CreateIssue
|
||||||
|
|||||||
74
packages/frontend/src/components/project-select.tsx
Normal file
74
packages/frontend/src/components/project-select.tsx
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import type { ProjectResponse } from "@issue/shared";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { CreateProject } from "@/components/create-project";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectSeparator,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
|
||||||
|
export function ProjectSelect({
|
||||||
|
projects,
|
||||||
|
selectedProject,
|
||||||
|
organisationId,
|
||||||
|
onSelectedProjectChange,
|
||||||
|
onCreateProject,
|
||||||
|
placeholder = "Select Project",
|
||||||
|
}: {
|
||||||
|
projects: ProjectResponse[];
|
||||||
|
selectedProject: ProjectResponse | null;
|
||||||
|
organisationId: number | undefined;
|
||||||
|
onSelectedProjectChange: (project: ProjectResponse | null) => void;
|
||||||
|
onCreateProject?: (projectId: number) => void | Promise<void>;
|
||||||
|
placeholder?: string;
|
||||||
|
}) {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
value={selectedProject ? `${selectedProject.Project.id}` : undefined}
|
||||||
|
onValueChange={(value) => {
|
||||||
|
const project = projects.find((p) => p.Project.id === Number(value));
|
||||||
|
if (!project) {
|
||||||
|
console.error(`NO PROJECT FOUND FOR ID: ${value}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onSelectedProjectChange(project);
|
||||||
|
}}
|
||||||
|
onOpenChange={setOpen}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="text-sm" isOpen={open}>
|
||||||
|
<SelectValue
|
||||||
|
placeholder={selectedProject ? `P: ${selectedProject.Project.name}` : placeholder}
|
||||||
|
/>
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent side="bottom" position="popper" align={"start"}>
|
||||||
|
{projects.map((project) => (
|
||||||
|
<SelectItem key={project.Project.id} value={`${project.Project.id}`}>
|
||||||
|
{project.Project.name}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
{projects.length > 0 && <SelectSeparator />}
|
||||||
|
<CreateProject
|
||||||
|
organisationId={organisationId}
|
||||||
|
trigger={
|
||||||
|
<Button size={"sm"} variant="ghost" className={"w-full"} disabled={!organisationId}>
|
||||||
|
Create Project
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
completeAction={async (projectId) => {
|
||||||
|
try {
|
||||||
|
await onCreateProject?.(projectId);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user