Skip to content
Open
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
43 changes: 43 additions & 0 deletions app/dashboard/projects/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
EscrowStatusTracker,
type EscrowStage,
} from "@/components/dashboard/escrow-status-tracker";
import { MilestoneProgressTracker } from "@/components/dashboard/milestone-progress-tracker";

interface Milestone {
id: string;
Expand Down Expand Up @@ -102,6 +103,48 @@
const [showApprovalDialog, setShowApprovalDialog] = useState(false);
const [now] = useState(() => Date.now());

const handleMilestoneStatusUpdate = async (milestoneId: string, newStatus: string) => {
try {
const res = await fetch(`/api/milestones/${milestoneId}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
...getAuthHeaders(),
},
body: JSON.stringify({ status: newStatus }),
});
if (!res.ok) {
const errorData = await res.json();
throw new Error(errorData.error || "Failed to update milestone status");
}

// Update local state dynamically
setMilestones((prev) =>
prev.map((m) =>
m.id === milestoneId
? {
...m,
status: newStatus,
}
: m
)
);

// Trigger standard API re-fetch for absolute sync
const resProj = await fetch(`/api/projects/${id}`, {
headers: getAuthHeaders(),
});
if (resProj.ok) {
const data = await resProj.json();
setProject(data.project);
setMilestones(data.milestones ?? []);
}
} catch (err: any) {
console.error(err);
alert(err.message || "Failed to update milestone status. Make sure you are authorized.");
}
};

useEffect(() => {
if (!id) return;
(async () => {
Expand Down Expand Up @@ -317,7 +360,7 @@

<div className="flex items-center gap-4">
{project.client?.avatar_url ? (
<img

Check warning on line 363 in app/dashboard/projects/[id]/page.tsx

View workflow job for this annotation

GitHub Actions / build

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
src={project.client.avatar_url}
alt={project.client.display_name || project.client.username}
className="w-12 h-12 rounded-full object-cover border border-border/50"
Expand Down Expand Up @@ -366,7 +409,7 @@
<>
<div className="flex items-center gap-4">
{project.freelancer.avatar_url ? (
<img

Check warning on line 412 in app/dashboard/projects/[id]/page.tsx

View workflow job for this annotation

GitHub Actions / build

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
src={project.freelancer.avatar_url}
alt={project.freelancer.display_name || project.freelancer.username}
className="w-12 h-12 rounded-full object-cover border border-border/50"
Expand Down
180 changes: 180 additions & 0 deletions app/dashboard/projects/milestone-demo/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
"use client";

import Link from "next/link";
import { ArrowLeft, Sparkles, ShieldCheck, HelpCircle } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { MilestoneProgressTracker, type Milestone } from "@/components/dashboard/milestone-progress-tracker";

// Comprehensive mock data covering all states
const initialMockMilestones: Milestone[] = [
{
id: "demo-m1",
title: "1. Smart Contract Architecture & Escrow Hooks",
description: "Design and implement the core Soroban smart contracts for trustless multi-party escrow, dynamic fees computation, and cryptographic payouts release hooks. Completed after initial security validation.",
amount: 3500.00,
currency: "USDC",
due_date: "2026-05-10",
status: "paid",
deliverables: [
"Escrow Soroban Contract compiled on Rust",
"Automated unit testing suite (98% coverage)",
"Testnet deployment and anchoring transactions record"
],
submitted_at: "2026-05-08T14:32:00Z",
approved_at: "2026-05-09T10:15:00Z",
paid_at: "2026-05-10T09:00:00Z"
},
{
id: "demo-m2",
title: "2. UI/UX Dashboard Integration & Themes",
description: "Build a highly responsive dark-themed dashboard frontend with glassmorphism components, detailed state management (using custom hooks), and dynamic performance metrics charting. Fully validated by designers.",
amount: 2500.00,
currency: "USDC",
due_date: "2026-05-20",
status: "approved",
deliverables: [
"Responsive React elements matching Figma wireframes",
"Client/Freelancer contextual dashboards layout",
"Sleek light/dark theme toggle hook integration"
],
submitted_at: "2026-05-19T18:00:00Z",
approved_at: "2026-05-20T11:45:00Z"
},
{
id: "demo-m3",
title: "3. Stellar SDK freighter Wallet Connection",
description: "Implement secure browser-extension wallet auth using @stellar/freighter-api, signature authentication of user payloads on dynamic requests, and instant state retrieval for on-chain balances.",
amount: 1800.00,
currency: "USDC",
due_date: "2026-05-28",
status: "submitted",
deliverables: [
"Freighter API connect button & wallet session persistence",
"Cryptographic signing helper methods for client payloads",
"Balance synchronization with Stellar Testnet nodes"
],
submitted_at: "2026-05-27T22:30:00Z"
},
{
id: "demo-m4",
title: "4. Stress Testing, Security Auditing & QA",
description: "Conduct thorough load testing of API endpoints, test contract resilience against common attack vectors (reentrancy, overflow, auth bypass), and compile a detailed cryptographic security clearance report.",
amount: 1200.00,
currency: "USDC",
due_date: "2026-06-15",
status: "in_progress",
deliverables: [
"Resilience testing audit against reentrancy vectors",
"10k concurrent simulated requests benchmark report",
"Cryptographic security audit certification document"
]
},
{
id: "demo-m5",
title: "5. Production Deployment & Live Verification",
description: "Anchor finalized smart contracts on Stellar Mainnet, release verified source code to public blockchain explorers, and configure production monitoring dashboard to trace live transactions stream.",
amount: 1000.00,
currency: "USDC",
due_date: "2026-06-30",
status: "pending",
deliverables: [
"Mainnet smart contracts anchoring setup",
"Verified source code publication on explorer",
"Live transactional alerts monitoring system"
]
}
];

export default function MilestoneDemoPage() {
return (
<div className="p-8 space-y-8 max-w-7xl mx-auto">
{/* Back button and title */}
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
<div className="flex items-start gap-4">
<Link href="/dashboard/projects">
<Button variant="ghost" size="icon" className="hover:bg-muted/30">
<ArrowLeft className="h-5 w-5" />
</Button>
</Link>
<div>
<div className="flex items-center gap-2">
<h1 className="text-3xl font-extrabold text-foreground tracking-tight">
Milestone Tracker Sandbox
</h1>
<Sparkles className="h-5 w-5 text-primary animate-pulse" />
</div>
<p className="text-muted-foreground mt-1">
Interactive playground showcasing TaskChain's premium, responsive Web3 milestone stepper & Kanban board.

Check failure on line 108 in app/dashboard/projects/milestone-demo/page.tsx

View workflow job for this annotation

GitHub Actions / build

`'` can be escaped with `&apos;`, `&lsquo;`, `&#39;`, `&rsquo;`
</p>
</div>
</div>
</div>

{/* Guide Banner */}
<Card className="p-4 bg-primary/5 border border-primary/20 backdrop-blur-sm rounded-xl flex items-start gap-3">
<ShieldCheck className="h-6 w-6 text-primary shrink-0 mt-0.5" />
<div className="space-y-1">
<h4 className="font-bold text-sm text-foreground">Interactive Demo Mode Active</h4>
<p className="text-xs text-muted-foreground leading-relaxed">
Use the buttons below to switch viewports (Cards, Stepper, or Kanban). Toggle <strong>Enable Sandbox</strong> to simulate transitioning a milestone through its 5-state Web3 escrow lifecycle:
<span className="font-semibold text-foreground px-1">Pending</span> ➔
<span className="font-semibold text-indigo-400 px-1">In Progress</span> ➔
<span className="font-semibold text-amber-400 px-1">Submitted</span> ➔
<span className="font-semibold text-emerald-400 px-1">Approved</span> ➔
<span className="font-semibold text-violet-400 px-1">Paid</span>.
</p>
</div>
</Card>

{/* Main Component Rendered in interactive sandbox */}
<div className="space-y-4">
<div className="flex items-center gap-1.5 px-1">
<HelpCircle className="h-4.5 w-4.5 text-muted-foreground" />
<h3 className="text-sm font-bold uppercase tracking-widest text-muted-foreground">
Milestone Progress Component View
</h3>
</div>

<MilestoneProgressTracker
milestones={initialMockMilestones}
userRole="client"
contractAddress="C_STELLAR_ESCROW_DUMMY_37A9F4"
/>
</div>

{/* Instructional Walkthrough footer */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 pt-4">
<Card className="p-5 bg-card/20 border-border/40 space-y-2">
<h4 className="font-bold text-sm text-foreground flex items-center gap-2">
<span className="h-2 w-2 rounded-full bg-indigo-500" />
1. Initiation (Freelancer)
</h4>
<p className="text-xs text-muted-foreground leading-relaxed">
The milestone starts as <strong>Pending</strong>. Once the freelancer is ready to execute work, they click <strong>Start Milestone</strong> which flags it as <strong>In Progress</strong>.
</p>
</Card>

<Card className="p-5 bg-card/20 border-border/40 space-y-2">
<h4 className="font-bold text-sm text-foreground flex items-center gap-2">
<span className="h-2 w-2 rounded-full bg-amber-500" />
2. Submission & Review
</h4>
<p className="text-xs text-muted-foreground leading-relaxed">
When deliverables are ready, the freelancer uploads files and clicks <strong>Submit Deliverables</strong>. The state becomes <strong>Submitted</strong>, alerting the client to audit the work.
</p>
</Card>

<Card className="p-5 bg-card/20 border-border/40 space-y-2">
<h4 className="font-bold text-sm text-foreground flex items-center gap-2">
<span className="h-2 w-2 rounded-full bg-violet-500" />
3. Approval & Blockchain Payout
</h4>
<p className="text-xs text-muted-foreground leading-relaxed">
The client reviews work and clicks <strong>Approve</strong>. Once satisfied, they select <strong>Release Escrow Payout</strong> which invokes Soroban smart contracts, marking it as <strong>Paid</strong>.
</p>
</Card>
</div>
</div>
);
}
16 changes: 12 additions & 4 deletions app/dashboard/projects/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useEffect, useMemo, useState } from "react";
import Link from "next/link";
import { Search, Filter, ChevronRight, Loader2 } from "lucide-react";
import { Search, Filter, ChevronRight, Loader2, Sparkles } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
Expand Down Expand Up @@ -104,9 +104,17 @@ export default function ProjectsPage() {
return (
<div className="p-8">
<div className="space-y-8">
<div>
<h1 className="text-3xl font-bold">All Projects</h1>
<p className="text-muted-foreground mt-2">View and manage all your projects</p>
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div>
<h1 className="text-3xl font-bold">All Projects</h1>
<p className="text-muted-foreground mt-2">View and manage all your projects</p>
</div>
<Link href="/dashboard/projects/milestone-demo">
<Button className="bg-primary/20 border border-primary/40 text-primary hover:bg-primary/30 text-xs font-semibold gap-1.5 h-9 shrink-0">
<Sparkles className="h-4 w-4 animate-pulse" />
Try Milestone Sandbox
</Button>
</Link>
</div>

<div className="flex flex-col sm:flex-row gap-4">
Expand Down
Loading
Loading