Revert "Merge pull request 'Dev' (#58) from Dev into production"
This reverts commit821e96e011, reversing changes made to0ff39e9e58.
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
# `next build` runs inside the image (see Dockerfile), so local build output and dependencies must
|
||||
# not be sent as build context: they are large, and a Windows node_modules would break the Linux build.
|
||||
node_modules
|
||||
.next
|
||||
.git
|
||||
.env*
|
||||
*.tsbuildinfo
|
||||
npm-debug.log*
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
@@ -1,38 +0,0 @@
|
||||
# ERP frontend image — built on the server by .gitea/workflows/ci-cd.yml (`docker build`), using the
|
||||
# same pattern as Client_New_Fe. There are no build args: the app only calls same-origin /api/v1 and
|
||||
# Apache routes /api/ straight to ERPCore (docs/40-DEPLOYMENT.md, "Active").
|
||||
|
||||
FROM node:24-alpine AS deps
|
||||
WORKDIR /app
|
||||
RUN apk add --no-cache libc6-compat
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci --no-audit --no-fund
|
||||
|
||||
FROM node:24-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
# Shared 8 GB VPS: keep the build's heap bounded (docker build has no --memory under BuildKit).
|
||||
ENV NEXT_TELEMETRY_DISABLED=1 \
|
||||
NODE_ENV=production \
|
||||
NODE_OPTIONS=--max-old-space-size=2048
|
||||
RUN npm run build
|
||||
|
||||
FROM node:24-alpine AS runner
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production \
|
||||
NEXT_TELEMETRY_DISABLED=1 \
|
||||
PORT=3000 \
|
||||
HOSTNAME=0.0.0.0
|
||||
|
||||
RUN addgroup --system --gid 1001 nodejs \
|
||||
&& adduser --system --uid 1001 nextjs
|
||||
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
USER nextjs
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
@@ -112,17 +112,6 @@ function NewPurchaseInvoiceContent() {
|
||||
[vendors]
|
||||
)
|
||||
|
||||
// Deep-linked from a GRN detail page's "Create Purchase Invoice" prompt — that GRN is the
|
||||
// whole reason this page was opened, so show only it rather than the vendor's full eligible
|
||||
// list (which could pull in unrelated GRNs the user never meant to consolidate here).
|
||||
// Declared before toggleAll, which reads it: referencing it ahead of its declaration stopped
|
||||
// the React Compiler from preserving this memo (react-hooks/preserve-manual-memoization).
|
||||
const deepLinkedGrnId = grnIdFromQuery ? Number(grnIdFromQuery) : null
|
||||
const visibleGrns = useMemo(
|
||||
() => (deepLinkedGrnId === null ? (eligibleGrns ?? []) : (eligibleGrns ?? []).filter((g) => g.grnId === deepLinkedGrnId)),
|
||||
[eligibleGrns, deepLinkedGrnId]
|
||||
)
|
||||
|
||||
function toggleGrn(grnId: number, checked: boolean) {
|
||||
setSelectedGrnIds((prev) => {
|
||||
const next = new Set(prev)
|
||||
@@ -136,6 +125,15 @@ function NewPurchaseInvoiceContent() {
|
||||
setSelectedGrnIds(checked ? new Set(visibleGrns.map((g) => g.grnId)) : new Set())
|
||||
}
|
||||
|
||||
// Deep-linked from a GRN detail page's "Create Purchase Invoice" prompt — that GRN is the
|
||||
// whole reason this page was opened, so show only it rather than the vendor's full eligible
|
||||
// list (which could pull in unrelated GRNs the user never meant to consolidate here).
|
||||
const deepLinkedGrnId = grnIdFromQuery ? Number(grnIdFromQuery) : null
|
||||
const visibleGrns = useMemo(
|
||||
() => (deepLinkedGrnId === null ? (eligibleGrns ?? []) : (eligibleGrns ?? []).filter((g) => g.grnId === deepLinkedGrnId)),
|
||||
[eligibleGrns, deepLinkedGrnId]
|
||||
)
|
||||
|
||||
const selectedGrns = useMemo(
|
||||
() => (eligibleGrns ?? []).filter((g) => selectedGrnIds.has(g.grnId)),
|
||||
[eligibleGrns, selectedGrnIds]
|
||||
|
||||
@@ -88,7 +88,7 @@ export default function SalesDayEndPage() {
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-foreground">Day End</h1>
|
||||
<p className="text-base text-muted-foreground">
|
||||
Close a cashier's business day — locks their posted sales slips and bundle sales, and posts one consolidated journal entry to the ledger.
|
||||
Close a cashier's business day — locks their posted sales slips and bundle sales, and posts one consolidated journal entry to the ledger.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -149,14 +149,14 @@ export default function InvoiceTemplatePage() {
|
||||
<Switch checked={showBankDetails} onCheckedChange={setShowBankDetails} className="mt-1 shrink-0" aria-label="Show bank details" />
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-base font-medium text-foreground">Show bank details</span>
|
||||
<span className="text-sm text-muted-foreground">Prints the company's bank name, account and SWIFT code on invoices.</span>
|
||||
<span className="text-sm text-muted-foreground">Prints the company's bank name, account and SWIFT code on invoices.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-start gap-4 py-4">
|
||||
<Switch checked={showTaxRegNo} onCheckedChange={setShowTaxRegNo} className="mt-1 shrink-0" aria-label="Show tax registration no." />
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-base font-medium text-foreground">Show tax registration no.</span>
|
||||
<span className="text-sm text-muted-foreground">Prints the company's tax registration number in the invoice header.</span>
|
||||
<span className="text-sm text-muted-foreground">Prints the company's tax registration number in the invoice header.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -32,7 +32,7 @@ export default function ForgotOtpPage() {
|
||||
</div>
|
||||
<h1 className="text-2xl font-bold text-foreground text-center">Verify your email</h1>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground text-center mb-8">We've sent a verification code to your email address. Enter it below to continue.</p>
|
||||
<p className="text-sm text-muted-foreground text-center mb-8">We've sent a verification code to your email address. Enter it below to continue.</p>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className="flex justify-center">
|
||||
@@ -48,7 +48,7 @@ export default function ForgotOtpPage() {
|
||||
}}
|
||||
className="text-sm font-medium text-foreground hover:text-foreground/80 transition-colors"
|
||||
>
|
||||
Didn't receive the code? Resend
|
||||
Didn't receive the code? Resend
|
||||
</button>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">Resend code available in <span className="font-semibold text-foreground">{Math.max(0, secondsLeft)}s</span></p>
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function ForgotEmailPage() {
|
||||
<div className="w-full max-w-2xl rounded-xl bg-card p-8 pl-10 shadow-lg border border-border">
|
||||
<div className="mb-8 text-center">
|
||||
<h1 className="text-2xl font-bold text-foreground">Reset your password</h1>
|
||||
<p className="mt-2 text-sm text-muted-foreground">Enter the email address associated with your account and we'll send you a one-time code to verify your identity.</p>
|
||||
<p className="mt-2 text-sm text-muted-foreground">Enter the email address associated with your account and we'll send you a one-time code to verify your identity.</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
|
||||
@@ -13,19 +13,6 @@ import {
|
||||
} from "@/components/ui/dialog"
|
||||
import { Check, Eye, EyeOff } from "lucide-react"
|
||||
|
||||
// Declared at module scope: a component defined inside the page body is a new type on every
|
||||
// render, so React would remount (and reset) each requirement row on each keystroke.
|
||||
function PasswordRequirement({ met, label }: { met: boolean; label: string }) {
|
||||
return (
|
||||
<div className="flex items-center gap-3">
|
||||
<div className={`flex items-center justify-center w-5 h-5 rounded-full shrink-0 text-sm font-semibold ${met ? 'bg-success/10 text-success' : 'bg-muted text-muted-foreground'}`}>
|
||||
{met ? <Check className="size-4" /> : <span>○</span>}
|
||||
</div>
|
||||
<span className={`text-sm ${met ? 'text-foreground font-medium' : 'text-muted-foreground'}`}>{label}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function ForgotResetPage() {
|
||||
const router = useRouter()
|
||||
const [password, setPassword] = useState("")
|
||||
@@ -41,6 +28,15 @@ export default function ForgotResetPage() {
|
||||
const passwordsMatch = password === confirm && password.length > 0
|
||||
const allValid = meetsLength && hasUpper && hasNumber && hasSpecial && passwordsMatch
|
||||
|
||||
const PasswordRequirement = ({ met, label }: { met: boolean; label: string }) => (
|
||||
<div className="flex items-center gap-3">
|
||||
<div className={`flex items-center justify-center w-5 h-5 rounded-full shrink-0 text-sm font-semibold ${met ? 'bg-success/10 text-success' : 'bg-muted text-muted-foreground'}`}>
|
||||
{met ? <Check className="size-4" /> : <span>○</span>}
|
||||
</div>
|
||||
<span className={`text-sm ${met ? 'text-foreground font-medium' : 'text-muted-foreground'}`}>{label}</span>
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-background to-background/95 p-4">
|
||||
<div className="w-full max-w-xl rounded-xl bg-card p-8 shadow-lg border border-border">
|
||||
@@ -101,7 +97,7 @@ export default function ForgotResetPage() {
|
||||
</div>
|
||||
|
||||
{!passwordsMatch && confirm.length > 0 && (
|
||||
<p className="text-sm text-error font-medium">Passwords don't match.</p>
|
||||
<p className="text-sm text-error font-medium">Passwords don't match.</p>
|
||||
)}
|
||||
|
||||
<div className="flex gap-3">
|
||||
|
||||
@@ -5,14 +5,6 @@ import nextTs from "eslint-config-next/typescript";
|
||||
const eslintConfig = defineConfig([
|
||||
...nextVitals,
|
||||
...nextTs,
|
||||
{
|
||||
rules: {
|
||||
// Temporarily a warning: ~80 pre-existing violations from the React Compiler rules that
|
||||
// eslint-config-next 16 enabled. Everything else stays an error so CI can gate on lint
|
||||
// now; flip this back to "error" once the backlog is cleared (docs/40-DEPLOYMENT.md §7).
|
||||
"react-hooks/set-state-in-effect": "warn",
|
||||
},
|
||||
},
|
||||
// Override default ignores of eslint-config-next.
|
||||
globalIgnores([
|
||||
// Default ignores of eslint-config-next:
|
||||
|
||||
@@ -8,16 +8,9 @@ import path from "path"
|
||||
//
|
||||
// Defaults to the backend's HTTP port: the HTTPS port uses a self-signed dev cert that
|
||||
// this proxy would reject.
|
||||
//
|
||||
// Rewrites are resolved at `next build`, so this is effectively a local-dev setting. In the
|
||||
// deployed environments Apache sends /api/ straight to ERPCore before Next ever sees it, which
|
||||
// keeps one built image valid for both test and release (docs/40-DEPLOYMENT.md).
|
||||
const BACKEND_ORIGIN = process.env.BACKEND_ORIGIN ?? "http://localhost:5224"
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
// Self-contained server bundle (.next/standalone) for the runtime-only Docker image
|
||||
// (Dockerfile in this folder). Has no effect on `next dev`.
|
||||
output: "standalone",
|
||||
turbopack: {
|
||||
root: path.join(__dirname),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user