Jelajahi Sumber

feat(clients): restore Auto Renew field in client form

The vue→react rewrite dropped the per-client `reset` (Auto Renew)
input. The backend's autoRenewClients job has always honoured it, but
the form had no way to set or change the value, so existing
auto-renew settings were also invisible during edits.

Reinstate the field as an InputNumber with a tooltip explaining
"0 = disable (unit: day)", placed on the same row as the Reverse tag
field so the form doesn't grow taller for the common cases. Wired
through FormState defaults, edit-mode hydration, the submit payload,
and ClientFormSchema validation.
MHSanaei 13 jam lalu
induk
melakukan
313d041db3

+ 38 - 26
frontend/src/pages/clients/ClientFormModal.tsx

@@ -79,6 +79,7 @@ interface FormState {
   expiryDate: Dayjs | null;
   delayedStart: boolean;
   delayedDays: number;
+  reset: number;
   limitIp: number;
   tgId: number;
   comment: string;
@@ -99,6 +100,7 @@ function emptyForm(): FormState {
     expiryDate: null,
     delayedStart: false,
     delayedDays: 0,
+    reset: 0,
     limitIp: 0,
     tgId: 0,
     comment: '',
@@ -157,6 +159,7 @@ export default function ClientFormModal({
         flow: client.flow || '',
         reverseTag: client.reverse?.tag || '',
         totalGB: bytesToGB(client.totalGB || 0),
+        reset: Number(client.reset) || 0,
         limitIp: client.limitIp || 0,
         tgId: Number(client.tgId) || 0,
         comment: client.comment || '',
@@ -280,6 +283,7 @@ export default function ClientFormModal({
       totalGB: form.totalGB,
       delayedStart: form.delayedStart,
       delayedDays: form.delayedDays,
+      reset: form.reset,
       limitIp: form.limitIp,
       tgId: form.tgId,
       comment: form.comment,
@@ -303,6 +307,7 @@ export default function ClientFormModal({
       flow: showFlow ? (form.flow || '') : '',
       totalGB: gbToBytes(form.totalGB),
       expiryTime,
+      reset: Number(form.reset) || 0,
       limitIp: Number(form.limitIp) || 0,
       tgId: Number(form.tgId) || 0,
       comment: form.comment,
@@ -452,32 +457,39 @@ export default function ClientFormModal({
             </Col>
           </Row>
 
-          {(showFlow || showReverseTag) && (
-            <Row gutter={16}>
-              {showFlow && (
-                <Col xs={24} md={12}>
-                  <Form.Item label={t('pages.clients.flow')}>
-                    <Select
-                      value={form.flow}
-                      onChange={(v) => update('flow', v)}
-                      options={[
-                        { value: '', label: t('none') },
-                        ...FLOW_OPTIONS.map((k) => ({ value: k, label: k })),
-                      ]}
-                    />
-                  </Form.Item>
-                </Col>
-              )}
-              {showReverseTag && (
-                <Col xs={24} md={12}>
-                  <Form.Item label={t('pages.clients.reverseTag')}>
-                    <Input value={form.reverseTag} placeholder={t('pages.clients.reverseTagPlaceholder')}
-                      onChange={(e) => update('reverseTag', e.target.value)} />
-                  </Form.Item>
-                </Col>
-              )}
-            </Row>
-          )}
+          <Row gutter={16}>
+            <Col xs={24} md={12}>
+              <Form.Item
+                label={t('pages.clients.renew')}
+                tooltip={t('pages.clients.renewDesc')}
+              >
+                <InputNumber value={form.reset} min={0} style={{ width: '100%' }}
+                  onChange={(v) => update('reset', Number(v) || 0)} />
+              </Form.Item>
+            </Col>
+            {showReverseTag && (
+              <Col xs={24} md={12}>
+                <Form.Item label={t('pages.clients.reverseTag')}>
+                  <Input value={form.reverseTag} placeholder={t('pages.clients.reverseTagPlaceholder')}
+                    onChange={(e) => update('reverseTag', e.target.value)} />
+                </Form.Item>
+              </Col>
+            )}
+            {showFlow && (
+              <Col xs={24} md={12}>
+                <Form.Item label={t('pages.clients.flow')}>
+                  <Select
+                    value={form.flow}
+                    onChange={(v) => update('flow', v)}
+                    options={[
+                      { value: '', label: t('none') },
+                      ...FLOW_OPTIONS.map((k) => ({ value: k, label: k })),
+                    ]}
+                  />
+                </Form.Item>
+              </Col>
+            )}
+          </Row>
 
           <Row gutter={16}>
             {tgBotEnable && (

+ 1 - 0
frontend/src/schemas/client.ts

@@ -108,6 +108,7 @@ export const ClientFormSchema = z.object({
   totalGB: z.number().min(0),
   delayedStart: z.boolean(),
   delayedDays: z.number().int().min(0),
+  reset: z.number().int().min(0),
   limitIp: z.number().int().min(0),
   tgId: z.number().int().min(0),
   comment: z.string(),