+
setDraft((current) => ({ ...current, ...patch }))}
onToggleTag={(tagId) => setDraft((current) => ({ ...current, tags: toggleTagId(current.tags, tagId) }))}
onProjectChange={(projectId) => void commitPatchedDraft({ projectId })}
- projects={projects}
- tags={tags}
+ projects={editorProjects}
+ tags={editorTags}
t={t}
isRtl={false}
compact
@@ -1413,6 +1640,7 @@ function MobileRecordedEntryCard({
onEdit,
onDelete,
onRequestRestart,
+ lang,
}: {
entry: TimeEntry;
t: any;
@@ -1421,9 +1649,12 @@ function MobileRecordedEntryCard({
onEdit: (entry: TimeEntry) => void;
onDelete: (entry: TimeEntry) => void;
onRequestRestart: (entry: TimeEntry) => void;
+ lang: "en" | "fa";
}) {
- const project = projects.find((item) => item.id === entry.project);
- const entryTags = tags.filter((tag) => entry.tags.includes(tag.id));
+ const deletedProjectLabel = t.timesheet?.deletedProjectLabel || "Deleted project";
+ const deletedTagLabel = t.timesheet?.deletedTagLabel || "Deleted tag";
+ const project = getProjectDisplayDetails(entry, projects);
+ const entryTags = getTagDisplayDetails(entry, tags);
const wrapperRef = useRef(null);
const buttonRef = useRef(null);
const dropdownRef = useRef(null);
@@ -1554,18 +1785,20 @@ function MobileRecordedEntryCard({
{project && (
{"\u2022"}
- {project.name}
+
+ {project.isDeleted ? buildDeletedProjectLabel(project.name, deletedProjectLabel) : project.name}
+
)}
- {project?.client?.name && (
+ {project?.clientName && (
- - {project.client.name}
+ - {project.clientName}
)}
- {formatTimeOnly(entry.start_time)} - {formatTimeOnly(entry.end_time)}
+ {formatTimeOnly(entry.start_time, lang)} - {formatTimeOnly(entry.end_time, lang)}
{entryTags.length > 0 && (
- {entryTags.map((tag) => tag.name).join(" | ")}
+ {entryTags
+ .map((tag) => (tag.isDeleted ? buildDeletedTagLabel(tag.name, deletedTagLabel) : tag.name))
+ .join(" | ")}
)}
{entry.is_billable && (
@@ -1662,6 +1897,8 @@ export default function Timesheet() {
fromFilterPrefix?: string;
toFilterPrefix?: string;
restartConfirmMessage?: string;
+ deletedProjectLabel?: string;
+ deletedTagLabel?: string;
}) || {};
const [projects, setProjects] = useState
([]);
@@ -1708,6 +1945,24 @@ export default function Timesheet() {
const [isDiscardingTimer, setIsDiscardingTimer] = useState(false);
const runningEntry = activeRunningEntry;
+ const deletedProjectLabel = extendedTimesheet.deletedProjectLabel || "Deleted project";
+ const deletedTagLabel = extendedTimesheet.deletedTagLabel || "Deleted tag";
+ const runningTimerProjects = useMemo(
+ () => buildProjectOptionsForEntry(projects, runningEntry, timerDraft.projectId, deletedProjectLabel),
+ [deletedProjectLabel, projects, runningEntry, timerDraft.projectId],
+ );
+ const runningTimerTags = useMemo(
+ () => buildTagOptionsForEntry(tags, runningEntry, timerDraft.tags),
+ [runningEntry, tags, timerDraft.tags],
+ );
+ const modalProjects = useMemo(
+ () => buildProjectOptionsForEntry(projects, editingEntry, formState.projectId, deletedProjectLabel),
+ [deletedProjectLabel, editingEntry, formState.projectId, projects],
+ );
+ const modalTags = useMemo(
+ () => buildTagOptionsForEntry(tags, editingEntry, formState.tags),
+ [editingEntry, formState.tags, tags],
+ );
useEffect(() => {
if (!runningEntry) return;
@@ -2016,11 +2271,15 @@ export default function Timesheet() {
if (!activeWorkspace?.id || runningEntry) return;
try {
+ const restartProjectId = entry.project_details?.is_deleted ? null : entry.project;
+ const restartTagIds = (entry.tag_details || [])
+ .filter((tag) => !tag.is_deleted)
+ .map((tag) => tag.id);
await createTimeEntry({
workspace_id: activeWorkspace.id,
description: entry.description,
- project_id: entry.project,
- tags: entry.tags,
+ project_id: restartProjectId,
+ tags: restartTagIds,
is_billable: entry.is_billable,
start_time: new Date().toISOString(),
});
@@ -2166,10 +2425,10 @@ export default function Timesheet() {
-
-
+
+
setTimerDraft((current) => ({ ...current, projectId: String(value) }))}
options={[
{ value: "", label: t.timesheet?.projectLabel || "Project" },
- ...projects.map((project) => ({ value: project.id, label: project.name })),
+ ...runningTimerProjects.map((project) => ({ value: project.id, label: project.name })),
]}
- className="min-w-[170px]"
+ className="min-w-[190px] max-w-[220px]"
buttonClassName="h-12 w-full rounded-none border-0 bg-transparent px-3 text-sm text-sky-600 shadow-none outline-none dark:bg-transparent dark:text-sky-400 focus:ring-0 focus-visible:ring-0 focus-visible:ring-offset-0"
disabled={isStartingTimer}
portalOwnerId={timerEditorOwnerId}
/>
-
+
setTimerDraft((current) => ({ ...current, tags: toggleTagId(current.tags, tagId) }))
@@ -2205,6 +2464,8 @@ export default function Timesheet() {
title={t.tags?.title || "Tags"}
compact
portalOwnerId={timerEditorOwnerId}
+ className="max-w-[240px]"
+ buttonClassName="max-w-[240px]"
/>
@@ -2264,6 +2525,106 @@ export default function Timesheet() {
+
+
+
setTimerDraft((current) => ({ ...current, description: event.target.value }))}
+ disabled={isStartingTimer}
+ className="h-11 border-slate-200 bg-slate-50 text-sm dark:border-slate-700 dark:bg-slate-900"
+ />
+
+
+
+
+
+
setTimerDraft((current) => ({ ...current, isBillable: checked }))}
+ label={t.timesheet?.billable || "Billable"}
+ disabled={isStartingTimer}
+ />
+
+
+ {runningEntry ? (
+ <>
+
+
+ >
+ ) : (
+
+ )}
+
+
+
+
+
setTimerDraft((current) => ({ ...current, projectId: String(value) }))}
options={[
{ value: "", label: t.timesheet?.projectLabel || "Project" },
- ...projects.map((project) => ({ value: project.id, label: project.name })),
+ ...runningTimerProjects.map((project) => ({ value: project.id, label: project.name })),
]}
className="w-full"
buttonClassName="h-10 w-full rounded-md border border-slate-200 bg-slate-50 px-3 text-sm shadow-none outline-none dark:border-slate-700 dark:bg-slate-900 focus:ring-0 focus-visible:ring-0 focus-visible:ring-offset-0"
@@ -2300,7 +2661,7 @@ export default function Timesheet() {
setTimerDraft((current) => ({ ...current, tags: toggleTagId(current.tags, tagId) }))
@@ -2428,7 +2789,7 @@ export default function Timesheet() {
{day.entries.map((entry) => (
-
+
+
+
+
@@ -2448,6 +2823,7 @@ export default function Timesheet() {
onEdit={openEditModal}
onDelete={openDeleteModal}
onRequestRestart={openRestartModal}
+ lang={lang}
/>
@@ -2488,8 +2864,8 @@ export default function Timesheet() {
state={formState}
onChange={(patch) => setFormState((current) => ({ ...current, ...patch }))}
onToggleTag={(tagId) => setFormState((current) => ({ ...current, tags: toggleTagId(current.tags, tagId) }))}
- projects={projects}
- tags={tags}
+ projects={modalProjects}
+ tags={modalTags}
t={t}
isRtl={isRtl}
/>