fix(dates): use local 'today' for date-input defaults instead of the UTC date
11 form defaults across 6 files used new Date().toISOString().split('T')[0] (the UTC date), which lands on yesterday during the post-midnight Prague window (UTC+1/+2). Added todayLocalStr() (local YYYY-MM-DD) in formatters and replaced them. Future-date expressions (e.g. invoice due_date +14d) left untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@ import { Link } from "react-router-dom";
|
|||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
import { useAuth } from "../../context/AuthContext";
|
import { useAuth } from "../../context/AuthContext";
|
||||||
import { useAlert } from "../../context/AlertContext";
|
import { useAlert } from "../../context/AlertContext";
|
||||||
import { formatKm } from "../../utils/formatters";
|
import { formatKm, todayLocalStr } from "../../utils/formatters";
|
||||||
import AdminDatePicker from "../AdminDatePicker";
|
import AdminDatePicker from "../AdminDatePicker";
|
||||||
import apiFetch from "../../utils/api";
|
import apiFetch from "../../utils/api";
|
||||||
import useModalLock from "../../hooks/useModalLock";
|
import useModalLock from "../../hooks/useModalLock";
|
||||||
@@ -74,7 +74,7 @@ export default function DashQuickActions({
|
|||||||
const openTripModal = async () => {
|
const openTripModal = async () => {
|
||||||
setTripForm({
|
setTripForm({
|
||||||
vehicle_id: "",
|
vehicle_id: "",
|
||||||
trip_date: new Date().toISOString().split("T")[0],
|
trip_date: todayLocalStr(),
|
||||||
start_km: "",
|
start_km: "",
|
||||||
end_km: "",
|
end_km: "",
|
||||||
route_from: "",
|
route_from: "",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import Forbidden from "../components/Forbidden";
|
|||||||
import apiFetch from "../utils/api";
|
import apiFetch from "../utils/api";
|
||||||
import { jsonQuery } from "../lib/apiAdapter";
|
import { jsonQuery } from "../lib/apiAdapter";
|
||||||
import { useApiMutation } from "../lib/queries/mutations";
|
import { useApiMutation } from "../lib/queries/mutations";
|
||||||
import { czechPlural } from "../utils/formatters";
|
import { czechPlural, todayLocalStr } from "../utils/formatters";
|
||||||
|
|
||||||
const API_BASE = "/api/admin";
|
const API_BASE = "/api/admin";
|
||||||
|
|
||||||
@@ -140,8 +140,8 @@ export default function Attendance() {
|
|||||||
const [isLeaveModalOpen, setIsLeaveModalOpen] = useState(false);
|
const [isLeaveModalOpen, setIsLeaveModalOpen] = useState(false);
|
||||||
const [leaveForm, setLeaveForm] = useState({
|
const [leaveForm, setLeaveForm] = useState({
|
||||||
leave_type: "vacation",
|
leave_type: "vacation",
|
||||||
date_from: new Date().toISOString().split("T")[0],
|
date_from: todayLocalStr(),
|
||||||
date_to: new Date().toISOString().split("T")[0],
|
date_to: todayLocalStr(),
|
||||||
notes: "",
|
notes: "",
|
||||||
});
|
});
|
||||||
const [requestSubmitting, setRequestSubmitting] = useState(false);
|
const [requestSubmitting, setRequestSubmitting] = useState(false);
|
||||||
@@ -334,8 +334,8 @@ export default function Attendance() {
|
|||||||
alert.success(result?.message || "Žádost odeslána");
|
alert.success(result?.message || "Žádost odeslána");
|
||||||
setLeaveForm({
|
setLeaveForm({
|
||||||
leave_type: "vacation",
|
leave_type: "vacation",
|
||||||
date_from: new Date().toISOString().split("T")[0],
|
date_from: todayLocalStr(),
|
||||||
date_to: new Date().toISOString().split("T")[0],
|
date_to: todayLocalStr(),
|
||||||
notes: "",
|
notes: "",
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { motion } from "framer-motion";
|
|||||||
import AdminDatePicker from "../components/AdminDatePicker";
|
import AdminDatePicker from "../components/AdminDatePicker";
|
||||||
import FormField from "../components/FormField";
|
import FormField from "../components/FormField";
|
||||||
import { useApiMutation } from "../lib/queries/mutations";
|
import { useApiMutation } from "../lib/queries/mutations";
|
||||||
|
import { todayLocalStr } from "../utils/formatters";
|
||||||
const API_BASE = "/api/admin";
|
const API_BASE = "/api/admin";
|
||||||
|
|
||||||
interface CreateForm {
|
interface CreateForm {
|
||||||
@@ -46,7 +47,7 @@ export default function AttendanceCreate() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [form, setForm] = useState<CreateForm>(() => {
|
const [form, setForm] = useState<CreateForm>(() => {
|
||||||
const today = new Date().toISOString().split("T")[0];
|
const today = todayLocalStr();
|
||||||
return {
|
return {
|
||||||
user_id: "",
|
user_id: "",
|
||||||
shift_date: today,
|
shift_date: today,
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ import {
|
|||||||
import { offerCustomersOptions, type Customer } from "../lib/queries/offers";
|
import { offerCustomersOptions, type Customer } from "../lib/queries/offers";
|
||||||
import { bankAccountsOptions, type BankAccount } from "../lib/queries/common";
|
import { bankAccountsOptions, type BankAccount } from "../lib/queries/common";
|
||||||
import { jsonQuery } from "../lib/apiAdapter";
|
import { jsonQuery } from "../lib/apiAdapter";
|
||||||
import { formatCurrency, formatDate } from "../utils/formatters";
|
import { formatCurrency, formatDate, todayLocalStr } from "../utils/formatters";
|
||||||
|
|
||||||
const API_BASE = "/api/admin";
|
const API_BASE = "/api/admin";
|
||||||
|
|
||||||
@@ -326,9 +326,9 @@ export default function InvoiceDetail() {
|
|||||||
customer_id: null,
|
customer_id: null,
|
||||||
customer_name: "",
|
customer_name: "",
|
||||||
order_id: fromOrderId ? Number(fromOrderId) : null,
|
order_id: fromOrderId ? Number(fromOrderId) : null,
|
||||||
issue_date: new Date().toISOString().split("T")[0],
|
issue_date: todayLocalStr(),
|
||||||
due_date: new Date(Date.now() + 14 * 86400000).toISOString().split("T")[0],
|
due_date: new Date(Date.now() + 14 * 86400000).toISOString().split("T")[0],
|
||||||
tax_date: new Date().toISOString().split("T")[0],
|
tax_date: todayLocalStr(),
|
||||||
currency: "CZK",
|
currency: "CZK",
|
||||||
apply_vat: 1,
|
apply_vat: 1,
|
||||||
vat_rate: 21,
|
vat_rate: 21,
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ import AdminDatePicker from "../components/AdminDatePicker";
|
|||||||
import RichEditor from "../components/RichEditor";
|
import RichEditor from "../components/RichEditor";
|
||||||
import useDebounce from "../hooks/useDebounce";
|
import useDebounce from "../hooks/useDebounce";
|
||||||
import apiFetch from "../utils/api";
|
import apiFetch from "../utils/api";
|
||||||
import { formatCurrency } from "../utils/formatters";
|
import { formatCurrency, todayLocalStr } from "../utils/formatters";
|
||||||
import {
|
import {
|
||||||
companySettingsOptions,
|
companySettingsOptions,
|
||||||
type CompanySettingsData,
|
type CompanySettingsData,
|
||||||
@@ -101,7 +101,7 @@ const emptyForm: OfferForm = {
|
|||||||
project_code: "",
|
project_code: "",
|
||||||
customer_id: null,
|
customer_id: null,
|
||||||
customer_name: "",
|
customer_name: "",
|
||||||
created_at: new Date().toISOString().split("T")[0],
|
created_at: todayLocalStr(),
|
||||||
valid_until: "",
|
valid_until: "",
|
||||||
currency: "CZK",
|
currency: "CZK",
|
||||||
language: "EN",
|
language: "EN",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import FormModal from "../components/FormModal";
|
|||||||
import FormField from "../components/FormField";
|
import FormField from "../components/FormField";
|
||||||
import Forbidden from "../components/Forbidden";
|
import Forbidden from "../components/Forbidden";
|
||||||
import { formatDate } from "../utils/attendanceHelpers";
|
import { formatDate } from "../utils/attendanceHelpers";
|
||||||
import { formatKm } from "../utils/formatters";
|
import { formatKm, todayLocalStr } from "../utils/formatters";
|
||||||
import apiFetch from "../utils/api";
|
import apiFetch from "../utils/api";
|
||||||
import {
|
import {
|
||||||
tripListOptions,
|
tripListOptions,
|
||||||
@@ -53,7 +53,7 @@ export default function Trips() {
|
|||||||
}>({ show: false, tripId: null });
|
}>({ show: false, tripId: null });
|
||||||
const [form, setForm] = useState<TripForm>({
|
const [form, setForm] = useState<TripForm>({
|
||||||
vehicle_id: "",
|
vehicle_id: "",
|
||||||
trip_date: new Date().toISOString().split("T")[0],
|
trip_date: todayLocalStr(),
|
||||||
start_km: "",
|
start_km: "",
|
||||||
end_km: "",
|
end_km: "",
|
||||||
route_from: "",
|
route_from: "",
|
||||||
@@ -117,10 +117,9 @@ export default function Trips() {
|
|||||||
|
|
||||||
const openCreateModal = () => {
|
const openCreateModal = () => {
|
||||||
setEditingTrip(null);
|
setEditingTrip(null);
|
||||||
const today = new Date().toISOString().split("T")[0];
|
|
||||||
setForm({
|
setForm({
|
||||||
vehicle_id: "",
|
vehicle_id: "",
|
||||||
trip_date: today,
|
trip_date: todayLocalStr(),
|
||||||
start_km: "",
|
start_km: "",
|
||||||
end_km: "",
|
end_km: "",
|
||||||
route_from: "",
|
route_from: "",
|
||||||
|
|||||||
@@ -23,6 +23,19 @@ export function formatDate(dateStr: string | null | undefined): string {
|
|||||||
return d.toLocaleDateString("cs-CZ");
|
return d.toLocaleDateString("cs-CZ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Today's date as `YYYY-MM-DD` in LOCAL (Prague) time — use this for
|
||||||
|
* date-input defaults. `new Date().toISOString().slice(0, 10)` gives the UTC
|
||||||
|
* date, which is a day behind the Czech date during the post-midnight window
|
||||||
|
* (Prague is UTC+1/+2), so a "today" default could land on yesterday.
|
||||||
|
*/
|
||||||
|
export function todayLocalStr(): string {
|
||||||
|
const d = new Date();
|
||||||
|
const m = String(d.getMonth() + 1).padStart(2, "0");
|
||||||
|
const day = String(d.getDate()).padStart(2, "0");
|
||||||
|
return `${d.getFullYear()}-${m}-${day}`;
|
||||||
|
}
|
||||||
|
|
||||||
export function formatKm(km: number | string): string {
|
export function formatKm(km: number | string): string {
|
||||||
return new Intl.NumberFormat("cs-CZ").format(Number(km) || 0);
|
return new Intl.NumberFormat("cs-CZ").format(Number(km) || 0);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user