forked from github/plane
chore : dropdown loading state added and project card avatar fix (#2643)
* chore: project card avatar rendering fix * chore: state, assignee and label dropdown loading state added
This commit is contained in:
parent
ad558833af
commit
52395d0563
@ -47,11 +47,17 @@ export const IssuePropertyAssignee: React.FC<IIssuePropertyAssignee> = observer(
|
|||||||
|
|
||||||
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
||||||
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
||||||
|
const [isLoading, setIsLoading] = useState<Boolean>(false);
|
||||||
|
|
||||||
const projectMembers = projectId ? projectStore?.members?.[projectId] : undefined;
|
const projectMembers = projectId ? projectStore?.members?.[projectId] : undefined;
|
||||||
|
|
||||||
const fetchProjectMembers = () =>
|
const fetchProjectMembers = () => {
|
||||||
workspaceSlug && projectId && projectStore.fetchProjectMembers(workspaceSlug, projectId);
|
setIsLoading(true);
|
||||||
|
if (workspaceSlug && projectId)
|
||||||
|
workspaceSlug &&
|
||||||
|
projectId &&
|
||||||
|
projectStore.fetchProjectMembers(workspaceSlug, projectId).then(() => setIsLoading(false));
|
||||||
|
};
|
||||||
|
|
||||||
const options = (projectMembers ?? [])?.map((member) => ({
|
const options = (projectMembers ?? [])?.map((member) => ({
|
||||||
value: member.member.id,
|
value: member.member.id,
|
||||||
@ -128,7 +134,7 @@ export const IssuePropertyAssignee: React.FC<IIssuePropertyAssignee> = observer(
|
|||||||
className={`flex items-center justify-between gap-1 w-full text-xs ${
|
className={`flex items-center justify-between gap-1 w-full text-xs ${
|
||||||
disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80"
|
disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80"
|
||||||
} ${buttonClassName}`}
|
} ${buttonClassName}`}
|
||||||
onClick={() => fetchProjectMembers()}
|
onClick={() => !projectMembers && fetchProjectMembers()}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
{!hideDropdownArrow && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
|
{!hideDropdownArrow && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
|
||||||
@ -152,8 +158,9 @@ export const IssuePropertyAssignee: React.FC<IIssuePropertyAssignee> = observer(
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={`mt-2 space-y-1 max-h-48 overflow-y-scroll`}>
|
<div className={`mt-2 space-y-1 max-h-48 overflow-y-scroll`}>
|
||||||
{filteredOptions ? (
|
{isLoading ? (
|
||||||
filteredOptions.length > 0 ? (
|
<p className="text-center text-custom-text-200">Loading...</p>
|
||||||
|
) : filteredOptions.length > 0 ? (
|
||||||
filteredOptions.map((option) => (
|
filteredOptions.map((option) => (
|
||||||
<Combobox.Option
|
<Combobox.Option
|
||||||
key={option.value}
|
key={option.value}
|
||||||
@ -176,9 +183,6 @@ export const IssuePropertyAssignee: React.FC<IIssuePropertyAssignee> = observer(
|
|||||||
<span className="flex items-center gap-2 p-1">
|
<span className="flex items-center gap-2 p-1">
|
||||||
<p className="text-left text-custom-text-200 ">No matching results</p>
|
<p className="text-left text-custom-text-200 ">No matching results</p>
|
||||||
</span>
|
</span>
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<p className="text-center text-custom-text-200">Loading...</p>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -51,11 +51,15 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
|
|||||||
|
|
||||||
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
||||||
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
||||||
|
const [isLoading, setIsLoading] = useState<Boolean>(false);
|
||||||
|
|
||||||
const projectLabels = projectId && projectStore?.labels?.[projectId];
|
const projectLabels = projectId && projectStore?.labels?.[projectId];
|
||||||
|
|
||||||
const fetchProjectLabels = () =>
|
const fetchProjectLabels = () => {
|
||||||
workspaceSlug && projectId && projectStore.fetchProjectLabels(workspaceSlug, projectId);
|
setIsLoading(true);
|
||||||
|
if (workspaceSlug && projectId)
|
||||||
|
projectStore.fetchProjectLabels(workspaceSlug, projectId).then(() => setIsLoading(false));
|
||||||
|
};
|
||||||
|
|
||||||
const options = (projectLabels ? projectLabels : []).map((label) => ({
|
const options = (projectLabels ? projectLabels : []).map((label) => ({
|
||||||
value: label.id,
|
value: label.id,
|
||||||
@ -161,7 +165,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
|
|||||||
? "cursor-pointer"
|
? "cursor-pointer"
|
||||||
: "cursor-pointer hover:bg-custom-background-80"
|
: "cursor-pointer hover:bg-custom-background-80"
|
||||||
} ${buttonClassName}`}
|
} ${buttonClassName}`}
|
||||||
onClick={() => fetchProjectLabels()}
|
onClick={() => !projectLabels && fetchProjectLabels()}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
{!hideDropdownArrow && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
|
{!hideDropdownArrow && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
|
||||||
@ -186,8 +190,9 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={`mt-2 space-y-1 max-h-48 overflow-y-scroll`}>
|
<div className={`mt-2 space-y-1 max-h-48 overflow-y-scroll`}>
|
||||||
{filteredOptions ? (
|
{isLoading ? (
|
||||||
filteredOptions.length > 0 ? (
|
<p className="text-center text-custom-text-200">Loading...</p>
|
||||||
|
) : filteredOptions.length > 0 ? (
|
||||||
filteredOptions.map((option) => (
|
filteredOptions.map((option) => (
|
||||||
<Combobox.Option
|
<Combobox.Option
|
||||||
key={option.value}
|
key={option.value}
|
||||||
@ -210,9 +215,6 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
|
|||||||
<span className="flex items-center gap-2 p-1">
|
<span className="flex items-center gap-2 p-1">
|
||||||
<p className="text-left text-custom-text-200 ">No matching results</p>
|
<p className="text-left text-custom-text-200 ">No matching results</p>
|
||||||
</span>
|
</span>
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<p className="text-center text-custom-text-200">Loading...</p>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -47,14 +47,20 @@ export const IssuePropertyState: React.FC<IIssuePropertyState> = observer((props
|
|||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
||||||
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
||||||
|
const [isLoading, setIsLoading] = useState<Boolean>(false);
|
||||||
|
|
||||||
const projectStates: IState[] = [];
|
const projectStates: IState[] = [];
|
||||||
const projectStatesByGroup = projectId && projectStore?.states?.[projectId];
|
const projectStatesByGroup = projectId && projectStore?.states?.[projectId];
|
||||||
if (projectStatesByGroup)
|
if (projectStatesByGroup)
|
||||||
for (const group in projectStatesByGroup) projectStates.push(...projectStatesByGroup[group]);
|
for (const group in projectStatesByGroup) projectStates.push(...projectStatesByGroup[group]);
|
||||||
|
|
||||||
const fetchProjectStates = () =>
|
const fetchProjectStates = () => {
|
||||||
workspaceSlug && projectId && projectStore.fetchProjectStates(workspaceSlug, projectId);
|
setIsLoading(true);
|
||||||
|
if (workspaceSlug && projectId)
|
||||||
|
workspaceSlug &&
|
||||||
|
projectId &&
|
||||||
|
projectStore.fetchProjectStates(workspaceSlug, projectId).then(() => setIsLoading(false));
|
||||||
|
};
|
||||||
|
|
||||||
const dropdownOptions = projectStates?.map((state) => ({
|
const dropdownOptions = projectStates?.map((state) => ({
|
||||||
value: state.id,
|
value: state.id,
|
||||||
@ -113,7 +119,7 @@ export const IssuePropertyState: React.FC<IIssuePropertyState> = observer((props
|
|||||||
className={`flex items-center justify-between gap-1 w-full text-xs px-2.5 py-1 rounded border-[0.5px] border-custom-border-300 ${
|
className={`flex items-center justify-between gap-1 w-full text-xs px-2.5 py-1 rounded border-[0.5px] border-custom-border-300 ${
|
||||||
disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80"
|
disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80"
|
||||||
} ${buttonClassName}`}
|
} ${buttonClassName}`}
|
||||||
onClick={() => fetchProjectStates()}
|
onClick={() => !projectStatesByGroup && fetchProjectStates()}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
{!hideDropdownArrow && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
|
{!hideDropdownArrow && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
|
||||||
@ -137,8 +143,9 @@ export const IssuePropertyState: React.FC<IIssuePropertyState> = observer((props
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={`mt-2 space-y-1 max-h-48 overflow-y-scroll`}>
|
<div className={`mt-2 space-y-1 max-h-48 overflow-y-scroll`}>
|
||||||
{filteredOptions ? (
|
{isLoading ? (
|
||||||
filteredOptions.length > 0 ? (
|
<p className="text-center text-custom-text-200">Loading...</p>
|
||||||
|
) : filteredOptions.length > 0 ? (
|
||||||
filteredOptions.map((option) => (
|
filteredOptions.map((option) => (
|
||||||
<Combobox.Option
|
<Combobox.Option
|
||||||
key={option.value}
|
key={option.value}
|
||||||
@ -161,9 +168,6 @@ export const IssuePropertyState: React.FC<IIssuePropertyState> = observer((props
|
|||||||
<span className="flex items-center gap-2 p-1">
|
<span className="flex items-center gap-2 p-1">
|
||||||
<p className="text-left text-custom-text-200 ">No matching results</p>
|
<p className="text-left text-custom-text-200 ">No matching results</p>
|
||||||
</span>
|
</span>
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<p className="text-center text-custom-text-200">Loading...</p>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -181,7 +181,7 @@ export const ProjectCard: React.FC<ProjectCardProps> = observer((props) => {
|
|||||||
<div className="flex items-center cursor-pointer gap-2 text-custom-text-200">
|
<div className="flex items-center cursor-pointer gap-2 text-custom-text-200">
|
||||||
<AvatarGroup showTooltip={false}>
|
<AvatarGroup showTooltip={false}>
|
||||||
{projectMembersIds.map((memberId) => {
|
{projectMembersIds.map((memberId) => {
|
||||||
const member = project.members?.find((m) => m.id === memberId);
|
const member = project.members?.find((m) => m.member_id === memberId);
|
||||||
|
|
||||||
if (!member) return null;
|
if (!member) return null;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user