dealroom/templates/dealroom.templ

209 lines
9.3 KiB
Plaintext

package templates
import "dealroom/internal/model"
import "fmt"
templ DealRoomDetail(profile *model.Profile, deal *model.Deal, folders []*model.Folder, files []*model.File, requests []*model.DiligenceRequest) {
@Layout(profile, "deals") {
<div class="space-y-5">
<!-- Header -->
<div>
<a href="/deals" class="text-sm text-gray-500 hover:text-gray-300 flex items-center gap-1 mb-3">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
Back to Deal Rooms
</a>
<div class="flex items-center gap-3">
<h1 class="text-2xl font-bold">{ deal.Name }</h1>
@StageBadge(deal.Stage)
</div>
<p class="text-sm text-gray-500 mt-1">{ deal.TargetCompany } · { deal.Description }</p>
</div>
<!-- Deal Info Cards -->
<div class="grid grid-cols-4 gap-4">
<div class="bg-gray-900 rounded-lg border border-gray-800 p-4">
<div class="text-xs text-gray-500 uppercase tracking-wider mb-1">Deal Size</div>
<div class="text-lg font-bold">{ formatDealSize(deal.DealSize) }</div>
</div>
<div class="bg-gray-900 rounded-lg border border-gray-800 p-4">
<div class="text-xs text-gray-500 uppercase tracking-wider mb-1">Close Probability</div>
<div class="text-lg font-bold">{ fmt.Sprintf("%d%%", deal.CloseProbability) }</div>
</div>
<div class="bg-gray-900 rounded-lg border border-gray-800 p-4">
<div class="text-xs text-gray-500 uppercase tracking-wider mb-1">IOI Date</div>
<div class="text-lg font-bold">
if deal.IOIDate != "" {
{ deal.IOIDate }
} else {
<span class="text-gray-600">—</span>
}
</div>
</div>
<div class="bg-gray-900 rounded-lg border border-gray-800 p-4">
<div class="text-xs text-gray-500 uppercase tracking-wider mb-1">Exclusivity Ends</div>
<div class="text-lg font-bold">
if deal.ExclusivityEnd != "" {
{ deal.ExclusivityEnd }
} else {
<span class="text-gray-600">—</span>
}
</div>
</div>
</div>
<!-- Tabs -->
<div x-data="{ tab: 'documents' }">
<div class="flex gap-1 border-b border-gray-800 mb-4">
<button onclick="showTab('documents')" id="tab-documents" class="px-4 py-2 text-sm font-medium border-b-2 border-teal-500 text-teal-400">
Documents ({ fmt.Sprintf("%d", len(files)) })
</button>
<button onclick="showTab('requests')" id="tab-requests" class="px-4 py-2 text-sm font-medium border-b-2 border-transparent text-gray-500 hover:text-gray-300">
Request List ({ fmt.Sprintf("%d", len(requests)) })
</button>
</div>
<!-- Documents Tab -->
<div id="panel-documents">
<div class="grid grid-cols-4 gap-4">
<!-- Folder Tree -->
<div class="bg-gray-900 rounded-lg border border-gray-800 p-3">
<h3 class="text-xs font-medium text-gray-500 uppercase tracking-wider mb-3">Folders</h3>
for _, folder := range folders {
if folder.ParentID == "" {
<div class="mb-1">
<div class="flex items-center gap-1.5 py-1.5 px-2 rounded hover:bg-gray-800 text-sm cursor-pointer">
<svg class="w-4 h-4 text-teal-400/70 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"></path></svg>
<span class="truncate text-gray-300">{ folder.Name }</span>
</div>
<!-- Child folders -->
for _, child := range folders {
if child.ParentID == folder.ID {
<div class="ml-4">
<div class="flex items-center gap-1.5 py-1.5 px-2 rounded hover:bg-gray-800 text-sm cursor-pointer">
<svg class="w-4 h-4 text-teal-400/70 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"></path></svg>
<span class="truncate text-gray-300">{ child.Name }</span>
</div>
</div>
}
}
</div>
}
}
</div>
<!-- Files Table -->
<div class="col-span-3 bg-gray-900 rounded-lg border border-gray-800">
<table class="w-full">
<thead>
<tr class="border-b border-gray-800">
<th class="text-left px-4 py-2.5 text-xs font-medium text-gray-500 uppercase tracking-wider">File Name</th>
<th class="text-left px-4 py-2.5 text-xs font-medium text-gray-500 uppercase tracking-wider w-24">Size</th>
<th class="text-left px-4 py-2.5 text-xs font-medium text-gray-500 uppercase tracking-wider w-24">Status</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-800/50">
for _, file := range files {
<tr class="hover:bg-gray-800/30 transition">
<td class="px-4 py-2.5">
<div class="flex items-center gap-2">
@fileIcon(file.Name)
<span class="text-sm">{ file.Name }</span>
</div>
</td>
<td class="px-4 py-2.5 text-xs text-gray-500">{ formatFileSize(file.FileSize) }</td>
<td class="px-4 py-2.5">@FileStatusBadge(file.Status)</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
<!-- Requests Tab -->
<div id="panel-requests" style="display:none">
<div class="bg-gray-900 rounded-lg border border-gray-800">
<table class="w-full">
<thead>
<tr class="border-b border-gray-800">
<th class="text-left px-4 py-2.5 text-xs font-medium text-gray-500 uppercase tracking-wider w-16">#</th>
<th class="text-left px-4 py-2.5 text-xs font-medium text-gray-500 uppercase tracking-wider w-24">Section</th>
<th class="text-left px-4 py-2.5 text-xs font-medium text-gray-500 uppercase tracking-wider">Request Item</th>
<th class="text-left px-4 py-2.5 text-xs font-medium text-gray-500 uppercase tracking-wider w-16">Priority</th>
<th class="text-left px-4 py-2.5 text-xs font-medium text-gray-500 uppercase tracking-wider w-20">Atlas</th>
<th class="text-left px-4 py-2.5 text-xs font-medium text-gray-500 uppercase tracking-wider w-16">Conf.</th>
<th class="text-left px-4 py-2.5 text-xs font-medium text-gray-500 uppercase tracking-wider">Buyer</th>
<th class="text-left px-4 py-2.5 text-xs font-medium text-gray-500 uppercase tracking-wider">Seller</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-800/50">
for _, req := range requests {
<tr class="hover:bg-gray-800/30">
<td class="px-4 py-2.5 text-xs text-gray-500">{ req.ItemNumber }</td>
<td class="px-4 py-2.5 text-xs text-gray-400">{ req.Section }</td>
<td class="px-4 py-2.5 text-sm">{ req.Description }</td>
<td class="px-4 py-2.5">@PriorityBadge(req.Priority)</td>
<td class="px-4 py-2.5">@StatusIcon(req.AtlasStatus)</td>
<td class="px-4 py-2.5 text-xs text-gray-500">
if req.Confidence > 0 {
{ fmt.Sprintf("%d%%", req.Confidence) }
}
</td>
<td class="px-4 py-2.5 text-xs text-gray-400 max-w-[140px] truncate">{ req.BuyerComment }</td>
<td class="px-4 py-2.5 text-xs text-gray-400 max-w-[140px] truncate">{ req.SellerComment }</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
<script>
function showTab(name) {
document.getElementById('panel-documents').style.display = name === 'documents' ? '' : 'none';
document.getElementById('panel-requests').style.display = name === 'requests' ? '' : 'none';
document.getElementById('tab-documents').className = name === 'documents'
? 'px-4 py-2 text-sm font-medium border-b-2 border-teal-500 text-teal-400'
: 'px-4 py-2 text-sm font-medium border-b-2 border-transparent text-gray-500 hover:text-gray-300';
document.getElementById('tab-requests').className = name === 'requests'
? 'px-4 py-2 text-sm font-medium border-b-2 border-teal-500 text-teal-400'
: 'px-4 py-2 text-sm font-medium border-b-2 border-transparent text-gray-500 hover:text-gray-300';
}
</script>
</div>
}
}
func formatFileSize(bytes int64) string {
if bytes < 1024 {
return fmt.Sprintf("%d B", bytes)
}
if bytes < 1024*1024 {
return fmt.Sprintf("%d KB", bytes/1024)
}
return fmt.Sprintf("%.1f MB", float64(bytes)/(1024*1024))
}
templ fileIcon(name string) {
<div class={ "w-7 h-7 rounded flex items-center justify-center text-xs font-semibold text-white",
templ.KV("bg-red-500", hasSuffix(name, ".pdf")),
templ.KV("bg-green-600", hasSuffix(name, ".xlsx") || hasSuffix(name, ".csv")),
templ.KV("bg-blue-500", hasSuffix(name, ".doc") || hasSuffix(name, ".docx")),
templ.KV("bg-gray-600", !hasSuffix(name, ".pdf") && !hasSuffix(name, ".xlsx") && !hasSuffix(name, ".csv") && !hasSuffix(name, ".doc") && !hasSuffix(name, ".docx")) }>
if hasSuffix(name, ".pdf") {
PDF
} else if hasSuffix(name, ".xlsx") || hasSuffix(name, ".csv") {
XLS
} else if hasSuffix(name, ".doc") || hasSuffix(name, ".docx") {
DOC
} else {
FILE
}
</div>
}
func hasSuffix(s, suffix string) bool {
return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
}