feat: add Auto Check MH Payment toggle with weekly schedule
Adds a toggle behind the Go button on the Payments page to automatically run the MH batch payment check on a user-selected day of week and hour. Default is off. - Schema: added autoMhCheckEnabled, autoMhCheckDayOfWeek, autoMhCheckHour to User model - Backend: new mhBatchPaymentService (shared logic), GET/PUT /auto-mh-check-setting routes, hourly cron job that fires on matching day+hour - Frontend: toggle + day select (Mon–Sun) + time select (hourly) that persist immediately to DB Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,8 @@ import {
|
||||
CardDescription,
|
||||
} from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { DollarSign, CalendarIcon } from "lucide-react";
|
||||
import {
|
||||
Select,
|
||||
@@ -31,6 +33,21 @@ import { apiRequest } from "@/lib/queryClient";
|
||||
import { toast } from "@/hooks/use-toast";
|
||||
import PaymentEditModal from "@/components/payments/payment-edit-modal";
|
||||
|
||||
const DAYS_OF_WEEK = [
|
||||
{ label: "Sunday", value: 0 },
|
||||
{ label: "Monday", value: 1 },
|
||||
{ label: "Tuesday", value: 2 },
|
||||
{ label: "Wednesday", value: 3 },
|
||||
{ label: "Thursday", value: 4 },
|
||||
{ label: "Friday", value: 5 },
|
||||
{ label: "Saturday", value: 6 },
|
||||
];
|
||||
|
||||
const HOURS = Array.from({ length: 24 }, (_, i) => ({
|
||||
label: i === 0 ? "12:00 AM" : i < 12 ? `${i}:00 AM` : i === 12 ? "12:00 PM" : `${i - 12}:00 PM`,
|
||||
value: i,
|
||||
}));
|
||||
|
||||
function formatDateInput(raw: string): string {
|
||||
const digits = raw.replace(/\D/g, "").slice(0, 8);
|
||||
if (digits.length <= 2) return digits;
|
||||
@@ -41,6 +58,12 @@ function formatDateInput(raw: string): string {
|
||||
export default function PaymentsPage() {
|
||||
const [paymentPeriod, setPaymentPeriod] = useState<string>("all-time");
|
||||
|
||||
// Auto MH check schedule
|
||||
const [autoMhCheckEnabled, setAutoMhCheckEnabled] = useState(false);
|
||||
const [autoMhCheckDay, setAutoMhCheckDay] = useState(1);
|
||||
const [autoMhCheckHour, setAutoMhCheckHour] = useState(13);
|
||||
const [autoMhCheckLoaded, setAutoMhCheckLoaded] = useState(false);
|
||||
|
||||
// Check Payments Online date range
|
||||
const [mhFromDate, setMhFromDate] = useState<Date | undefined>(undefined);
|
||||
const [mhToDate, setMhToDate] = useState<Date | undefined>(undefined);
|
||||
@@ -147,6 +170,41 @@ export default function PaymentsPage() {
|
||||
clearUrlParams(["paymentId", "patientId"]);
|
||||
}, [location]);
|
||||
|
||||
// Load auto MH check setting on mount
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const res = await apiRequest("GET", "/api/database-management/auto-mh-check-setting");
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
setAutoMhCheckEnabled(data.autoMhCheckEnabled ?? false);
|
||||
setAutoMhCheckDay(data.autoMhCheckDayOfWeek ?? 1);
|
||||
setAutoMhCheckHour(data.autoMhCheckHour ?? 13);
|
||||
}
|
||||
} catch {}
|
||||
setAutoMhCheckLoaded(true);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const saveAutoMhCheckSetting = async (
|
||||
enabled: boolean,
|
||||
day: number,
|
||||
hour: number
|
||||
) => {
|
||||
try {
|
||||
const res = await apiRequest("PUT", "/api/database-management/auto-mh-check-setting", {
|
||||
autoMhCheckEnabled: enabled,
|
||||
autoMhCheckDayOfWeek: day,
|
||||
autoMhCheckHour: hour,
|
||||
});
|
||||
if (!res.ok) {
|
||||
toast({ title: "Failed to save auto MH check setting", variant: "destructive" });
|
||||
}
|
||||
} catch {
|
||||
toast({ title: "Failed to save auto MH check setting", variant: "destructive" });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Header */}
|
||||
@@ -358,6 +416,69 @@ export default function PaymentsPage() {
|
||||
>
|
||||
Go
|
||||
</Button>
|
||||
|
||||
{/* Auto check MH payment toggle */}
|
||||
{autoMhCheckLoaded && (
|
||||
<div className="flex flex-wrap items-center gap-3 ml-2 pl-4 border-l border-gray-200">
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch
|
||||
id="auto-mh-check"
|
||||
checked={autoMhCheckEnabled}
|
||||
onCheckedChange={(checked) => {
|
||||
setAutoMhCheckEnabled(checked);
|
||||
saveAutoMhCheckSetting(checked, autoMhCheckDay, autoMhCheckHour);
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor="auto-mh-check" className="text-sm font-medium whitespace-nowrap cursor-pointer">
|
||||
Auto Check MH Payment
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
{autoMhCheckEnabled && (
|
||||
<>
|
||||
<Select
|
||||
value={String(autoMhCheckDay)}
|
||||
onValueChange={(v) => {
|
||||
const day = Number(v);
|
||||
setAutoMhCheckDay(day);
|
||||
saveAutoMhCheckSetting(autoMhCheckEnabled, day, autoMhCheckHour);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-[140px]">
|
||||
<SelectValue placeholder="Day" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{DAYS_OF_WEEK.map((d) => (
|
||||
<SelectItem key={d.value} value={String(d.value)}>
|
||||
{d.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<Select
|
||||
value={String(autoMhCheckHour)}
|
||||
onValueChange={(v) => {
|
||||
const hour = Number(v);
|
||||
setAutoMhCheckHour(hour);
|
||||
saveAutoMhCheckSetting(autoMhCheckEnabled, autoMhCheckDay, hour);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-[130px]">
|
||||
<SelectValue placeholder="Time" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{HOURS.map((h) => (
|
||||
<SelectItem key={h.value} value={String(h.value)}>
|
||||
{h.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user