AccessClientFields.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import { IconX } from "@tabler/icons-react";
  2. import cn from "classnames";
  3. import { useFormikContext } from "formik";
  4. import { useState } from "react";
  5. import type { AccessListClient } from "src/api/backend";
  6. import { intl, T } from "src/locale";
  7. interface Props {
  8. initialValues: AccessListClient[];
  9. name?: string;
  10. }
  11. export function AccessClientFields({ initialValues, name = "clients" }: Props) {
  12. const [values, setValues] = useState<AccessListClient[]>(initialValues || []);
  13. const { setFieldValue } = useFormikContext();
  14. const blankClient: AccessListClient = { directive: "allow", address: "" };
  15. if (values?.length === 0) {
  16. setValues([blankClient]);
  17. }
  18. const handleAdd = () => {
  19. setValues([...values, blankClient]);
  20. };
  21. const handleRemove = (idx: number) => {
  22. const newValues = values.filter((_: AccessListClient, i: number) => i !== idx);
  23. if (newValues.length === 0) {
  24. newValues.push(blankClient);
  25. }
  26. setValues(newValues);
  27. setFormField(newValues);
  28. };
  29. const handleChange = (idx: number, field: string, fieldValue: string) => {
  30. const newValues = values.map((v: AccessListClient, i: number) =>
  31. i === idx ? { ...v, [field]: fieldValue } : v,
  32. );
  33. setValues(newValues);
  34. setFormField(newValues);
  35. };
  36. const setFormField = (newValues: AccessListClient[]) => {
  37. const filtered = newValues.filter((v: AccessListClient) => v?.address?.trim() !== "");
  38. setFieldValue(name, filtered);
  39. };
  40. return (
  41. <>
  42. <p className="text-muted">
  43. <T id="access-list.help.rules-order" />
  44. </p>
  45. {values.map((client: AccessListClient, idx: number) => (
  46. <div className="row mb-1" key={idx}>
  47. <div className="col-11">
  48. <div className="input-group mb-2">
  49. <span className="input-group-select">
  50. <select
  51. className={cn(
  52. "form-select",
  53. "m-0",
  54. client.directive === "allow" ? "bg-lime-lt" : "bg-orange-lt",
  55. )}
  56. name={`clients[${idx}].directive`}
  57. value={client.directive}
  58. onChange={(e) => handleChange(idx, "directive", e.target.value)}
  59. >
  60. <option value="allow"><T id="action.allow" /></option>
  61. <option value="deny"><T id="action.deny" /></option>
  62. </select>
  63. </span>
  64. <input
  65. name={`clients[${idx}].address`}
  66. type="text"
  67. className="form-control"
  68. autoComplete="off"
  69. value={client.address}
  70. onChange={(e) => handleChange(idx, "address", e.target.value)}
  71. placeholder={intl.formatMessage({ id: "access-list.rule-source.placeholder" })}
  72. />
  73. </div>
  74. </div>
  75. <div className="col-1">
  76. <a
  77. role="button"
  78. className="btn btn-ghost btn-danger p-0"
  79. onClick={(e) => {
  80. e.preventDefault();
  81. handleRemove(idx);
  82. }}
  83. >
  84. <IconX size={16} />
  85. </a>
  86. </div>
  87. </div>
  88. ))}
  89. <div className="mb-3">
  90. <button type="button" className="btn btn-sm" onClick={handleAdd}>
  91. <T id="action.add" />
  92. </button>
  93. </div>
  94. <div className="row mb-3">
  95. <p className="text-muted">
  96. <T id="access-list.help-rules-last" />
  97. </p>
  98. <div className="col-11">
  99. <div className="input-group mb-2">
  100. <span className="input-group-select">
  101. <select
  102. className="form-select m-0 bg-orange-lt"
  103. name="clients[last].directive"
  104. value="deny"
  105. disabled
  106. >
  107. <option value="deny"><T id="action.deny" /></option>
  108. </select>
  109. </span>
  110. <input
  111. name="clients[last].address"
  112. type="text"
  113. className="form-control"
  114. autoComplete="off"
  115. value="all"
  116. disabled
  117. />
  118. </div>
  119. </div>
  120. </div>
  121. </>
  122. );
  123. }