feat(i18n): Add Polish translations for task management components and update search placeholder

This commit is contained in:
Chop
2025-07-27 23:54:56 +02:00
parent e828aa660b
commit 747a68832e
4 changed files with 74 additions and 72 deletions

View File

@@ -6,8 +6,8 @@ export default function ProjectTasksPage() {
return ( return (
<PageContainer> <PageContainer>
<PageHeader <PageHeader
title="Project Tasks" title="Zadania projektów"
description="View and manage tasks across all projects in a structured list format" description="Przeglądaj i zarządzaj zadaniami wszystkich projektów w ustrukturyzowanym formacie listy"
/> />
<ProjectTasksList /> <ProjectTasksList />
</PageContainer> </PageContainer>

View File

@@ -15,8 +15,10 @@ import {
formatDistanceToNow, formatDistanceToNow,
} from "date-fns"; } from "date-fns";
import { formatDate } from "@/lib/utils"; import { formatDate } from "@/lib/utils";
import { useTranslation } from "@/lib/i18n";
export default function ProjectTasksList() { export default function ProjectTasksList() {
const { t } = useTranslation();
const [allTasks, setAllTasks] = useState([]); const [allTasks, setAllTasks] = useState([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
@@ -210,7 +212,7 @@ export default function ProjectTasksList() {
// Group tasks by task name when groupBy is set to "task_name" // Group tasks by task name when groupBy is set to "task_name"
const groupTasksByName = (tasks) => { const groupTasksByName = (tasks) => {
if (groupBy !== "task_name") return { "All Tasks": tasks }; if (groupBy !== "task_name") return { [t("tasks.allTasks")]: tasks };
const groups = {}; const groups = {};
tasks.forEach((task) => { tasks.forEach((task) => {
@@ -238,10 +240,10 @@ export default function ProjectTasksList() {
const tasks = await res2.json(); const tasks = await res2.json();
setAllTasks(tasks); setAllTasks(tasks);
} else { } else {
alert("Failed to update task status"); alert(t("errors.generic"));
} }
} catch (error) { } catch (error) {
alert("Error updating task status"); alert(t("errors.generic"));
} }
}; };
@@ -281,7 +283,7 @@ export default function ProjectTasksList() {
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span className="font-medium text-gray-900">{task.task_name}</span> <span className="font-medium text-gray-900">{task.task_name}</span>
<Badge variant={getPriorityVariant(task.priority)} size="sm"> <Badge variant={getPriorityVariant(task.priority)} size="sm">
{task.priority} {t(`tasks.${task.priority}`)}
</Badge> </Badge>
</div> </div>
</td> </td>
@@ -307,7 +309,7 @@ export default function ProjectTasksList() {
</div> </div>
</div> </div>
) : ( ) : (
<span className="text-gray-400 italic">Unassigned</span> <span className="text-gray-400 italic">{t("projects.unassigned")}</span>
)} )}
</td> </td>
{showTimeLeft && ( {showTimeLeft && (
@@ -322,9 +324,9 @@ export default function ProjectTasksList() {
> >
{!isNaN(task.statusInfo.daysRemaining) {!isNaN(task.statusInfo.daysRemaining)
? task.statusInfo.daysRemaining > 0 ? task.statusInfo.daysRemaining > 0
? `${task.statusInfo.daysRemaining}d left` ? `${task.statusInfo.daysRemaining}${t("tasks.daysLeft")}`
: `${Math.abs(task.statusInfo.daysRemaining)}d overdue` : `${Math.abs(task.statusInfo.daysRemaining)}${t("tasks.daysOverdue")}`
: "Calculating..."} : t("common.loading")}
</Badge> </Badge>
)} )}
{task.statusInfo && {task.statusInfo &&
@@ -332,8 +334,8 @@ export default function ProjectTasksList() {
task.status === "in_progress" && ( task.status === "in_progress" && (
<Badge variant="danger" size="sm"> <Badge variant="danger" size="sm">
{!isNaN(task.statusInfo.daysRemaining) {!isNaN(task.statusInfo.daysRemaining)
? `${Math.abs(task.statusInfo.daysRemaining)}d overdue` ? `${Math.abs(task.statusInfo.daysRemaining)}${t("tasks.daysOverdue")}`
: "Overdue"} : t("tasks.overdue")}
</Badge> </Badge>
)} )}
</div> </div>
@@ -343,7 +345,7 @@ export default function ProjectTasksList() {
{task.status === "completed" && task.date_completed ? ( {task.status === "completed" && task.date_completed ? (
<div> <div>
<div> <div>
Completed:{" "} {t("taskStatus.completed")}:{" "}
{(() => { {(() => {
try { try {
const completedDate = new Date(task.date_completed); const completedDate = new Date(task.date_completed);
@@ -359,7 +361,7 @@ export default function ProjectTasksList() {
) : task.status === "in_progress" && task.date_started ? ( ) : task.status === "in_progress" && task.date_started ? (
<div> <div>
<div> <div>
Started:{" "} {t("tasks.dateStarted")}:{" "}
{(() => { {(() => {
try { try {
const startedDate = new Date(task.date_started); const startedDate = new Date(task.date_started);
@@ -385,7 +387,7 @@ export default function ProjectTasksList() {
</td> </td>
{showMaxWait && ( {showMaxWait && (
<td className="px-4 py-3 text-sm text-gray-500"> <td className="px-4 py-3 text-sm text-gray-500">
{task.max_wait_days} days {task.max_wait_days} {t("tasks.days")}
</td> </td>
)} )}
<td className="px-4 py-3"> <td className="px-4 py-3">
@@ -399,7 +401,7 @@ export default function ProjectTasksList() {
variant="secondary" variant="secondary"
size="sm" size="sm"
onClick={() => handleShowComments(task)} onClick={() => handleShowComments(task)}
title="View comments" title={t("tasks.comments")}
> >
💬 💬
</Button> </Button>
@@ -418,48 +420,48 @@ export default function ProjectTasksList() {
<thead className="bg-gray-50"> <thead className="bg-gray-50">
<tr> <tr>
<th className="px-4 py-3 text-left text-sm font-medium text-gray-700"> <th className="px-4 py-3 text-left text-sm font-medium text-gray-700">
Task Name {t("tasks.taskName")}
</th>{" "} </th>{" "}
<th className="px-4 py-3 text-left text-sm font-medium text-gray-700"> <th className="px-4 py-3 text-left text-sm font-medium text-gray-700">
Project {t("tasks.project")}
</th> </th>
<th className="px-4 py-3 text-left text-sm font-medium text-gray-700"> <th className="px-4 py-3 text-left text-sm font-medium text-gray-700">
City {t("projects.city")}
</th> </th>
<th className="px-4 py-3 text-left text-sm font-medium text-gray-700"> <th className="px-4 py-3 text-left text-sm font-medium text-gray-700">
Address {t("projects.address")}
</th> </th>
<th className="px-4 py-3 text-left text-sm font-medium text-gray-700"> <th className="px-4 py-3 text-left text-sm font-medium text-gray-700">
Assigned To {t("tasks.assignedTo")}
</th> </th>
{showTimeLeft && ( {showTimeLeft && (
<th className="px-4 py-3 text-left text-sm font-medium text-gray-700"> <th className="px-4 py-3 text-left text-sm font-medium text-gray-700">
Time Left {t("tasks.daysLeft")}
</th> </th>
)} )}
<th className="px-4 py-3 text-left text-sm font-medium text-gray-700"> <th className="px-4 py-3 text-left text-sm font-medium text-gray-700">
Date Info {t("tasks.dateCreated")}
</th> </th>
{showMaxWait && ( {showMaxWait && (
<th className="px-4 py-3 text-left text-sm font-medium text-gray-700"> <th className="px-4 py-3 text-left text-sm font-medium text-gray-700">
Max Wait {t("tasks.maxWait")}
</th> </th>
)}{" "} )}{" "}
<th className="px-4 py-3 text-left text-sm font-medium text-gray-700"> <th className="px-4 py-3 text-left text-sm font-medium text-gray-700">
Actions {t("tasks.actions")}
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{Object.entries(groupedTasks).map(([groupName, groupTasks]) => ( {Object.entries(groupedTasks).map(([groupName, groupTasks]) => (
<Fragment key={`group-fragment-${groupName}`}> <Fragment key={`group-fragment-${groupName}`}>
{showGrouped && groupName !== "All Tasks" && ( {showGrouped && groupName !== t("tasks.allTasks") && (
<tr key={`group-${groupName}`}> <tr key={`group-${groupName}`}>
<td <td
colSpan={colSpan} colSpan={colSpan}
className="px-4 py-2 bg-gray-100 font-medium text-gray-800 text-sm" className="px-4 py-2 bg-gray-100 font-medium text-gray-800 text-sm"
> >
{groupName} ({groupTasks.length} tasks) {groupName} ({groupTasks.length} {t("tasks.tasks")})
</td> </td>
</tr> </tr>
)} )}
@@ -477,7 +479,7 @@ export default function ProjectTasksList() {
</table> </table>
{filteredTasks.length === 0 && ( {filteredTasks.length === 0 && (
<div className="text-center py-8 text-gray-500"> <div className="text-center py-8 text-gray-500">
<p>No tasks found</p> <p>{t("tasks.noTasks")}</p>
</div> </div>
)} )}
</div> </div>
@@ -503,7 +505,7 @@ export default function ProjectTasksList() {
<div className="text-2xl font-bold text-blue-600"> <div className="text-2xl font-bold text-blue-600">
{taskGroups.pending.length} {taskGroups.pending.length}
</div> </div>
<div className="text-sm text-gray-600">Pending</div> <div className="text-sm text-gray-600">{t("taskStatus.pending")}</div>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
@@ -511,7 +513,7 @@ export default function ProjectTasksList() {
<div className="text-2xl font-bold text-purple-600"> <div className="text-2xl font-bold text-purple-600">
{taskGroups.in_progress.length} {taskGroups.in_progress.length}
</div> </div>
<div className="text-sm text-gray-600">In Progress</div> <div className="text-sm text-gray-600">{t("taskStatus.in_progress")}</div>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
@@ -519,7 +521,7 @@ export default function ProjectTasksList() {
<div className="text-2xl font-bold text-green-600"> <div className="text-2xl font-bold text-green-600">
{taskGroups.completed.length} {taskGroups.completed.length}
</div> </div>
<div className="text-sm text-gray-600">Completed</div> <div className="text-sm text-gray-600">{t("taskStatus.completed")}</div>
</CardContent> </CardContent>
</Card> </Card>
</div>{" "} </div>{" "}
@@ -527,26 +529,26 @@ export default function ProjectTasksList() {
<SearchBar <SearchBar
searchTerm={searchTerm} searchTerm={searchTerm}
onSearchChange={(e) => setSearchTerm(e.target.value)} onSearchChange={(e) => setSearchTerm(e.target.value)}
placeholder="Search tasks, projects, city, or address..." placeholder={t("tasks.searchPlaceholder")}
resultsCount={ resultsCount={
filterTasks(taskGroups.pending).length + filterTasks(taskGroups.pending).length +
filterTasks(taskGroups.in_progress).length + filterTasks(taskGroups.in_progress).length +
filterTasks(taskGroups.completed).length filterTasks(taskGroups.completed).length
} }
resultsText="tasks" resultsText={t("tasks.tasks")}
filters={ filters={
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<label className="text-sm font-medium text-gray-700"> <label className="text-sm font-medium text-gray-700">
Group by: {t("tasks.sortBy")}:
</label> </label>
<Select <Select
value={groupBy} value={groupBy}
onChange={(e) => setGroupBy(e.target.value)} onChange={(e) => setGroupBy(e.target.value)}
className="min-w-[120px]" className="min-w-[120px]"
> >
<option value="none">None</option> <option value="none">{t("common.none")}</option>
<option value="task_name">Task Name</option> <option value="task_name">{t("tasks.taskName")}</option>
</Select> </Select>
</div> </div>
</div> </div>
@@ -558,13 +560,13 @@ export default function ProjectTasksList() {
<div> <div>
<div className="mb-4"> <div className="mb-4">
<h2 className="text-xl font-semibold text-gray-900 flex items-center gap-2"> <h2 className="text-xl font-semibold text-gray-900 flex items-center gap-2">
Pending Tasks {t("taskStatus.pending")} {t("tasks.tasks")}
<Badge variant="primary" size="md"> <Badge variant="primary" size="md">
{taskGroups.pending.length} {taskGroups.pending.length}
</Badge> </Badge>
</h2> </h2>
<p className="text-sm text-gray-600 mt-1"> <p className="text-sm text-gray-600 mt-1">
Tasks waiting to be started {t("tasks.noTasksMessage")}
</p> </p>
</div> </div>
<TaskTable <TaskTable
@@ -579,13 +581,13 @@ export default function ProjectTasksList() {
<div> <div>
<div className="mb-4"> <div className="mb-4">
<h2 className="text-xl font-semibold text-gray-900 flex items-center gap-2"> <h2 className="text-xl font-semibold text-gray-900 flex items-center gap-2">
In Progress Tasks {t("taskStatus.in_progress")} {t("tasks.tasks")}
<Badge variant="secondary" size="md"> <Badge variant="secondary" size="md">
{taskGroups.in_progress.length} {taskGroups.in_progress.length}
</Badge> </Badge>
</h2> </h2>
<p className="text-sm text-gray-600 mt-1"> <p className="text-sm text-gray-600 mt-1">
Tasks currently being worked on - showing time left for completion Zadania aktualnie w trakcie realizacji - pokazujący pozostały czas do ukończenia
</p> </p>
</div> </div>
<TaskTable <TaskTable
@@ -600,13 +602,13 @@ export default function ProjectTasksList() {
<div> <div>
<div className="mb-4"> <div className="mb-4">
<h2 className="text-xl font-semibold text-gray-900 flex items-center gap-2"> <h2 className="text-xl font-semibold text-gray-900 flex items-center gap-2">
Completed Tasks {t("taskStatus.completed")} {t("tasks.tasks")}
<Badge variant="success" size="md"> <Badge variant="success" size="md">
{taskGroups.completed.length} {taskGroups.completed.length}
</Badge> </Badge>
</h2> </h2>
<p className="text-sm text-gray-600 mt-1"> <p className="text-sm text-gray-600 mt-1">
Recently completed and cancelled tasks Ostatnio ukończone i anulowane zadania
</p> </p>
</div> </div>
<TaskTable <TaskTable
@@ -616,9 +618,7 @@ export default function ProjectTasksList() {
showMaxWait={false} showMaxWait={false}
/> />
</div> </div>
</div> </div> {/* Comments Modal */}
{/* Comments Modal */}
<TaskCommentsModal <TaskCommentsModal
task={selectedTask} task={selectedTask}
isOpen={showCommentsModal} isOpen={showCommentsModal}

View File

@@ -5,8 +5,10 @@ import Button from "./ui/Button";
import Badge from "./ui/Badge"; import Badge from "./ui/Badge";
import { formatDate } from "@/lib/utils"; import { formatDate } from "@/lib/utils";
import { formatDistanceToNow, parseISO } from "date-fns"; import { formatDistanceToNow, parseISO } from "date-fns";
import { useTranslation } from "@/lib/i18n";
export default function TaskCommentsModal({ task, isOpen, onClose }) { export default function TaskCommentsModal({ task, isOpen, onClose }) {
const { t } = useTranslation();
const [notes, setNotes] = useState([]); const [notes, setNotes] = useState([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [newNote, setNewNote] = useState(""); const [newNote, setNewNote] = useState("");
@@ -148,14 +150,14 @@ export default function TaskCommentsModal({ task, isOpen, onClose }) {
{task?.task_name} {task?.task_name}
</h3> </h3>
<Badge variant={getPriorityVariant(task?.priority)} size="sm"> <Badge variant={getPriorityVariant(task?.priority)} size="sm">
{task?.priority} {t(`tasks.${task?.priority}`)}
</Badge> </Badge>
<Badge variant={getStatusVariant(task?.status)} size="sm"> <Badge variant={getStatusVariant(task?.status)} size="sm">
{task?.status?.replace('_', ' ')} {t(`taskStatus.${task?.status}`)}
</Badge> </Badge>
</div> </div>
<p className="text-sm text-gray-600 mb-3"> <p className="text-sm text-gray-600 mb-3">
Project: <span className="font-medium">{task?.project_name}</span> {t("tasks.project")}: <span className="font-medium">{task?.project_name}</span>
</p> </p>
</div> </div>
<button <button
@@ -172,7 +174,7 @@ export default function TaskCommentsModal({ task, isOpen, onClose }) {
{/* Location Information */} {/* Location Information */}
{(task?.city || task?.address) && ( {(task?.city || task?.address) && (
<div className="space-y-1"> <div className="space-y-1">
<h4 className="text-xs font-medium text-gray-500 uppercase tracking-wide">Location</h4> <h4 className="text-xs font-medium text-gray-500 uppercase tracking-wide">{t("projects.locationDetails")}</h4>
{task?.city && ( {task?.city && (
<p className="text-sm text-gray-900">{task.city}</p> <p className="text-sm text-gray-900">{task.city}</p>
)} )}
@@ -184,26 +186,26 @@ export default function TaskCommentsModal({ task, isOpen, onClose }) {
{/* Assignment Information */} {/* Assignment Information */}
<div className="space-y-1"> <div className="space-y-1">
<h4 className="text-xs font-medium text-gray-500 uppercase tracking-wide">Assignment</h4> <h4 className="text-xs font-medium text-gray-500 uppercase tracking-wide">{t("tasks.assignedTo")}</h4>
{task?.assigned_to_name ? ( {task?.assigned_to_name ? (
<div> <div>
<p className="text-sm text-gray-900">{task.assigned_to_name}</p> <p className="text-sm text-gray-900">{task.assigned_to_name}</p>
<p className="text-xs text-gray-600">{task.assigned_to_email}</p> <p className="text-xs text-gray-600">{task.assigned_to_email}</p>
</div> </div>
) : ( ) : (
<p className="text-sm text-gray-500 italic">Unassigned</p> <p className="text-sm text-gray-500 italic">{t("projects.unassigned")}</p>
)} )}
</div> </div>
{/* Task Timing */} {/* Task Timing */}
<div className="space-y-1"> <div className="space-y-1">
<h4 className="text-xs font-medium text-gray-500 uppercase tracking-wide">Timing</h4> <h4 className="text-xs font-medium text-gray-500 uppercase tracking-wide">{t("tasks.dateCreated")}</h4>
{task?.max_wait_days && ( {task?.max_wait_days && (
<p className="text-xs text-gray-600">Max wait: {task.max_wait_days} days</p> <p className="text-xs text-gray-600">{t("tasks.maxWait")}: {task.max_wait_days} {t("tasks.days")}</p>
)} )}
{(() => { {(() => {
if (task?.status === "completed" && task?.date_completed) { if (task?.status === "completed" && task?.date_completed) {
const dateInfo = formatTaskDate(task.date_completed, "Completed"); const dateInfo = formatTaskDate(task.date_completed, t("taskStatus.completed"));
return ( return (
<div> <div>
<p className="text-sm text-green-700 font-medium">{dateInfo.relative}</p> <p className="text-sm text-green-700 font-medium">{dateInfo.relative}</p>
@@ -211,18 +213,18 @@ export default function TaskCommentsModal({ task, isOpen, onClose }) {
</div> </div>
); );
} else if (task?.status === "in_progress" && task?.date_started) { } else if (task?.status === "in_progress" && task?.date_started) {
const dateInfo = formatTaskDate(task.date_started, "Started"); const dateInfo = formatTaskDate(task.date_started, t("tasks.dateStarted"));
return ( return (
<div> <div>
<p className="text-sm text-blue-700 font-medium">Started {dateInfo.relative}</p> <p className="text-sm text-blue-700 font-medium">{t("tasks.dateStarted")} {dateInfo.relative}</p>
<p className="text-xs text-gray-600">{dateInfo.absolute}</p> <p className="text-xs text-gray-600">{dateInfo.absolute}</p>
</div> </div>
); );
} else if (task?.date_added) { } else if (task?.date_added) {
const dateInfo = formatTaskDate(task.date_added, "Created"); const dateInfo = formatTaskDate(task.date_added, t("tasks.dateCreated"));
return ( return (
<div> <div>
<p className="text-sm text-gray-700 font-medium">Created {dateInfo.relative}</p> <p className="text-sm text-gray-700 font-medium">{t("tasks.dateCreated")} {dateInfo.relative}</p>
<p className="text-xs text-gray-600">{dateInfo.absolute}</p> <p className="text-xs text-gray-600">{dateInfo.absolute}</p>
</div> </div>
); );
@@ -234,7 +236,7 @@ export default function TaskCommentsModal({ task, isOpen, onClose }) {
{/* Task Description */} {/* Task Description */}
{task?.description && ( {task?.description && (
<div className="space-y-1 md:col-span-2 lg:col-span-3"> <div className="space-y-1 md:col-span-2 lg:col-span-3">
<h4 className="text-xs font-medium text-gray-500 uppercase tracking-wide">Description</h4> <h4 className="text-xs font-medium text-gray-500 uppercase tracking-wide">{t("tasks.description")}</h4>
<p className="text-sm text-gray-900 leading-relaxed">{task.description}</p> <p className="text-sm text-gray-900 leading-relaxed">{task.description}</p>
</div> </div>
)} )}
@@ -255,7 +257,7 @@ export default function TaskCommentsModal({ task, isOpen, onClose }) {
<div className="space-y-4"> <div className="space-y-4">
<div className="flex items-center gap-2 mb-4"> <div className="flex items-center gap-2 mb-4">
<h5 className="text-lg font-medium text-gray-900"> <h5 className="text-lg font-medium text-gray-900">
Comments & Activity {t("tasks.comments")}
</h5> </h5>
<Badge variant="secondary" size="sm"> <Badge variant="secondary" size="sm">
{notes.length} {notes.length}
@@ -267,8 +269,8 @@ export default function TaskCommentsModal({ task, isOpen, onClose }) {
<div className="w-16 h-16 mx-auto mb-4 bg-gray-100 rounded-full flex items-center justify-center"> <div className="w-16 h-16 mx-auto mb-4 bg-gray-100 rounded-full flex items-center justify-center">
<span className="text-2xl">💬</span> <span className="text-2xl">💬</span>
</div> </div>
<p className="text-lg font-medium mb-1">No comments yet</p> <p className="text-lg font-medium mb-1">{t("tasks.noComments")}</p>
<p className="text-sm">Be the first to add a comment!</p> <p className="text-sm">Bądź pierwszy, który doda komentarz!</p>
</div> </div>
) : ( ) : (
<div className="space-y-4"> <div className="space-y-4">
@@ -286,12 +288,12 @@ export default function TaskCommentsModal({ task, isOpen, onClose }) {
{note.is_system ? ( {note.is_system ? (
<span className="px-2 py-1 text-xs bg-blue-100 text-blue-700 rounded-full font-medium flex items-center gap-1"> <span className="px-2 py-1 text-xs bg-blue-100 text-blue-700 rounded-full font-medium flex items-center gap-1">
<span>🤖</span> <span>🤖</span>
System {t("admin.system")}
</span> </span>
) : ( ) : (
<span className="px-2 py-1 text-xs bg-gray-100 text-gray-700 rounded-full font-medium flex items-center gap-1"> <span className="px-2 py-1 text-xs bg-gray-100 text-gray-700 rounded-full font-medium flex items-center gap-1">
<span>👤</span> <span>👤</span>
{note.created_by_name || 'User'} {note.created_by_name || t("userRoles.user")}
</span> </span>
)} )}
<span className="text-xs text-gray-500 font-medium"> <span className="text-xs text-gray-500 font-medium">
@@ -308,7 +310,7 @@ export default function TaskCommentsModal({ task, isOpen, onClose }) {
<button <button
onClick={() => handleDeleteNote(note.note_id)} onClick={() => handleDeleteNote(note.note_id)}
className="ml-3 p-1 text-red-400 hover:text-red-600 hover:bg-red-50 rounded transition-colors" className="ml-3 p-1 text-red-400 hover:text-red-600 hover:bg-red-50 rounded transition-colors"
title="Delete comment" title={t("common.delete")}
> >
<span className="text-sm">🗑</span> <span className="text-sm">🗑</span>
</button> </button>
@@ -327,13 +329,13 @@ export default function TaskCommentsModal({ task, isOpen, onClose }) {
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span className="text-lg">💬</span> <span className="text-lg">💬</span>
<label className="text-sm font-medium text-gray-700"> <label className="text-sm font-medium text-gray-700">
Add a comment {t("tasks.addComment")}
</label> </label>
</div> </div>
<textarea <textarea
value={newNote} value={newNote}
onChange={(e) => setNewNote(e.target.value)} onChange={(e) => setNewNote(e.target.value)}
placeholder="Type your comment here... (Ctrl+Enter to submit)" placeholder={t("common.addNotePlaceholder")}
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none shadow-sm" className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none shadow-sm"
rows={3} rows={3}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
@@ -341,7 +343,7 @@ export default function TaskCommentsModal({ task, isOpen, onClose }) {
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<p className="text-xs text-gray-500 flex items-center gap-1"> <p className="text-xs text-gray-500 flex items-center gap-1">
<span></span> <span></span>
Press Ctrl+Enter to submit or Escape to close Naciśnij Ctrl+Enter aby wysłać lub Escape aby zamknąć
</p> </p>
<div className="flex gap-3"> <div className="flex gap-3">
<Button <Button
@@ -349,7 +351,7 @@ export default function TaskCommentsModal({ task, isOpen, onClose }) {
size="sm" size="sm"
onClick={onClose} onClick={onClose}
> >
Close {t("common.close")}
</Button> </Button>
<Button <Button
variant="primary" variant="primary"
@@ -357,7 +359,7 @@ export default function TaskCommentsModal({ task, isOpen, onClose }) {
onClick={handleAddNote} onClick={handleAddNote}
disabled={loadingAdd || !newNote.trim()} disabled={loadingAdd || !newNote.trim()}
> >
{loadingAdd ? "Adding..." : "💾 Add Comment"} {loadingAdd ? t("common.saving") : `💾 ${t("tasks.addComment")}`}
</Button> </Button>
</div> </div>
</div> </div>

View File

@@ -211,7 +211,7 @@ const translations = {
status: "Status", status: "Status",
project: "Projekt", project: "Projekt",
template: "Szablon", template: "Szablon",
searchPlaceholder: "Szukaj zadań...", searchPlaceholder: "Szukaj zadań, projektów, miast lub adresów...",
noTasks: "Brak zadań", noTasks: "Brak zadań",
noTasksMessage: "Brak zadań przypisanych do tego projektu.", noTasksMessage: "Brak zadań przypisanych do tego projektu.",
addTaskMessage: "Dodaj zadanie powyżej, aby rozpocząć.", addTaskMessage: "Dodaj zadanie powyżej, aby rozpocząć.",
@@ -596,7 +596,7 @@ const translations = {
status: "Status", status: "Status",
project: "Project", project: "Project",
template: "Template", template: "Template",
searchPlaceholder: "Search tasks...", searchPlaceholder: "Search tasks, projects, city, or address...",
noTasks: "No tasks", noTasks: "No tasks",
noTasksMessage: "No tasks assigned to this project yet.", noTasksMessage: "No tasks assigned to this project yet.",
addTaskMessage: "Add a task above to get started.", addTaskMessage: "Add a task above to get started.",