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
29 changes: 28 additions & 1 deletion src/app/developers/tokenize/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
ArrowLeft,
Upload,
Info,
ShieldCheck
ShieldCheck,
Monitor
} from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
Expand Down Expand Up @@ -351,6 +352,32 @@ export default function TokenizationWizardPage() {
</div>
</CardContent>
</Card>

{/* Widget Embed Card */}
<Card className="mt-8 bg-gradient-to-r from-blue-50 to-indigo-50 dark:from-blue-900/20 dark:to-indigo-900/20 border-blue-200 dark:border-blue-800">
<CardContent className="p-6">
<div className="flex items-start gap-4">
<div className="w-12 h-12 bg-blue-600 rounded-xl flex items-center justify-center shrink-0">
<Monitor className="h-6 w-6 text-white" />
</div>
<div className="flex-1">
<h3 className="font-bold text-lg text-gray-900 dark:text-white mb-2">
Embed Investment Calculator on Your Website
</h3>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
Drive more investors to your properties with our embeddable calculator widget.
Customize branding, show projected returns, and add a direct "Invest on PropChain" CTA button.
</p>
<Link href="/widget/embed-code">
<Button className="bg-blue-600 hover:bg-blue-700 text-white">
Get Embed Code
<ArrowRight className="h-4 w-4 ml-2" />
</Button>
</Link>
</div>
</div>
</CardContent>
</Card>
</div>
</div>
);
Expand Down
61 changes: 61 additions & 0 deletions src/app/properties/[id]/PropertyDetailPageClient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use client';

import React from 'react';
import { PropertyDetail } from '@/components/PropertyDetail';
import { WalletConnector } from '@/components/WalletConnector';
import { Button } from '@/components/ui/button';
import Link from 'next/link';
import { ArrowLeft, Monitor } from 'lucide-react';

interface PropertyDetailPageClientProps {
propertyId: string;
}

export function PropertyDetailPageClient({ propertyId }: PropertyDetailPageClientProps) {
return (
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
{/* Header */}
<header className="bg-white dark:bg-gray-800 shadow-sm border-b border-gray-200 dark:border-gray-700 sticky top-0 z-30">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
<div className="flex items-center gap-4">
<Link href="/properties">
<Button variant="ghost" size="sm">
<ArrowLeft className="w-4 h-4 mr-2" />
Back to Properties
</Button>
</Link>
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center">
<span className="text-white font-bold text-sm">PC</span>
</div>
<h1 className="text-xl font-bold text-gray-900 dark:text-white">
PropChain
</h1>
</div>
</div>
<div className="flex items-center gap-3">
<Link href="/secondary-market">
<Button variant="ghost" size="sm" className="text-blue-600 font-semibold">
Secondary Market
</Button>
</Link>
<Link href="/widget/embed-code">
<Button variant="ghost" size="sm" className="text-indigo-600 font-semibold">
<Monitor className="w-4 h-4 mr-1" />
Embed Widget
</Button>
</Link>
<WalletConnector />
</div>
</div>
</div>
</header>

{/* Property Detail */}
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<PropertyDetail propertyId={propertyId} />
</div>
</div>
);
}
56 changes: 52 additions & 4 deletions src/app/properties/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,40 @@
'use client';
import { Suspense } from 'react';
import type { Metadata } from 'next';
import { PropertyDetailPageClient } from './PropertyDetailPageClient';
import { propertyService } from '@/lib/propertyService';

interface PropertyDetailPageProps {
params: Promise<{ id: string }>;
}

export async function generateMetadata({
params,
}: PropertyDetailPageProps): Promise<Metadata> {
const { id } = await params;

try {
const property = await propertyService.getPropertyById(id);
if (!property) {
return {
title: 'Property Not Found - PropChain',
description: 'The requested property could not be found.',
};
}
return {
title: `${property.name} - PropChain`,
description: property.description,
openGraph: {
title: `${property.name} - PropChain`,
description: `${property.name} in ${property.location.city}, ${property.location.state} β€” ${property.propertyType} investment from $${property.price.perToken.toLocaleString()} per token.`,
},
};
} catch {
return {
title: 'Property Not Found - PropChain',
description: 'The requested property could not be found.',
};
}
}
import React from 'react';
import { useParams } from 'next/navigation';
import { PropertyDetail } from '@/components/PropertyDetail';
Expand All @@ -9,11 +44,24 @@ import { Button } from '@/components/ui/button';
import Link from 'next/link';
import { ArrowLeft, Loader2 } from 'lucide-react';

export default function PropertyDetailPage() {
const params = useParams();
const propertyId = params?.id as string;
export default async function PropertyDetailPage({
params,
}: PropertyDetailPageProps) {
const { id } = await params;

return (
<Suspense
fallback={
<div className="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900">
<div className="text-center">
<div className="inline-block w-12 h-12 border-4 border-blue-600 border-t-transparent rounded-full animate-spin mb-4" />
<p className="text-gray-600 dark:text-gray-400">Loading property...</p>
</div>
</div>
}
>
<PropertyDetailPageClient propertyId={id} />
</Suspense>
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
{/* Header */}
<header className="bg-white dark:bg-gray-800 shadow-sm border-b border-gray-200 dark:border-gray-700 sticky top-0 z-30">
Expand Down
Loading
Loading