SettingsDomain.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import { useFormState } from "react-use-form-state";
  2. import { Flex } from "reflexbox/styled-components";
  3. import React, { FC, useState } from "react";
  4. import styled from "styled-components";
  5. import getConfig from "next/config";
  6. import { useStoreState, useStoreActions } from "../../store";
  7. import { Domain } from "../../store/settings";
  8. import { errorMessage } from "../../utils";
  9. import { useMessage } from "../../hooks";
  10. import Text, { H2, Span } from "../Text";
  11. import { Colors } from "../../consts";
  12. import { TextInput } from "../Input";
  13. import { Button } from "../Button";
  14. import { Col } from "../Layout";
  15. import Table from "../Table";
  16. import Modal from "../Modal";
  17. import Icon from "../Icon";
  18. const { publicRuntimeConfig } = getConfig();
  19. const Th = styled(Flex).attrs({ as: "th", py: 3, px: 3 })`
  20. font-size: 15px;
  21. `;
  22. const Td = styled(Flex).attrs({ as: "td", py: 12, px: 3 })`
  23. font-size: 15px;
  24. `;
  25. const SettingsDomain: FC = () => {
  26. const { saveDomain, deleteDomain } = useStoreActions(s => s.settings);
  27. const [domainToDelete, setDomainToDelete] = useState<Domain>(null);
  28. const [deleteLoading, setDeleteLoading] = useState(false);
  29. const domains = useStoreState(s => s.settings.domains);
  30. const [message, setMessage] = useMessage(2000);
  31. const [loading, setLoading] = useState(false);
  32. const [modal, setModal] = useState(false);
  33. const [formState, { label, text }] = useFormState<{
  34. address: string;
  35. homepage: string;
  36. }>(null, { withIds: true });
  37. const onSubmit = async e => {
  38. e.preventDefault();
  39. setLoading(true);
  40. try {
  41. await saveDomain(formState.values);
  42. } catch (err) {
  43. setMessage(err?.response?.data?.error || "Couldn't add domain.");
  44. }
  45. formState.clear();
  46. setLoading(false);
  47. };
  48. const closeModal = () => {
  49. setDomainToDelete(null);
  50. setModal(false);
  51. };
  52. const onDelete = async () => {
  53. setDeleteLoading(true);
  54. await deleteDomain(domainToDelete.id).catch(err =>
  55. setMessage(errorMessage(err, "Couldn't delete the domain."))
  56. );
  57. setMessage("Domain has been deleted successfully.", "green");
  58. closeModal();
  59. setDeleteLoading(false);
  60. };
  61. return (
  62. <Col alignItems="flex-start" maxWidth="100%">
  63. <H2 mb={4} bold>
  64. Custom domain
  65. </H2>
  66. <Text mb={3}>
  67. You can set a custom domain for your short URLs, so instead of{" "}
  68. <b>{publicRuntimeConfig.DEFAULT_DOMAIN}/shorturl</b> you can have{" "}
  69. <b>example.com/shorturl.</b>
  70. </Text>
  71. <Text mb={4}>
  72. Point your domain A record to <b>192.64.116.170</b> then add the domain
  73. via form below:
  74. </Text>
  75. {domains.length > 0 && (
  76. <Table my={3} scrollWidth="550px">
  77. <thead>
  78. <tr>
  79. <Th width={2 / 5}>Domain</Th>
  80. <Th width={2 / 5}>Homepage</Th>
  81. <Th width={1 / 5}></Th>
  82. </tr>
  83. </thead>
  84. <tbody>
  85. {domains.map(d => (
  86. <tr key={d.address}>
  87. <Td width={2 / 5}>{d.address}</Td>
  88. <Td width={2 / 5}>
  89. {d.homepage || publicRuntimeConfig.DEFAULT_DOMAIN}
  90. </Td>
  91. <Td width={1 / 5} justifyContent="center">
  92. <Icon
  93. as="button"
  94. name="trash"
  95. stroke={Colors.TrashIcon}
  96. strokeWidth="2.5"
  97. backgroundColor={Colors.TrashIconBg}
  98. py={0}
  99. px={0}
  100. size={[23, 24]}
  101. p={["4px", "5px"]}
  102. onClick={() => {
  103. setDomainToDelete(d);
  104. setModal(true);
  105. }}
  106. />
  107. </Td>
  108. </tr>
  109. ))}
  110. </tbody>
  111. </Table>
  112. )}
  113. <Col
  114. alignItems="flex-start"
  115. onSubmit={onSubmit}
  116. width={1}
  117. as="form"
  118. my={[3, 4]}
  119. >
  120. <Flex width={1} flexDirection={["column", "row"]}>
  121. <Col mr={[0, 2]} mb={[3, 0]} flex="0 0 auto">
  122. <Text
  123. {...label("address")}
  124. as="label"
  125. mb={[2, 3]}
  126. fontSize={[15, 16]}
  127. bold
  128. >
  129. Domain:
  130. </Text>
  131. <TextInput
  132. {...text("address")}
  133. placeholder="example.com"
  134. maxWidth="240px"
  135. required
  136. />
  137. </Col>
  138. <Col ml={[0, 2]} flex="0 0 auto">
  139. <Text
  140. {...label("homepage")}
  141. as="label"
  142. mb={[2, 3]}
  143. fontSize={[15, 16]}
  144. bold
  145. >
  146. Homepage (optional):
  147. </Text>
  148. <TextInput
  149. {...text("homepage")}
  150. placeholder="Homepage URL"
  151. flex="1 1 auto"
  152. maxWidth="240px"
  153. />
  154. </Col>
  155. </Flex>
  156. <Button type="submit" color="purple" mt={[24, 3]} disabled={loading}>
  157. <Icon name={loading ? "spinner" : "plus"} mr={2} stroke="white" />
  158. {loading ? "Setting..." : "Set domain"}
  159. </Button>
  160. </Col>
  161. <Text color={message.color}>{message.text}</Text>
  162. <Modal id="delete-custom-domain" show={modal} closeHandler={closeModal}>
  163. <H2 mb={24} textAlign="center" bold>
  164. Delete domain?
  165. </H2>
  166. <Text textAlign="center">
  167. Are you sure do you want to delete the domain{" "}
  168. <Span bold>"{domainToDelete && domainToDelete.address}"</Span>?
  169. </Text>
  170. <Flex justifyContent="center" mt={44}>
  171. {deleteLoading ? (
  172. <>
  173. <Icon name="spinner" size={20} stroke={Colors.Spinner} />
  174. </>
  175. ) : (
  176. <>
  177. <Button color="gray" mr={3} onClick={closeModal}>
  178. Cancel
  179. </Button>
  180. <Button color="red" ml={3} onClick={onDelete}>
  181. <Icon name="trash" stroke="white" mr={2} />
  182. Delete
  183. </Button>
  184. </>
  185. )}
  186. </Flex>
  187. </Modal>
  188. </Col>
  189. );
  190. };
  191. export default SettingsDomain;