SettingsDomain.tsx 6.0 KB

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