|
1 | 1 | "use client"; |
2 | 2 |
|
| 3 | +import { useState } from "react"; |
3 | 4 | import Link from "next/link"; |
4 | 5 | import { api, type RouterOutputs } from "~/trpc/react"; |
5 | 6 |
|
@@ -175,6 +176,89 @@ export function AdminDashboardClient() { |
175 | 176 | ))} |
176 | 177 | </div> |
177 | 178 | </Section> |
| 179 | + |
| 180 | + {/* Web export */} |
| 181 | + <WebExportPanel /> |
| 182 | + </div> |
| 183 | + </div> |
| 184 | + ); |
| 185 | +} |
| 186 | + |
| 187 | +function WebExportPanel() { |
| 188 | + const [result, setResult] = useState<{ prUrl?: string; prNumber?: number; memberCount?: number; imagesUploaded?: number; newIdAssignments?: number } | null>(null); |
| 189 | + const [error, setError] = useState<string | null>(null); |
| 190 | + |
| 191 | + const exportMutation = api.admin.exportToWebRepo.useMutation({ |
| 192 | + onSuccess: (data) => { |
| 193 | + if (!data.dryRun) setResult(data); |
| 194 | + }, |
| 195 | + onError: (e) => setError(e.message), |
| 196 | + }); |
| 197 | + |
| 198 | + const dryRunMutation = api.admin.exportToWebRepo.useMutation({ |
| 199 | + onSuccess: (data) => { |
| 200 | + if (data.dryRun) { |
| 201 | + const preview = data as { dryRun: true; memberCount: number; newIdAssignments: number }; |
| 202 | + setResult({ memberCount: preview.memberCount, newIdAssignments: preview.newIdAssignments }); |
| 203 | + } |
| 204 | + }, |
| 205 | + onError: (e) => setError(e.message), |
| 206 | + }); |
| 207 | + |
| 208 | + const isBusy = exportMutation.isPending || dryRunMutation.isPending; |
| 209 | + |
| 210 | + return ( |
| 211 | + <div className="bg-white rounded-xl border border-gray-200 shadow-sm overflow-hidden lg:col-span-2"> |
| 212 | + <div className="flex items-center justify-between px-4 py-3 border-b border-gray-100"> |
| 213 | + <h2 className="text-sm font-semibold text-gray-900">Export Members to Website</h2> |
| 214 | + <span className="text-xs text-gray-400">roborregos-web</span> |
| 215 | + </div> |
| 216 | + <div className="px-4 py-4 space-y-3"> |
| 217 | + <p className="text-xs text-gray-500"> |
| 218 | + Creates a pull request on <span className="font-mono">RoBorregos/roborregos-web</span> with |
| 219 | + updated <span className="font-mono">members.json</span> and member images. |
| 220 | + Members marked “Exclude from export” are skipped. Web IDs are auto-assigned if missing. |
| 221 | + </p> |
| 222 | + |
| 223 | + {error && ( |
| 224 | + <p className="text-xs text-red-600 bg-red-50 rounded-lg px-3 py-2">{error}</p> |
| 225 | + )} |
| 226 | + |
| 227 | + {result?.prUrl && ( |
| 228 | + <div className="text-xs bg-green-50 border border-green-200 rounded-lg px-3 py-2 space-y-1"> |
| 229 | + <p className="font-medium text-green-800">PR created successfully</p> |
| 230 | + <p className="text-green-700"> |
| 231 | + {result.memberCount} members · {result.imagesUploaded} images · {result.newIdAssignments} new IDs assigned |
| 232 | + </p> |
| 233 | + <a href={result.prUrl} target="_blank" rel="noreferrer" className="text-blue-600 hover:underline font-mono"> |
| 234 | + PR #{result.prNumber} |
| 235 | + </a> |
| 236 | + </div> |
| 237 | + )} |
| 238 | + |
| 239 | + {result && !result.prUrl && ( |
| 240 | + <div className="text-xs bg-blue-50 border border-blue-200 rounded-lg px-3 py-2"> |
| 241 | + <p className="font-medium text-blue-800">Dry run complete</p> |
| 242 | + <p className="text-blue-700">{result.memberCount} members to export · {result.newIdAssignments} would get new IDs</p> |
| 243 | + </div> |
| 244 | + )} |
| 245 | + |
| 246 | + <div className="flex gap-2"> |
| 247 | + <button |
| 248 | + onClick={() => { setError(null); setResult(null); dryRunMutation.mutate({ dryRun: true }); }} |
| 249 | + disabled={isBusy} |
| 250 | + className="px-3 py-1.5 text-xs border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 disabled:opacity-50 transition-colors" |
| 251 | + > |
| 252 | + {dryRunMutation.isPending ? "Running…" : "Dry Run"} |
| 253 | + </button> |
| 254 | + <button |
| 255 | + onClick={() => { setError(null); setResult(null); exportMutation.mutate({ dryRun: false }); }} |
| 256 | + disabled={isBusy} |
| 257 | + className="px-3 py-1.5 text-xs bg-[#1a2744] text-white rounded-lg hover:bg-[#243660] disabled:opacity-50 transition-colors" |
| 258 | + > |
| 259 | + {exportMutation.isPending ? "Creating PR…" : "Create PR"} |
| 260 | + </button> |
| 261 | + </div> |
178 | 262 | </div> |
179 | 263 | </div> |
180 | 264 | ); |
|
0 commit comments