Compare commits
5 Commits
98e05193ec
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50f28e2a29 | ||
|
|
79616c8fdc | ||
|
|
287e9a2a0e | ||
|
|
a03d1e8541 | ||
|
|
23fd84d85c |
@@ -11,5 +11,9 @@ export async function GET(req: Request) {
|
|||||||
const target = email
|
const target = email
|
||||||
? `${prefix}/min-sida/oversikt`
|
? `${prefix}/min-sida/oversikt`
|
||||||
: `${prefix}/min-sida/verifiera`;
|
: `${prefix}/min-sida/verifiera`;
|
||||||
return NextResponse.redirect(new URL(target, url.origin));
|
// Use the configured public origin — req.url.origin is the internal
|
||||||
|
// container host (e.g. http://<hash>:3000) when behind Traefik.
|
||||||
|
const base =
|
||||||
|
process.env.NEXT_PUBLIC_SITE_URL ?? process.env.AUTH_URL ?? url.origin;
|
||||||
|
return NextResponse.redirect(new URL(target, base));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
|
import { Link } from '@/i18n/routing';
|
||||||
import { LanguageSwitcher } from './LanguageSwitcher';
|
import { LanguageSwitcher } from './LanguageSwitcher';
|
||||||
|
|
||||||
export function Header() {
|
export function Header() {
|
||||||
const t = useTranslations('header');
|
const t = useTranslations('header');
|
||||||
const c = useTranslations('common');
|
const c = useTranslations('common');
|
||||||
|
const cu = useTranslations('customer');
|
||||||
return (
|
return (
|
||||||
<header className="border-b border-brand-700 bg-brand-600 text-white">
|
<header className="border-b border-brand-700 bg-brand-600 text-white">
|
||||||
<div className="mx-auto flex max-w-5xl items-center justify-between gap-3 px-4 py-3 sm:py-5">
|
<div className="mx-auto flex max-w-5xl items-center justify-between gap-3 px-4 py-3 sm:py-5">
|
||||||
<div className="flex min-w-0 items-center gap-3">
|
<Link
|
||||||
|
href="/"
|
||||||
|
className="flex min-w-0 items-center gap-3 rounded-lg outline-none ring-white/40 transition-opacity hover:opacity-90 focus-visible:ring-2"
|
||||||
|
aria-label={c('siteName')}
|
||||||
|
>
|
||||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-white p-1 shadow-sm sm:h-12 sm:w-12 sm:p-1.5">
|
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-white p-1 shadow-sm sm:h-12 sm:w-12 sm:p-1.5">
|
||||||
<Image
|
<Image
|
||||||
src="/gasol247-logo.png"
|
src="/gasol247-logo.png"
|
||||||
@@ -27,9 +33,17 @@ export function Header() {
|
|||||||
{t('tagline')}
|
{t('tagline')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Link>
|
||||||
|
<div className="flex items-center gap-2 sm:gap-3">
|
||||||
|
<Link
|
||||||
|
href="/min-sida"
|
||||||
|
className="rounded-md border border-white/20 bg-white/10 px-2.5 py-1 text-xs font-medium text-white backdrop-blur-sm transition-colors hover:bg-white/20 sm:px-3 sm:py-1.5"
|
||||||
|
>
|
||||||
|
{cu('navTitle')}
|
||||||
|
</Link>
|
||||||
<LanguageSwitcher />
|
<LanguageSwitcher />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState, useTransition } from 'react';
|
import { useEffect, useState, useTransition } from 'react';
|
||||||
import { useTranslations, useLocale } from 'next-intl';
|
import { useTranslations, useLocale } from 'next-intl';
|
||||||
import {
|
import {
|
||||||
setItemFulfillment,
|
setItemFulfillment,
|
||||||
@@ -36,9 +36,7 @@ export function FulfillmentTable({
|
|||||||
{t('title')}
|
{t('title')}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
<form
|
<form action={markAllDelivered}>
|
||||||
action={(fd) => startTransition(() => markAllDelivered(fd))}
|
|
||||||
>
|
|
||||||
<input type="hidden" name="bookingId" value={bookingId} />
|
<input type="hidden" name="bookingId" value={bookingId} />
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
@@ -48,9 +46,7 @@ export function FulfillmentTable({
|
|||||||
↑ {t('deliverAll')}
|
↑ {t('deliverAll')}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<form
|
<form action={markAllReturned}>
|
||||||
action={(fd) => startTransition(() => markAllReturned(fd))}
|
|
||||||
>
|
|
||||||
<input type="hidden" name="bookingId" value={bookingId} />
|
<input type="hidden" name="bookingId" value={bookingId} />
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
@@ -113,6 +109,13 @@ function FulfillmentRow({
|
|||||||
const [delivered, setDelivered] = useState(item.deliveredQuantity);
|
const [delivered, setDelivered] = useState(item.deliveredQuantity);
|
||||||
const [returned, setReturned] = useState(item.returnedQuantity);
|
const [returned, setReturned] = useState(item.returnedQuantity);
|
||||||
|
|
||||||
|
// Sync local state when server data refreshes (e.g. after deliver-all /
|
||||||
|
// return-all bulk actions). Without this, the inputs stay stale until reload.
|
||||||
|
useEffect(() => {
|
||||||
|
setDelivered(item.deliveredQuantity);
|
||||||
|
setReturned(item.returnedQuantity);
|
||||||
|
}, [item.deliveredQuantity, item.returnedQuantity]);
|
||||||
|
|
||||||
const outstanding = Math.max(0, delivered - returned);
|
const outstanding = Math.max(0, delivered - returned);
|
||||||
const dirty =
|
const dirty =
|
||||||
delivered !== item.deliveredQuantity || returned !== item.returnedQuantity;
|
delivered !== item.deliveredQuantity || returned !== item.returnedQuantity;
|
||||||
|
|||||||
Reference in New Issue
Block a user