diff --git a/frontend/package.json b/frontend/package.json index fcea324..d5a5a4b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,13 +9,16 @@ }, "dependencies": { "@babel/core": ">=7.0.0 <8.0.0", + "@headlessui/react": "^1.6.3", "@heroicons/react": "^1.0.6", "clsx": "^1.1.1", "react": "^18.0.0", "react-dom": "^18.0.0", + "react-query": "^3.39.0", "react-router-dom": "6" }, "devDependencies": { + "@faker-js/faker": "^7.1.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@vitejs/plugin-react": "^1.3.0", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 2362bfa..764f7f3 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -2,6 +2,8 @@ lockfileVersion: 5.4 specifiers: '@babel/core': '>=7.0.0 <8.0.0' + '@faker-js/faker': ^7.1.0 + '@headlessui/react': ^1.6.3 '@heroicons/react': ^1.0.6 '@types/react': ^18.0.0 '@types/react-dom': ^18.0.0 @@ -11,6 +13,7 @@ specifiers: postcss: ^8.4.14 react: ^18.0.0 react-dom: ^18.0.0 + react-query: ^3.39.0 react-router-dom: '6' tailwindcss: ^3.0.24 typescript: ^4.6.3 @@ -18,13 +21,16 @@ specifiers: dependencies: '@babel/core': 7.17.10 + '@headlessui/react': 1.6.3_ef5jwxihqo6n7gxfmzogljlgcm '@heroicons/react': 1.0.6_react@18.1.0 clsx: 1.1.1 react: 18.1.0 react-dom: 18.1.0_react@18.1.0 + react-query: 3.39.0_ef5jwxihqo6n7gxfmzogljlgcm react-router-dom: 6.3.0_ef5jwxihqo6n7gxfmzogljlgcm devDependencies: + '@faker-js/faker': 7.1.0 '@types/react': 18.0.9 '@types/react-dom': 18.0.4 '@vitejs/plugin-react': 1.3.2 @@ -283,6 +289,22 @@ packages: '@babel/helper-validator-identifier': 7.16.7 to-fast-properties: 2.0.0 + /@faker-js/faker/7.1.0: + resolution: {integrity: sha512-G+EvE29QUd9/6GTrwA/TK2AiN79W4ZG6kyJqj2RAqUqEd8A8ICnjA3Rj3F2IaaA+sq6WJzs4lh8GJJRDG1UH7A==} + engines: {node: '>=14.0.0', npm: '>=6.0.0'} + dev: true + + /@headlessui/react/1.6.3_ef5jwxihqo6n7gxfmzogljlgcm: + resolution: {integrity: sha512-WNu/ypGzl0JmJ+sD34KtdycEu2n7EZjKFx2rq6fivsszPdoEyOVZ/GYQMJ437dfAJI0/ZxoRYfrOVduZHjlokQ==} + engines: {node: '>=10'} + peerDependencies: + react: ^16 || ^17 || ^18 + react-dom: ^16 || ^17 || ^18 + dependencies: + react: 18.1.0 + react-dom: 18.1.0_react@18.1.0 + dev: false + /@heroicons/react/1.0.6_react@18.1.0: resolution: {integrity: sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ==} peerDependencies: @@ -435,11 +457,27 @@ packages: postcss-value-parser: 4.2.0 dev: true + /balanced-match/1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: false + + /big-integer/1.6.51: + resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} + engines: {node: '>=0.6'} + dev: false + /binary-extensions/2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} dev: true + /brace-expansion/1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: false + /braces/3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} @@ -447,6 +485,19 @@ packages: fill-range: 7.0.1 dev: true + /broadcast-channel/3.7.0: + resolution: {integrity: sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==} + dependencies: + '@babel/runtime': 7.18.0 + detect-node: 2.1.0 + js-sha3: 0.8.0 + microseconds: 0.2.0 + nano-time: 1.0.0 + oblivious-set: 1.0.0 + rimraf: 3.0.2 + unload: 2.2.0 + dev: false + /browserslist/4.20.3: resolution: {integrity: sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -506,6 +557,10 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true + /concat-map/0.0.1: + resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} + dev: false + /convert-source-map/1.8.0: resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} dependencies: @@ -536,6 +591,10 @@ packages: resolution: {integrity: sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=} dev: true + /detect-node/2.1.0: + resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + dev: false + /detective/5.2.0: resolution: {integrity: sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==} engines: {node: '>=0.8.0'} @@ -805,6 +864,10 @@ packages: resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} dev: true + /fs.realpath/1.0.0: + resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=} + dev: false + /fsevents/2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -835,6 +898,17 @@ packages: is-glob: 4.0.3 dev: true + /glob/7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: false + /globals/11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -856,6 +930,17 @@ packages: '@babel/runtime': 7.18.0 dev: false + /inflight/1.0.6: + resolution: {integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: false + + /inherits/2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: false + /is-binary-path/2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -886,6 +971,10 @@ packages: engines: {node: '>=0.12.0'} dev: true + /js-sha3/0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} + dev: false + /js-tokens/4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -911,6 +1000,13 @@ packages: js-tokens: 4.0.0 dev: false + /match-sorter/6.3.1: + resolution: {integrity: sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==} + dependencies: + '@babel/runtime': 7.18.0 + remove-accents: 0.4.2 + dev: false + /merge2/1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -924,6 +1020,16 @@ packages: picomatch: 2.3.1 dev: true + /microseconds/0.2.0: + resolution: {integrity: sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==} + dev: false + + /minimatch/3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: false + /minimist/1.2.6: resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} dev: true @@ -931,6 +1037,12 @@ packages: /ms/2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + /nano-time/1.0.0: + resolution: {integrity: sha1-sFVPaa2J4i0JB/ehKwmTpdlhN+8=} + dependencies: + big-integer: 1.6.51 + dev: false + /nanoid/3.3.4: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -955,6 +1067,21 @@ packages: engines: {node: '>= 6'} dev: true + /oblivious-set/1.0.0: + resolution: {integrity: sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==} + dev: false + + /once/1.4.0: + resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=} + dependencies: + wrappy: 1.0.2 + dev: false + + /path-is-absolute/1.0.1: + resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=} + engines: {node: '>=0.10.0'} + dev: false + /path-parse/1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true @@ -1044,6 +1171,25 @@ packages: scheduler: 0.22.0 dev: false + /react-query/3.39.0_ef5jwxihqo6n7gxfmzogljlgcm: + resolution: {integrity: sha512-Od0IkSuS79WJOhzWBx/ys0x13+7wFqgnn64vBqqAAnZ9whocVhl/y1padD5uuZ6EIkXbFbInax0qvY7zGM0thA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: '*' + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + dependencies: + '@babel/runtime': 7.18.0 + broadcast-channel: 3.7.0 + match-sorter: 6.3.1 + react: 18.1.0 + react-dom: 18.1.0_react@18.1.0 + dev: false + /react-refresh/0.13.0: resolution: {integrity: sha512-XP8A9BT0CpRBD+NYLLeIhld/RqG9+gktUjW1FkE+Vm7OCinbG1SshcK5tb9ls4kzvjZr9mOQc7HYgBngEyPAXg==} engines: {node: '>=0.10.0'} @@ -1088,6 +1234,10 @@ packages: resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} dev: false + /remove-accents/0.4.2: + resolution: {integrity: sha1-CkPTqq4egNuRngeuJUsoXZ4ce7U=} + dev: false + /resolve/1.22.0: resolution: {integrity: sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==} hasBin: true @@ -1102,6 +1252,13 @@ packages: engines: {iojs: '>=1.0.0', node: '>=0.10.0'} dev: true + /rimraf/3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: false + /rollup/2.72.1: resolution: {integrity: sha512-NTc5UGy/NWFGpSqF1lFY8z9Adri6uhyMLI6LvPAXdBKoPRFhIIiBUpt+Qg2awixqO3xvzSijjhnb4+QEZwJmxA==} engines: {node: '>=10.0.0'} @@ -1192,6 +1349,13 @@ packages: hasBin: true dev: true + /unload/2.2.0: + resolution: {integrity: sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==} + dependencies: + '@babel/runtime': 7.18.0 + detect-node: 2.1.0 + dev: false + /util-deprecate/1.0.2: resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=} dev: true @@ -1220,6 +1384,10 @@ packages: fsevents: 2.3.2 dev: true + /wrappy/1.0.2: + resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=} + dev: false + /xtend/4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} diff --git a/frontend/src/components/atoms/Button.tsx b/frontend/src/components/atoms/Button.tsx index be86d64..99f2e57 100644 --- a/frontend/src/components/atoms/Button.tsx +++ b/frontend/src/components/atoms/Button.tsx @@ -1,10 +1,33 @@ -import { FC, HTMLProps } from "react"; +import clsx from "clsx"; +import { FC, MouseEventHandler, ReactNode } from "react"; +import { InputSize } from "../../types"; -const Button: FC> = (props) => { +interface InputProps { + onClick?: MouseEventHandler | undefined; + className?: string; + children?: ReactNode; + size?: InputSize; +} + +const getButtonSize = (size?: InputSize) => { + switch (size) { + case "md": + return "px-[1rem] py-[.5rem] text-sm"; + default: + return "px-10 py-4 text-base"; + } +}; + +const Button: FC = (props) => { + const btnClassName = getButtonSize(props.size); return ( diff --git a/frontend/src/components/atoms/InlineLink.tsx b/frontend/src/components/atoms/InlineLink.tsx new file mode 100644 index 0000000..2e3be27 --- /dev/null +++ b/frontend/src/components/atoms/InlineLink.tsx @@ -0,0 +1,11 @@ +import { FC, HTMLProps } from "react"; + +const InlineLink: FC> = (props) => { + return ( + + {props.children} + + ); +}; + +export default InlineLink; diff --git a/frontend/src/components/atoms/Input.tsx b/frontend/src/components/atoms/Input.tsx index 6fdca12..3d6d9c6 100644 --- a/frontend/src/components/atoms/Input.tsx +++ b/frontend/src/components/atoms/Input.tsx @@ -1,14 +1,44 @@ -import { FC, HTMLProps } from "react"; +import clsx from "clsx"; +import { FC } from "react"; +import { InputSize } from "../../types"; -const Input: FC> = (props) => { +interface InputProps { + id?: string; + type?: string; + className?: string; + placeholder?: string; + required?: boolean; + name?: string; + size?: InputSize; + value?: string; + onInput?: React.FormEventHandler; +} + +const getInputSize = (size?: InputSize) => { + switch (size) { + case "md": + return "px-[1rem] py-[.5rem] text-sm"; + default: + return "px-5 py-3 text-base"; + } +}; + +const Input: FC = (props) => { + const sizeClassNames = getInputSize(props.size); return ( ); }; diff --git a/frontend/src/components/atoms/InputLabel.tsx b/frontend/src/components/atoms/InputLabel.tsx index 45d9f3f..a0395a8 100644 --- a/frontend/src/components/atoms/InputLabel.tsx +++ b/frontend/src/components/atoms/InputLabel.tsx @@ -1,12 +1,17 @@ import { FC, HTMLProps } from "react"; -const InputLabel: FC> = (props) => { +interface InputLabelProps extends HTMLProps { + required?: boolean; +} + +const InputLabel: FC = (props) => { return ( ); }; diff --git a/frontend/src/components/layouts/Container.tsx b/frontend/src/components/layouts/Container.tsx new file mode 100644 index 0000000..1e25d59 --- /dev/null +++ b/frontend/src/components/layouts/Container.tsx @@ -0,0 +1,7 @@ +import { FC, HTMLProps } from "react"; + +const Container: FC> = (props) => { + return
{props.children}
; +}; + +export default Container; diff --git a/frontend/src/components/molecules/Sidebar.tsx b/frontend/src/components/molecules/Sidebar.tsx index e4ac10c..f5956dd 100644 --- a/frontend/src/components/molecules/Sidebar.tsx +++ b/frontend/src/components/molecules/Sidebar.tsx @@ -7,6 +7,7 @@ import { } from "@heroicons/react/outline"; import { FC, ReactNode } from "react"; import { useNavigate } from "react-router-dom"; +import useServices from "../../hooks/useServices"; import Badge from "../atoms/Badge"; import InputLabel from "../atoms/InputLabel"; @@ -70,7 +71,7 @@ const Sidebar = () => {
  • 0} + badge={12} onClick={navFactory("/services")} > diff --git a/frontend/src/components/molecules/TextField.tsx b/frontend/src/components/molecules/TextField.tsx index 6f82efc..2535830 100644 --- a/frontend/src/components/molecules/TextField.tsx +++ b/frontend/src/components/molecules/TextField.tsx @@ -1,17 +1,34 @@ -import { FC, HTMLProps } from "react"; +import { FC } from "react"; +import { InputSize } from "../../types"; import Input from "../atoms/Input"; import InputLabel from "../atoms/InputLabel"; -const TextField: FC> = (props) => { +interface TextFieldProps { + id?: string; + type?: string; + className?: string; + placeholder?: string; + required?: boolean; + name?: string; + size?: InputSize; + label?: string; + inputClassName?: string; +} + +const TextField: FC = (props) => { return ( -
    - {props.label} +
    + + {props.label} +
    diff --git a/frontend/src/components/pages/services/index.tsx b/frontend/src/components/pages/services/index.tsx index 2ccc901..18d886f 100644 --- a/frontend/src/components/pages/services/index.tsx +++ b/frontend/src/components/pages/services/index.tsx @@ -1,9 +1,104 @@ +import { PlusIcon } from "@heroicons/react/outline"; +import clsx from "clsx"; +import { useState } from "react"; +import useServices from "../../../hooks/useServices"; +import Button from "../../atoms/Button"; +import InlineLink from "../../atoms/InlineLink"; +import Container from "../../layouts/Container"; import DashboardLayout from "../../layouts/Dashboard"; +import TextField from "../../molecules/TextField"; const ServicesPage = () => { + const [toggleCreate, setToggleCreate] = useState(false); + const services = useServices(); + + const handleToggleCreate = () => { + setToggleCreate(!toggleCreate); + }; + return ( -
    Services
    + +

    Services

    +
    + + +
    + {toggleCreate && ( +
    +

    Create a new service

    +
    + + +
    + +
    +
    +
    + )} +
    + + + + + + + + + + + {services.data && + services.data.map((service) => ( + + + + + + + ))} + +
    NameDestinationReferenced by{/* Delete */}
    {service.name} + + {service.destination[0]} + + + + {service.references} + + Delete
    +
    +
    ); }; diff --git a/frontend/src/hooks/useServices.tsx b/frontend/src/hooks/useServices.tsx new file mode 100644 index 0000000..abc54c6 --- /dev/null +++ b/frontend/src/hooks/useServices.tsx @@ -0,0 +1,19 @@ +import { faker } from "@faker-js/faker"; +import { useQuery } from "react-query"; +import { Service } from "../types"; + +let services = Array(11) + .fill(0) + .map(() => ({ + name: faker.name.lastName(), + references: [faker.name.firstName()], + destination: [faker.internet.ipv4()], + })); + +const fetchServices = async (): Promise => { + return services; +}; + +export default function useServices() { + return useQuery(["services"], fetchServices); +} diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 9b67590..51fbe49 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,10 +1,19 @@ import React from "react"; import ReactDOM from "react-dom/client"; +import { QueryClient, QueryClientProvider } from "react-query"; +import { ReactQueryDevtools } from "react-query/devtools"; import App from "./App"; import "./index.css"; +const queryClient = new QueryClient(); + ReactDOM.createRoot(document.getElementById("root")!).render( - + + + + ); + +export { queryClient }; diff --git a/frontend/src/types.ts b/frontend/src/types.ts new file mode 100644 index 0000000..8839efd --- /dev/null +++ b/frontend/src/types.ts @@ -0,0 +1,7 @@ +export type InputSize = "sm" | "md" | "lg"; + +export interface Service { + name: string; + references: string[]; + destination: string[]; +}