Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion devboard/client/src/components/Board/TaskCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useState } from "react";
import { Draggable } from "@hello-pangea/dnd";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { vscDarkPlus } from "react-syntax-highlighter/dist/esm/styles/prism";
import { useBoard } from "../../context/BoardContext";

const PRIORITY_COLORS = {
high: "bg-red-500/20 text-red-400",
Expand All @@ -12,6 +13,7 @@ const PRIORITY_COLORS = {
const TaskCard = ({ task, index, onSelect }) => {
const [expanded, setExpanded] = useState(false);
const [selectedSnippet, setSelectedSnippet] = useState(0);
const { activeTag, setActiveTag } = useBoard();

// Check if the task due date has passed and the task is not completed ---------
const today = new Date();
Expand Down Expand Up @@ -125,7 +127,15 @@ const TaskCard = ({ task, index, onSelect }) => {
{task.tags?.map((tag) => (
<span
key={tag}
className="text-[10px] px-1.5 py-0.5 rounded bg-[var(--border-primary)] text-[#888]"
onClick={(e) => {
e.stopPropagation();
setActiveTag(activeTag === tag ? null : tag);
}}
className={`text-[10px] px-1.5 py-0.5 rounded cursor-pointer transition
${activeTag === tag
? "bg-purple-600/30 text-purple-300 ring-1 ring-purple-500"
: "bg-[var(--border-primary)] text-[#888] hover:bg-[var(--border-primary)]/80"
}`}
>
{tag}
</span>
Expand Down
18 changes: 15 additions & 3 deletions devboard/client/src/context/BoardContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const BoardProvider = ({ children }) => {
const [allTasks, setAllTasks] = useState([]);
const [loading, setLoading] = useState(true);
const [searchQuery, setSearchQuery] = useState("");
const [activeTag, setActiveTag] = useState(null);
const [user, setUser] = useState(() => {
const saved = localStorage.getItem("devboard_user");
return saved ? JSON.parse(saved) : null;
Expand Down Expand Up @@ -70,16 +71,25 @@ export const BoardProvider = ({ children }) => {
};

const tasks = useMemo(() => {
let filtered = allTasks;

// Filter by active tag if one is selected
if (activeTag) {
filtered = filtered.filter((task) =>
task.tags?.includes(activeTag)
);
}

const query = searchQuery.trim().toLowerCase();

if (!query) return allTasks;
if (!query) return filtered;

const priorityLabel = (priority) => {
if (!priority) return "";
return `${priority} priority`;
};

return allTasks.filter((task) => {
return filtered.filter((task) => {
const title = task.title?.toLowerCase() || "";
const description = task.description?.toLowerCase() || "";
const tags = task.tags?.join(" ").toLowerCase() || "";
Expand All @@ -94,7 +104,7 @@ export const BoardProvider = ({ children }) => {
priorityText.includes(query)
);
});
}, [allTasks, searchQuery]);
}, [allTasks, searchQuery, activeTag]);

return (
<BoardContext.Provider
Expand All @@ -104,6 +114,8 @@ export const BoardProvider = ({ children }) => {
user,
searchQuery,
setSearchQuery,
activeTag,
setActiveTag,
addTask,
updateTask,
deleteTask,
Expand Down
13 changes: 12 additions & 1 deletion devboard/client/src/pages/Dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const LoadingSpinner = () => (
);

const Dashboard = () => {
const { user, logout, updateTask, loading, searchQuery, setSearchQuery, tasks, addTask } = useBoard();
const { user, logout, updateTask, loading, searchQuery, setSearchQuery, tasks, addTask, activeTag, setActiveTag } = useBoard();
useEffect(() => {
document.title = "Dashboard — DevBoard";
}, []);
Expand All @@ -42,6 +42,17 @@ const Dashboard = () => {
<span className="text-xs bg-purple-600/20 text-purple-400 px-2 py-0.5 rounded-full ml-1">
beta
</span>
<span className="text-xs text-[#666] ml-2">
{tasks.length} {tasks.length === 1 ? "task" : "tasks"}
</span>
{activeTag && (
<button
onClick={() => setActiveTag(null)}
className="text-xs bg-purple-600/30 text-purple-300 px-2 py-0.5 rounded-full flex items-center gap-1 hover:bg-purple-600/40 transition"
>
#{activeTag} <span aria-hidden>✕</span>
</button>
)}
</div>
<div className="flex-1 w-full max-w-xl md:px-6">
<label className="relative block">
Expand Down