Add PayloadCMS type definitions, Prettier config, and PNPM lockfile

This commit is contained in:
2025-09-13 17:17:50 +02:00
parent bb86a68fa2
commit b995bdb505
50 changed files with 16356 additions and 0 deletions

68
src/exports/client.tsx Normal file
View File

@@ -0,0 +1,68 @@
/**
* Client-side components and utilities for the billing plugin
* These components run in the browser and have access to React hooks and client-side APIs
*/
'use client'
import React from 'react'
// Example client component that could be used in the admin dashboard
export const BillingDashboardWidget: React.FC = () => {
return (
<div className="billing-dashboard-widget">
<h3>Billing Overview</h3>
<p>Payment statistics and recent transactions will be displayed here.</p>
</div>
)
}
// Client-side utilities
export const formatCurrency = (amount: number, currency: string) => {
return new Intl.NumberFormat('en-US', {
currency: currency.toUpperCase(),
style: 'currency',
}).format(amount / 100)
}
export const getPaymentStatusColor = (status: string) => {
switch (status) {
case 'canceled':
return 'gray'
case 'failed':
return 'red'
case 'pending':
return 'yellow'
case 'succeeded':
return 'green'
default:
return 'blue'
}
}
// Example of a client component for payment status display
export const PaymentStatusBadge: React.FC<{ status: string }> = ({ status }) => {
const color = getPaymentStatusColor(status)
return (
<span
className={`payment-status-badge payment-status-${status}`}
style={{
backgroundColor: color,
borderRadius: '4px',
color: 'white',
fontSize: '12px',
padding: '2px 8px'
}}
>
{status.toUpperCase()}
</span>
)
}
export default {
BillingDashboardWidget,
formatCurrency,
getPaymentStatusColor,
PaymentStatusBadge,
}

146
src/exports/rsc.tsx Normal file
View File

@@ -0,0 +1,146 @@
/**
* React Server Components (RSC) and server-side utilities for the billing plugin
* These components run on the server and can access server-side APIs and databases
*/
import React from 'react'
// Server component that can fetch data during server-side rendering
interface BillingServerStatsProps {
payloadInstance?: unknown
}
export const BillingServerStats: React.FC<BillingServerStatsProps> = async ({
payloadInstance
}) => {
// In a real implementation, this would fetch data from the database
// const stats = await payloadInstance?.find({
// collection: 'payments',
// limit: 0,
// depth: 0
// })
return (
<div className="billing-server-stats">
<h3>Payment Statistics</h3>
<div className="stats-grid">
<div className="stat-item">
<span className="stat-label">Total Payments</span>
<span className="stat-value">-</span>
</div>
<div className="stat-item">
<span className="stat-label">Successful</span>
<span className="stat-value">-</span>
</div>
<div className="stat-item">
<span className="stat-label">Pending</span>
<span className="stat-value">-</span>
</div>
<div className="stat-item">
<span className="stat-label">Failed</span>
<span className="stat-value">-</span>
</div>
</div>
</div>
)
}
// Server-side utility functions
export const generateInvoiceNumber = () => {
const timestamp = Date.now()
const random = Math.random().toString(36).substring(2, 8).toUpperCase()
return `INV-${timestamp}-${random}`
}
export const calculateInvoiceTotal = (items: Array<{
quantity: number
unitAmount: number
}>, taxRate: number = 0) => {
const subtotal = items.reduce((sum, item) => sum + (item.quantity * item.unitAmount), 0)
const taxAmount = Math.round(subtotal * taxRate)
return {
subtotal,
taxAmount,
total: subtotal + taxAmount
}
}
// Server component for displaying invoice details
interface InvoiceDetailsProps {
invoice?: {
amount: number
currency: string
customer?: {
email?: string
name?: string
}
dueDate?: string
items?: Array<{
description: string
quantity: number
totalAmount: number
unitAmount: number
}>
number: string
status: string
}
readonly?: boolean
}
export const InvoiceDetails: React.FC<InvoiceDetailsProps> = ({ invoice, readonly = false }) => {
if (!invoice) {
return <div>No invoice data available</div>
}
return (
<div className="invoice-details">
<div className="invoice-header">
<h3>Invoice {invoice.number}</h3>
<span className={`status-badge status-${invoice.status}`}>
{invoice.status}
</span>
</div>
<div className="invoice-content">
<div className="invoice-meta">
<p><strong>Customer:</strong> {invoice.customer?.name || invoice.customer?.email}</p>
<p><strong>Due Date:</strong> {invoice.dueDate ? new Date(invoice.dueDate).toLocaleDateString() : 'N/A'}</p>
<p><strong>Amount:</strong> {invoice.currency} {(invoice.amount / 100).toFixed(2)}</p>
</div>
{invoice.items && invoice.items.length > 0 && (
<div className="invoice-items">
<h4>Items</h4>
<table className="items-table">
<thead>
<tr>
<th>Description</th>
<th>Quantity</th>
<th>Unit Amount</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{invoice.items.map((item, index) => (
<tr key={index}>
<td>{item.description}</td>
<td>{item.quantity}</td>
<td>{invoice.currency} {(item.unitAmount / 100).toFixed(2)}</td>
<td>{invoice.currency} {(item.totalAmount / 100).toFixed(2)}</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
</div>
)
}
export default {
BillingServerStats,
calculateInvoiceTotal,
generateInvoiceNumber,
InvoiceDetails,
}