mirror of
https://github.com/soconnor0919/beenvoice.git
synced 2026-05-08 09:38:55 -04:00
Set up proper DB migrations and fix remaining mobile responsive issues
Migrations: - drizzle.config.ts: add out: './drizzle' so drizzle-kit generate writes SQL migration files instead of only supporting push - drizzle/0000_glossy_magneto.sql: initial migration capturing all 9 current tables (users, accounts, sessions, verification_tokens, sso_providers, clients, businesses, invoices, invoice_items) - src/server/db/migrate.ts: programmatic runner using drizzle-orm's migrate() — tracks applied migrations in __drizzle_migrations, safe to run on every deploy - package.json: db:migrate now runs the programmatic runner instead of drizzle-kit migrate (CLI requires devDeps at runtime) - start.sh: replace drizzle-kit push with bun src/server/db/migrate.ts - Dockerfile: copy drizzle/ folder into the runner image so migrations are available at container startup Mobile fixes: - data-table.tsx: pagination buttons grow from 32px to 40px on mobile (h-10 w-10 md:h-8 md:w-8) to meet 44px touch-target guidelines - floating-action-bar.tsx: stack left-content + action buttons to column layout on narrow screens (flex-col sm:flex-row), reduce padding on mobile (p-3 sm:p-4) - revenue-chart.tsx: responsive chart height (h-48 md:h-64) so the chart doesn't consume too much vertical space on small screens https://claude.ai/code/session_012sqEgNQpx676isepeoX4Mi
This commit is contained in:
@@ -86,7 +86,7 @@ export function RevenueChart({ data }: RevenueChartProps) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-64 w-full">
|
||||
<div className="h-48 w-full md:h-64">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<AreaChart data={chartData}>
|
||||
<defs>
|
||||
|
||||
@@ -471,7 +471,7 @@ export function DataTable<TData, TValue>({
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="h-8 w-8"
|
||||
className="h-10 w-10 md:h-8 md:w-8"
|
||||
onClick={() => table.setPageIndex(0)}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
>
|
||||
@@ -481,7 +481,7 @@ export function DataTable<TData, TValue>({
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="h-8 w-8"
|
||||
className="h-10 w-10 md:h-8 md:w-8"
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
>
|
||||
@@ -503,7 +503,7 @@ export function DataTable<TData, TValue>({
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="h-8 w-8"
|
||||
className="h-10 w-10 md:h-8 md:w-8"
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
>
|
||||
@@ -513,7 +513,7 @@ export function DataTable<TData, TValue>({
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="h-8 w-8"
|
||||
className="h-10 w-10 md:h-8 md:w-8"
|
||||
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
||||
disabled={!table.getCanNextPage()}
|
||||
>
|
||||
|
||||
@@ -72,7 +72,7 @@ export function FloatingActionBar({
|
||||
)}
|
||||
>
|
||||
<Card className="hover-lift bg-card border-border border shadow-lg">
|
||||
<CardContent className="flex items-center justify-between p-4">
|
||||
<CardContent className="flex flex-col gap-3 p-3 sm:flex-row sm:items-center sm:justify-between sm:p-4">
|
||||
{/* Left content */}
|
||||
{leftContent && (
|
||||
<div className="text-card-foreground animate-fade-in flex flex-1 items-center gap-3">
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Programmatic migration runner for production deployments.
|
||||
*
|
||||
* Run with: bun src/server/db/migrate.ts
|
||||
*
|
||||
* This applies any pending migrations from the drizzle/ directory to the
|
||||
* database specified by DATABASE_URL. It is safe to run multiple times —
|
||||
* Drizzle tracks applied migrations in the __drizzle_migrations table.
|
||||
*/
|
||||
import * as dotenv from "dotenv";
|
||||
|
||||
// Load env files before importing anything that reads process.env
|
||||
dotenv.config({ path: ".env.local" });
|
||||
dotenv.config({ path: ".env" });
|
||||
|
||||
import { Pool } from "pg";
|
||||
import { drizzle } from "drizzle-orm/node-postgres";
|
||||
import { migrate } from "drizzle-orm/node-postgres/migrator";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const databaseUrl = process.env.DATABASE_URL;
|
||||
if (!databaseUrl) {
|
||||
console.error("[migrate] ERROR: DATABASE_URL is not set");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const migrationsFolder = path.resolve(__dirname, "../../../drizzle");
|
||||
|
||||
const pool = new Pool({
|
||||
connectionString: databaseUrl,
|
||||
ssl: process.env.DB_DISABLE_SSL === "true" ? false : { rejectUnauthorized: false },
|
||||
max: 1,
|
||||
});
|
||||
|
||||
const db = drizzle(pool);
|
||||
|
||||
console.log("[migrate] Running migrations from", migrationsFolder);
|
||||
|
||||
try {
|
||||
await migrate(db, { migrationsFolder });
|
||||
console.log("[migrate] All migrations applied successfully");
|
||||
} catch (err) {
|
||||
console.error("[migrate] Migration failed:", err);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await pool.end();
|
||||
}
|
||||
Reference in New Issue
Block a user