@@ -58,6 +58,8 @@ export default function SettingsPage() {
5858 const [ budgetBillsMode , setBudgetBillsMode ] = useState ( "auto" ) ;
5959 const [ reserveNextMonthSaving , setReserveNextMonthSaving ] = useState ( false ) ;
6060 const [ reserveSaved , setReserveSaved ] = useState ( false ) ;
61+ const [ ynabSyncHour , setYnabSyncHour ] = useState ( "6" ) ;
62+ const [ syncHourSaved , setSyncHourSaved ] = useState ( false ) ;
6163 const [ billsModeSaved , setBillsModeSaved ] = useState ( false ) ;
6264 const [ thresholds , setThresholds ] = useState ( { tight : "20" , normal : "30" , good : "50" } ) ;
6365 const [ thresholdsSaved , setThresholdsSaved ] = useState ( false ) ;
@@ -128,6 +130,9 @@ export default function SettingsPage() {
128130 if ( householdData . settings ?. reserve_next_month_saving !== undefined ) {
129131 setReserveNextMonthSaving ( householdData . settings . reserve_next_month_saving === "1" ) ;
130132 }
133+ if ( householdData . settings ?. ynab_sync_hour !== undefined ) {
134+ setYnabSyncHour ( String ( householdData . settings . ynab_sync_hour ) ) ;
135+ }
131136 if ( householdData . settings ?. budget_threshold_tight ) setThresholds ( ( p ) => ( { ...p , tight : householdData . settings . budget_threshold_tight } ) ) ;
132137 if ( householdData . settings ?. budget_threshold_normal ) setThresholds ( ( p ) => ( { ...p , normal : householdData . settings . budget_threshold_normal } ) ) ;
133138 if ( householdData . settings ?. budget_threshold_good ) setThresholds ( ( p ) => ( { ...p , good : householdData . settings . budget_threshold_good } ) ) ;
@@ -777,6 +782,36 @@ export default function SettingsPage() {
777782 : "Use if your largest paycheck arrives in the last days of the month. Reserves next month's full saving goal on payday so the daily budget doesn't look overly generous. Next month skips the proportional saving deduction since it's already reserved." }
778783 </ p >
779784 </ div >
785+ < div className = "form-field" >
786+ < Label > { locale === "fi" ? "YNAB-synkronoinnin tunti" : "YNAB sync hour" } </ Label >
787+ < div className = "settings-row" >
788+ < Input
789+ type = "number"
790+ min = "0"
791+ max = "23"
792+ value = { ynabSyncHour }
793+ onChange = { ( e ) => setYnabSyncHour ( e . target . value ) }
794+ className = "settings-input"
795+ />
796+ < Button size = "sm" variant = "outline" onClick = { async ( ) => {
797+ const h = String ( Math . min ( 23 , Math . max ( 0 , parseInt ( ynabSyncHour , 10 ) || 6 ) ) ) ;
798+ setYnabSyncHour ( h ) ;
799+ await fetch ( "/api/household" , {
800+ method : "POST" ,
801+ headers : { "Content-Type" : "application/json" } ,
802+ body : JSON . stringify ( { ynab_sync_hour : h } ) ,
803+ } ) ;
804+ setSyncHourSaved ( true ) ;
805+ setTimeout ( ( ) => setSyncHourSaved ( false ) , 2000 ) ;
806+ } } > { t . common . save } </ Button >
807+ { syncHourSaved && < span className = "settings-saved" > { t . common . saved } </ span > }
808+ </ div >
809+ < p className = "settings-help" >
810+ { locale === "fi"
811+ ? "Tunti (0–23, Helsingin aika), jolloin YNAB synkronoidaan automaattisesti kerran päivässä."
812+ : "Hour (0–23, Helsinki time) when YNAB is synced automatically once a day." }
813+ </ p >
814+ </ div >
780815 < div className = "form-field" >
781816 < Label > { locale === "fi" ? "Budjettirajat (€)" : "Budget thresholds (€)" } </ Label >
782817 < div className = "list-edit-row" >
0 commit comments