Skip to content
Closed
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
72 changes: 28 additions & 44 deletions dongle/app/discover/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,22 @@

import React, { useState, useMemo } from "react";
import LayoutWrapper from "@/components/layout/LayoutWrapper";
import { mockProjects } from "@/data/mockProjects";
import { mockProjects, Project } from "@/data/mockProjects";

Check warning on line 5 in dongle/app/discover/page.tsx

View workflow job for this annotation

GitHub Actions / Lint and Build

'Project' is defined but never used
import { ProjectCard } from "@/components/projects/ProjectCard";
import { Button } from "@/components/ui/Button";
import { Search, Filter } from "lucide-react";
import { Search, Loader2, Filter } from "lucide-react";

Check warning on line 8 in dongle/app/discover/page.tsx

View workflow job for this annotation

GitHub Actions / Lint and Build

'Loader2' is defined but never used
import { FormField } from "@/components/ui/FormField";

Check warning on line 9 in dongle/app/discover/page.tsx

View workflow job for this annotation

GitHub Actions / Lint and Build

'FormField' is defined but never used

const ITEMS_PER_PAGE = 9;

export default function DiscoverPage() {
const [searchQuery, setSearchQuery] = useState("");
const [selectedCategory, setSelectedCategory] = useState<string>("All");
const [sortBy, setSortBy] = useState<"rating" | "newest" | "popular">(
"rating",
);
const [sortBy, setSortBy] = useState<"rating" | "newest" | "popular">("rating");
const [visibleCount, setVisibleCount] = useState(ITEMS_PER_PAGE);
const [isLoadingMore, setIsLoadingMore] = useState(false);

const categories = [
"All",
...Array.from(new Set(mockProjects.map((p) => p.category))),
];
const categories = ["All", ...Array.from(new Set(mockProjects.map(p => p.category)))];

// Apply filters and sorting
const filteredAndSortedProjects = useMemo(() => {
Expand All @@ -30,26 +26,22 @@
// Apply Search
if (searchQuery) {
const q = searchQuery.toLowerCase();
result = result.filter(
(p) =>
p.name.toLowerCase().includes(q) ||
p.description.toLowerCase().includes(q),
result = result.filter(p =>
p.name.toLowerCase().includes(q) ||
p.description.toLowerCase().includes(q)
);
}

// Apply Category Filter
if (selectedCategory !== "All") {
result = result.filter((p) => p.category === selectedCategory);
result = result.filter(p => p.category === selectedCategory);
}

// Apply Sorting
result = [...result].sort((a, b) => {
if (sortBy === "rating") return b.rating - a.rating;
if (sortBy === "popular") return b.reviews - a.reviews;
if (sortBy === "newest")
return (
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
);
if (sortBy === "newest") return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();
return 0;
});

Expand All @@ -63,7 +55,7 @@
setIsLoadingMore(true);
// Simulate network delay for loading chunks
setTimeout(() => {
setVisibleCount((prev) => prev + ITEMS_PER_PAGE);
setVisibleCount(prev => prev + ITEMS_PER_PAGE);
setIsLoadingMore(false);
}, 600);
};
Expand All @@ -77,20 +69,18 @@
<LayoutWrapper>
<main className="min-h-screen pt-32 pb-24 bg-zinc-50 dark:bg-zinc-950">
<div className="container mx-auto px-4">

{/* Header & Controls */}
<div className="mb-12">
<h1 className="text-4xl font-bold tracking-tight mb-4">
Discover Projects
</h1>
<h1 className="text-4xl font-bold tracking-tight mb-4">Discover Projects</h1>
<p className="text-lg text-zinc-500 dark:text-zinc-400 mb-8 max-w-2xl">
Explore the ecosystem of decentralized applications,
infrastructure, and tools built on Stellar and Soroban.
Explore the ecosystem of decentralized applications, infrastructure, and tools built on Stellar and Soroban.
</p>

<div className="flex flex-col lg:flex-row gap-4 justify-between items-start lg:items-center bg-white dark:bg-zinc-900 p-4 rounded-3xl border border-zinc-200 dark:border-zinc-800 shadow-sm">
<div className="flex-1 w-full lg:w-auto relative">
<Search className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-zinc-400" />
<input
<input
type="text"
placeholder="Search projects by name or description..."
className="w-full pl-12 pr-4 py-3 bg-zinc-50 dark:bg-zinc-900/50 border border-zinc-200 dark:border-zinc-800 rounded-2xl focus:outline-none focus:ring-2 focus:ring-blue-500/20"
Expand All @@ -101,13 +91,13 @@

<div className="flex flex-wrap items-center gap-3 w-full lg:w-auto">
<div className="flex items-center gap-2 overflow-x-auto pb-2 lg:pb-0 hide-scrollbar">
{categories.map((cat) => (
{categories.map(cat => (
<button
key={cat}
onClick={() => setSelectedCategory(cat)}
className={`whitespace-nowrap px-4 py-2 rounded-xl text-sm font-medium transition-colors ${
selectedCategory === cat
? "bg-blue-500 text-white"
selectedCategory === cat
? "bg-blue-500 text-white"
: "bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-300 hover:bg-zinc-200 dark:hover:bg-zinc-700"
}`}
>
Expand All @@ -120,9 +110,7 @@

<select
value={sortBy}
onChange={(e) =>
setSortBy(e.target.value as "rating" | "newest" | "popular")
}
onChange={(e) => setSortBy(e.target.value as any)}

Check failure on line 113 in dongle/app/discover/page.tsx

View workflow job for this annotation

GitHub Actions / Lint and Build

Unexpected any. Specify a different type
className="px-4 py-2 bg-zinc-100 dark:bg-zinc-800 border border-transparent rounded-xl text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500/20"
>
<option value="rating">Highest Rated</option>
Expand All @@ -144,12 +132,9 @@
<div className="text-center py-24 bg-white dark:bg-zinc-900 rounded-3xl border border-zinc-200 dark:border-zinc-800">
<Filter className="w-12 h-12 text-zinc-300 mx-auto mb-4" />
<h3 className="text-xl font-bold mb-2">No projects found</h3>
<p className="text-zinc-500">
Try adjusting your search or filters to find what you&apos;re
looking for.
</p>
<Button
variant="outline"
<p className="text-zinc-500">Try adjusting your search or filters to find what you're looking for.</p>

Check failure on line 135 in dongle/app/discover/page.tsx

View workflow job for this annotation

GitHub Actions / Lint and Build

`'` can be escaped with `&apos;`, `&lsquo;`, `&#39;`, `&rsquo;`
<Button
variant="outline"
className="mt-6"
onClick={() => {
setSearchQuery("");
Expand All @@ -164,21 +149,20 @@
{/* Load More Pagination */}
{hasMore && visibleProjects.length > 0 && (
<div className="flex justify-center">
<Button
variant="secondary"
size="lg"
<Button
variant="secondary"
size="lg"
onClick={handleLoadMore}
isLoading={isLoadingMore}
className="w-full sm:w-auto min-w-50"
className="w-full sm:w-auto min-w-[200px]"
>
{!isLoadingMore && "Load More Projects"}
</Button>
</div>
)}

<div className="text-center mt-6 text-sm text-zinc-500">
Showing {visibleProjects.length} of{" "}
{filteredAndSortedProjects.length} projects
Showing {visibleProjects.length} of {filteredAndSortedProjects.length} projects
</div>
</div>
</main>
Expand Down
8 changes: 5 additions & 3 deletions dongle/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { WalletProvider } from "@/context/wallet.context";
import { Toaster } from "sonner";

Check warning on line 5 in dongle/app/layout.tsx

View workflow job for this annotation

GitHub Actions / Lint and Build

'Toaster' is defined but never used
import LayoutWrapper from "@/components/layout/LayoutWrapper";

const geistSans = Geist({
Expand All @@ -16,8 +17,7 @@

export const metadata: Metadata = {
title: "Dongle - Your Onchain App Store",
description:
"The decentralized app store for Stellar. Discovery, reviews, and verification powered by on-chain transparency.",
description: "The decentralized app store for Stellar. Discovery, reviews, and verification powered by on-chain transparency.",
};

export default function RootLayout({
Expand All @@ -31,7 +31,9 @@
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<WalletProvider>
<LayoutWrapper>{children}</LayoutWrapper>
<LayoutWrapper>
{children}
</LayoutWrapper>
</WalletProvider>
</body>
</html>
Expand Down
96 changes: 45 additions & 51 deletions dongle/app/projects/new/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,70 +2,64 @@

import React from "react";
import ProjectForm from "@/components/projects/ProjectForm";
import LayoutWrapper from "@/components/layout/LayoutWrapper";
import { useWallet } from "@/context/wallet.context";
import { Wallet2, ShieldCheck, Zap, Rocket } from "lucide-react";
import { Button } from "@/components/ui/Button";
import { Card } from "@/components/ui/Card";

export default function NewProjectPage() {
const { isConnected } = useWallet();
const { isConnected, connectWallet, isConnecting } = useWallet();

Check warning on line 12 in dongle/app/projects/new/page.tsx

View workflow job for this annotation

GitHub Actions / Lint and Build

'isConnecting' is assigned a value but never used

Check warning on line 12 in dongle/app/projects/new/page.tsx

View workflow job for this annotation

GitHub Actions / Lint and Build

'connectWallet' is assigned a value but never used
const [showForm, setShowForm] = React.useState(false);

// If already connected, show form immediately
// If not, allow mock bypass via showForm state
const isFormVisible = isConnected || showForm;

return (
<main className="min-h-screen pt-32 pb-24 bg-[radial-gradient(ellipse_at_top,var(--tw-gradient-stops))] from-blue-500/5 via-transparent to-transparent">
<div className="container mx-auto px-4">
{!isFormVisible ? (
<div className="max-w-xl mx-auto text-center py-20 animate-fade-in">
<div className="inline-flex p-4 bg-zinc-100 dark:bg-zinc-900 rounded-3xl mb-8 border border-zinc-200 dark:border-zinc-800">
<Wallet2 className="w-8 h-8 text-blue-500" />
<LayoutWrapper>
<main className="min-h-screen pt-32 pb-24 bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-blue-500/5 via-transparent to-transparent">
<div className="container mx-auto px-4">
{!isFormVisible ? (
<div className="max-w-xl mx-auto text-center py-20 animate-fade-in">
<div className="inline-flex p-4 bg-zinc-100 dark:bg-zinc-900 rounded-3xl mb-8 border border-zinc-200 dark:border-zinc-800">
<Wallet2 className="w-8 h-8 text-blue-500" />
</div>
<h1 className="text-4xl font-bold mb-6 tracking-tight">Connect your wallet to get started</h1>
<p className="text-zinc-500 dark:text-zinc-400 mb-10 text-lg">
To register a new project on Dongle, you need to sign an on-chain transaction with your Stellar wallet.
</p>
<Button
onClick={() => setShowForm(true)}
size="lg"
className="px-10"
>
Connect Wallet
</Button>

<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-20">
<Card className="text-left">
<ShieldCheck className="w-6 h-6 text-green-500 mb-3" />
<h3 className="font-bold mb-1">Secure</h3>
<p className="text-xs text-zinc-500">Your keys never leave Freighter.</p>
</Card>
<Card className="text-left">
<Zap className="w-6 h-6 text-yellow-500 mb-3" />
<h3 className="font-bold mb-1">Fast</h3>
<p className="text-xs text-zinc-500">Transactions settle in seconds.</p>
</Card>
<Card className="text-left">
<Rocket className="w-6 h-6 text-blue-500 mb-3" />
<h3 className="font-bold mb-1">Direct</h3>
<p className="text-xs text-zinc-500">Register directly on-chain.</p>
</Card>
</div>
</div>
<h1 className="text-4xl font-bold mb-6 tracking-tight">
Connect your wallet to get started
</h1>
<p className="text-zinc-500 dark:text-zinc-400 mb-10 text-lg">
To register a new project on Dongle, you need to sign an on-chain
transaction with your Stellar wallet.
</p>
<Button
onClick={() => setShowForm(true)}
size="lg"
className="px-10"
>
Connect Wallet
</Button>

<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-20">
<Card className="text-left">
<ShieldCheck className="w-6 h-6 text-green-500 mb-3" />
<h3 className="font-bold mb-1">Secure</h3>
<p className="text-xs text-zinc-500">
Your keys never leave Freighter.
</p>
</Card>
<Card className="text-left">
<Zap className="w-6 h-6 text-yellow-500 mb-3" />
<h3 className="font-bold mb-1">Fast</h3>
<p className="text-xs text-zinc-500">
Transactions settle in seconds.
</p>
</Card>
<Card className="text-left">
<Rocket className="w-6 h-6 text-blue-500 mb-3" />
<h3 className="font-bold mb-1">Direct</h3>
<p className="text-xs text-zinc-500">
Register directly on-chain.
</p>
</Card>
</div>
</div>
) : (
<ProjectForm />
)}
</div>
</main>
) : (
<ProjectForm />
)}
</div>
</main>
</LayoutWrapper>
);
}
2 changes: 1 addition & 1 deletion dongle/app/verify/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default function VerifyPage() {

return (
<LayoutWrapper>
<main className="min-h-screen pt-32 pb-24 bg-[radial-gradient(ellipse_at_top,var(--tw-gradient-stops))] from-green-500/5 via-transparent to-transparent">
<main className="min-h-screen pt-32 pb-24 bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-green-500/5 via-transparent to-transparent">
<div className="container mx-auto px-4">
<div className="max-w-2xl mx-auto text-center mb-12 animate-fade-in">
<h1 className="text-4xl font-bold tracking-tight mb-4">Project Verification</h1>
Expand Down
Loading
Loading