Merge public-gh/master into paperclip-company-import-export

This commit is contained in:
Dotta
2026-03-16 07:38:08 -05:00
28 changed files with 863 additions and 37 deletions

View File

@@ -285,7 +285,7 @@ export function OrgChart() {
</div>
<div
ref={containerRef}
className="w-full h-[calc(100vh-7rem)] overflow-hidden relative bg-muted/20 border border-border rounded-lg"
className="w-full h-[calc(100dvh-6rem)] overflow-hidden relative bg-muted/20 border border-border rounded-lg"
style={{ cursor: dragging ? "grabbing" : "grab" }}
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}

View File

@@ -274,6 +274,21 @@ export function ProjectDetail() {
onSuccess: invalidateProject,
});
const archiveProject = useMutation({
mutationFn: (archived: boolean) =>
projectsApi.update(
projectLookupRef,
{ archivedAt: archived ? new Date().toISOString() : null },
resolvedCompanyId ?? lookupCompanyId,
),
onSuccess: (_, archived) => {
invalidateProject();
if (archived) {
navigate("/projects");
}
},
});
const uploadImage = useMutation({
mutationFn: async (file: File) => {
if (!resolvedCompanyId) throw new Error("No company selected");
@@ -476,6 +491,8 @@ export function ProjectDetail() {
onUpdate={(data) => updateProject.mutate(data)}
onFieldUpdate={updateProjectField}
getFieldSaveState={(field) => fieldSaveStates[field] ?? "idle"}
onArchive={(archived) => archiveProject.mutate(archived)}
archivePending={archiveProject.isPending}
/>
</div>
)}

View File

@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useMemo } from "react";
import { useQuery } from "@tanstack/react-query";
import { projectsApi } from "../api/projects";
import { useCompany } from "../context/CompanyContext";
@@ -22,11 +22,15 @@ export function Projects() {
setBreadcrumbs([{ label: "Projects" }]);
}, [setBreadcrumbs]);
const { data: projects, isLoading, error } = useQuery({
const { data: allProjects, isLoading, error } = useQuery({
queryKey: queryKeys.projects.list(selectedCompanyId!),
queryFn: () => projectsApi.list(selectedCompanyId!),
enabled: !!selectedCompanyId,
});
const projects = useMemo(
() => (allProjects ?? []).filter((p) => !p.archivedAt),
[allProjects],
);
if (!selectedCompanyId) {
return <EmptyState icon={Hexagon} message="Select a company to view projects." />;
@@ -47,7 +51,7 @@ export function Projects() {
{error && <p className="text-sm text-destructive">{error.message}</p>}
{projects && projects.length === 0 && (
{!isLoading && projects.length === 0 && (
<EmptyState
icon={Hexagon}
message="No projects yet."
@@ -56,7 +60,7 @@ export function Projects() {
/>
)}
{projects && projects.length > 0 && (
{projects.length > 0 && (
<div className="border border-border">
{projects.map((project) => (
<EntityRow