BoardForm.jsx 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. import React from "react";
  2. import { useTranslation } from "react-i18next";
  3. import { nanoid } from "nanoid";
  4. import { Field } from "react-final-form";
  5. import { useBoardConfig } from "react-sync-board";
  6. import Hint from "../../ui/formUtils/Hint";
  7. import Label from "../../ui/formUtils/Label";
  8. import SliderRange from "../../ui/SliderRange";
  9. import { ImageField } from "../../mediaLibrary";
  10. import { backgrounds } from "../../gameComponents";
  11. const BoardConfigForm = () => {
  12. const { t } = useTranslation();
  13. const [boardConfig, setBoardConfig] = useBoardConfig();
  14. const [defaultPlayerCount] = React.useState([]);
  15. const addTranslation = React.useCallback(() => {
  16. setBoardConfig((prev) => ({
  17. ...prev,
  18. translations: [...(prev.translations || []), { id: nanoid() }],
  19. }));
  20. }, [setBoardConfig]);
  21. const removeTranslation = (idToRemove) => {
  22. setBoardConfig((prev) => ({
  23. ...prev,
  24. translations: prev.translations.filter(({ id }) => id !== idToRemove),
  25. }));
  26. };
  27. const CurrentBgForm = backgrounds.find(
  28. ({ type }) => type === (boardConfig.bgType || "default")
  29. )?.form;
  30. return (
  31. <>
  32. <Label>
  33. {t("Publish")}
  34. <Field
  35. name="published"
  36. component="input"
  37. type="checkbox"
  38. initialValue={boardConfig.published}
  39. />
  40. <Hint>{t("Check it to make your board publicly visible")}</Hint>
  41. </Label>
  42. <fieldset style={{ marginBottom: "2em", paddingBottom: "1em" }}>
  43. <legend>{t("Background")}</legend>
  44. <Label>{t("Type")}</Label>
  45. <Field
  46. name="bgType"
  47. component="select"
  48. initialValue={boardConfig.bgType || "default"}
  49. >
  50. {backgrounds.map((bg) => {
  51. return (
  52. <option key={bg.type} value={bg.type}>
  53. {bg.name}
  54. </option>
  55. );
  56. })}
  57. </Field>
  58. <div style={{ paddingTop: "1em" }}>
  59. {CurrentBgForm && (
  60. <Field name="bgConf" initialValue={boardConfig.bgConf}>
  61. {({ input: { onChange, value } }) => {
  62. return <CurrentBgForm value={value} onChange={onChange} />;
  63. }}
  64. </Field>
  65. )}
  66. </div>
  67. </fieldset>
  68. <Label>
  69. {t("Number of players")}
  70. <Field
  71. name="playerCount"
  72. initialValue={boardConfig.playerCount || defaultPlayerCount}
  73. >
  74. {({ input: { onChange, value } }) => {
  75. return (
  76. <SliderRange
  77. defaultValue={[2, 4]}
  78. value={value}
  79. min={1}
  80. max={9}
  81. step={1}
  82. onChange={onChange}
  83. />
  84. );
  85. }}
  86. </Field>
  87. </Label>
  88. <Label>
  89. {t("Duration (mins)")}
  90. <Field
  91. name="duration"
  92. initialValue={
  93. Array.isArray(boardConfig.duration)
  94. ? boardConfig.duration
  95. : defaultPlayerCount
  96. }
  97. >
  98. {({ input: { onChange, value } }) => {
  99. return (
  100. <SliderRange
  101. defaultValue={[15, 90]}
  102. value={value}
  103. min={15}
  104. max={90}
  105. step={15}
  106. onChange={onChange}
  107. />
  108. );
  109. }}
  110. </Field>
  111. </Label>
  112. <Label>
  113. {t("Minimal age (years)")}
  114. <Field
  115. name="minAge"
  116. component="input"
  117. initialValue={boardConfig.minAge}
  118. style={{ width: "5em", textAlign: "right" }}
  119. />
  120. </Label>
  121. <Label>
  122. {t("Magnetic Grid size")}
  123. <Field
  124. name="gridSize"
  125. component="input"
  126. initialValue={boardConfig.gridSize || 1}
  127. style={{ width: "5em", textAlign: "right" }}
  128. />
  129. </Label>
  130. <Label>
  131. {t("Main image")}
  132. <Field name="imageUrl" initialValue={boardConfig.imageUrl}>
  133. {({ input: { value, onChange } }) => {
  134. return <ImageField value={value} onChange={onChange} />;
  135. }}
  136. </Field>
  137. </Label>
  138. <Label>
  139. {t("Material language")}
  140. <Field
  141. name="materialLanguage"
  142. component="select"
  143. initialValue={boardConfig.materialLanguage}
  144. style={{ width: "10em" }}
  145. >
  146. <option />
  147. <option value="Multi-lang">🌍 {t("Multi-lang")}</option>
  148. <option value="it">🇮🇹 {t("Italian")}</option>
  149. <option value="en">🇬🇧 {t("English")}</option>
  150. <option value="fr">🇫🇷 {t("French")}</option>
  151. </Field>
  152. </Label>
  153. <fieldset style={{ marginBottom: "2em", paddingBottom: "1em" }}>
  154. <legend>{t("Informations")}</legend>
  155. <Label>
  156. {t("Default language")}
  157. <Field
  158. name="defaultLanguage"
  159. component="select"
  160. initialValue={boardConfig.defaultLanguage}
  161. style={{ width: "15em" }}
  162. >
  163. <option />
  164. <option value="it">🇮🇹 {t("Italian")}</option>
  165. <option value="en">🇬🇧 {t("English")}</option>
  166. <option value="fr">🇫🇷 {t("French")}</option>
  167. </Field>
  168. </Label>
  169. <Label>
  170. {t("Game name")}
  171. <Field
  172. name="defaultName"
  173. component="input"
  174. initialValue={boardConfig.defaultName || boardConfig.name}
  175. style={{ width: "15em" }}
  176. />
  177. </Label>
  178. <Label>
  179. {t("Keep title")}
  180. <Field
  181. name="keepTitle"
  182. component="input"
  183. type="checkbox"
  184. initialValue={boardConfig.keepTitle}
  185. />
  186. <Hint>
  187. {t("Check it to keep the game title above the game image.")}
  188. </Hint>
  189. </Label>
  190. <Label>
  191. {t("Baseline")}
  192. <Field
  193. name="defaultBaseline"
  194. component="input"
  195. initialValue={boardConfig.defaultBaseline}
  196. style={{ width: "100%" }}
  197. />
  198. </Label>
  199. <Label>
  200. {t("Description")}
  201. <Field
  202. name="defaultDescription"
  203. component="textarea"
  204. initialValue={boardConfig.defaultDescription || boardConfig.info}
  205. style={{ minHeight: "10em" }}
  206. />
  207. </Label>
  208. </fieldset>
  209. <div>
  210. {(boardConfig.translations || []).map(({ id }, index) => {
  211. return (
  212. <fieldset
  213. style={{ marginBottom: "2em", paddingBottom: "1em" }}
  214. key={id}
  215. >
  216. <legend>
  217. {t("Translation")} {index}
  218. </legend>
  219. <button
  220. className="button clear icon-only trash"
  221. onClick={() => removeTranslation(id)}
  222. >
  223. <img
  224. src="https://icongr.am/feather/trash.svg?size=25&color=ffffff"
  225. alt={t("Remove")}
  226. />
  227. </button>
  228. <Label>
  229. {t("Language")}
  230. <Field
  231. name={`translations[${index}].language`}
  232. component="select"
  233. initialValue={boardConfig.translations[index].language}
  234. style={{ width: "15em" }}
  235. >
  236. <option />
  237. <option value="it">🇮🇹 {t("Italian")}</option>
  238. <option value="en">🇬🇧 {t("English")}</option>
  239. <option value="fr">🇫🇷 {t("French")}</option>
  240. </Field>
  241. </Label>
  242. <Label>
  243. {t("Game name")}
  244. <Field
  245. name={`translations[${index}].name`}
  246. component="input"
  247. initialValue={boardConfig.translations[index].name}
  248. style={{ width: "15em" }}
  249. />
  250. </Label>
  251. <Label>
  252. {t("Baseline")}
  253. <Field
  254. name={`translations[${index}].baseline`}
  255. component="input"
  256. initialValue={boardConfig.translations[index].baseline}
  257. style={{ width: "100%" }}
  258. />
  259. </Label>
  260. <Label>
  261. {t("Description")}
  262. <Field
  263. name={`translations[${index}].description`}
  264. component="textarea"
  265. initialValue={boardConfig.translations[index].description}
  266. style={{ minHeight: "10em" }}
  267. />
  268. </Label>
  269. </fieldset>
  270. );
  271. })}
  272. <button onClick={addTranslation}>{t("Add translation")}</button>
  273. </div>
  274. </>
  275. );
  276. };
  277. export default BoardConfigForm;