diff --git a/LICENSE b/LICENSE index 206754f..4275a6f 100644 --- a/LICENSE +++ b/LICENSE @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/README.md b/README.md index 4fd0ff8..a867a85 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ React Query có cơ chế caching hơi khác một chút so với RTK Query, nê - `inactive`: là khi data đó không còn component nào subcribe cả ```tsx -const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList }) +const result = useQuery({ queryKey: ["todos"], queryFn: fetchTodoList }); ``` `result` là một object chứa một vài state rất quan trọng: `status`, `fetchStatus`,... @@ -88,13 +88,13 @@ Giả sử chúng ta dùng `cacheTime` mặc định là **5 phút** và `staleT ```jsx function A() { - const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodos }) + const result = useQuery({ queryKey: ["todos"], queryFn: fetchTodos }); } function B() { - const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodos }) + const result = useQuery({ queryKey: ["todos"], queryFn: fetchTodos }); } function C() { - const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodos }) + const result = useQuery({ queryKey: ["todos"], queryFn: fetchTodos }); } ``` diff --git a/server/db.json b/server/db.json index 690b7df..27b5450 100644 --- a/server/db.json +++ b/server/db.json @@ -1,45 +1,5 @@ { "students": [ - { - "id": 1, - "first_name": "Martie", - "last_name": "Kite", - "email": "mkite0@statcounter.com", - "gender": "Female", - "country": "Portugal", - "avatar": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAALzSURBVDjLdZPdT5JhGMaZf4Bbh3ZaBzn/gU46MM1iNrf8WExNVyz1IDUOHCFpfq4PmmZmtTTT8GMJNGAO0hgi8a0oIBAGfoS4N12gmUpmL1fPy9LGpu/27N2zPdfvvu7rfh4WANZRa2pqims2mycMBsME+bjHnUvYOJ3O1JmZmWQiTiLi9dXVVYRCIUil0nWVSpWkVCqTZTJZ6pEAIu4mYtpms1EmkylFr9dTi4uLWFhYABFSCoUihYCo4eFhWiwWdycAHA6HMBAIIBwOw+/3g4i3tVptzOv1wu12Qy6Xx4h4mzgDRVFQq9UQiUTCQwCpWkd6jTEQRjA/Px8HHQCYvcvlAgOwWCwQCAQxHo9Xl9CC0WhsZQ5PT0/DarVifHwcPT096O/vZxyBtAXbx6fwDXLgV7TC8ToLzq60EhYh2kn1FZ1OF/H5fLDb7dBoNGhqajLx+fzM+vr6zPb2dtPMxCNQWj42XaPAz1VsuKTQiy7/ZhExvba2FrfLVCZBYnBwEC0tLZkH7qzS7Kbv7nvYW1GC0omwO/cef5YNxEUZWGTGdDAYjPfI2GQckMTR2dkZB4TUpy9F3Hdj9K4Buwu3ELZV4rOYC9ebMvAqSmkWGYmdWFzp6+uLzM7OxiFMDr29vabJoSu1kTkB6KgZO4FSRINF2PLWwtOVQd/m5n/Ly8uzH4ZIxtRKgsTk5CSYv17+GNQU/5+4BNGvhfjhFmL++UW01XB6E+6BRCKpGxoaink8nrjYMNoB71gN6F09oktc/ApewyZx8oWI7Z/GUFVVFSsvL/8/xoGBASGTPHPz3rbx4FHVwql+gpC1ADtLRQg77sDZcSEmE7+IZ9XQ0IDc3Fxhwj1obGzsrq6upkceZgBby/C9yoe29iSML9n4cO8sLRGcT+dwOFROTg7NZrO7j3xMBJDafDNtf8/8DHvWDlhb0zFScQqV13MjhYWFScXFxckEkHrsa2RWwbkT0fulZ/Y1D9j0u+asjRtXsy3E7rHP+S+qJels2qSd5wAAAABJRU5ErkJggg==", - "btc_address": "1JADzZcCizitPooetjtrTpFUuThFmi5qvi" - }, - { - "id": 2, - "first_name": "Sherilyn", - "last_name": "Paddon", - "email": "spaddon1@washington.edu", - "gender": "Female", - "country": "Cameroon", - "avatar": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIsSURBVDjLpZPNbhJRFMf/w9fwNUiVlZWPncSmqemm7FjZaGJcsdCkS17AJ8AH6BvU6BKfgFIXLqArTQngSoPUDSGEhAUCLQN3xnPOMLSJGBdOcnK45J7f+Z//vVezbRv/8/luLxqNxvvlcnm0WCx8lEFZwjRNzh8KhcKrjYBWq3WHCt7G4/GCrocxpyJYFkQbKdzaiuPs7PQlrf4ENJvNp1ycSCS2I5EILn/2wN0ty4ZlWwSyoQg2n883j0CbT1OplCyurq6xoOKvrQsCWOt4cvhMxtgI4BkDgQDG47HTWSk82nks3e1Vdzb6rwqYrKiIN/GBsPRW8wtlJd35ixl5JJNJVKvVIf0XpP0/KH+kfCIKHK9sATFgZ3dfuosH9gJGNIx8Po9oNJrweDyYTqd7g8Fgr91uv/C4szkKWDJBlDP70LjEtZoik8lA1/W1bB6ZFVHDhwJYF6sb4xj07tsJzKUp3vR6PQyHQ/T7fVBnuR+s2MPmuLeRJcvxWU5+fe8NQlpYOrJ0PubRaIRgMIhYLCYAMZE3eL1eZ27FrhOAVdEathK4O6rrGX+sjBV8rtfrmEwmMAwDwZBON1ATkFoZ627m36trfQMoFosHnU7neaVSuTg/r0EPaMikHyCV2kY6eZ/tFfmscjabwe/3IxQKCYDH126/xlKpdEj0Y4pd9zFls1nkcjmk0+m1F6yi2+2iVqt91/71nMvlcoCkFymOKO4S2EedfxHkE8Xxb6/5rMKMZgtBAAAAAElFTkSuQmCC", - "btc_address": "14dvHxKVi6Cqic1dmitcfXUsikr6X7URgt" - }, - { - "id": 3, - "first_name": "Winona", - "last_name": "Kennerley", - "email": "wkennerley2@slate.com", - "gender": "Female", - "country": "Portugal", - "avatar": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKOSURBVDjLpVPbThNRFOUD/IJ+B6gvJr740mg0JsQUX0yMiUl9MJJIwGBsMOgDQSEz0mANhEIKoqhBBTEpahm5SWxLKTO9WBAKBTqtw9DpDbqcfUprvbw5ycpJTtZae+09+1QBqKrEqS4YdNToMOowHcJ4eGf4k18pPKKjuumFYh75vMbPuIPC4tKy7PX55akFUXj6McI3DCfMxCHubwaH4hODrg2LdzksxeIKVC2H/EGBYTeVRXQrgekFn9QzEbYQt2RSMqgmsU/8pqYzedCnZfeRUHOQdexl9tmdqmUxNedRbWMBMqlmBtQXxabKJfGOksW952HEklmG1mdhRBOZssnE5LR0fSBG7RjIoGZE+M5T7JJ4I5mBqW0Bqztp3OyTcLyuBde6/ViLpxlHjGyCG57hSUsGxumvAYF6pqhUcV1O4+IDD+aDCs7dfsfOM02jzFBJ5bGd1NA79FogLRmYPItLMg0rvptjBkSsa3ez864e/2htM24NBBDZ0liKbP4AA44hmbTMwO31MQOKT6T6XhHHLtxhsYMbKZy3OBGOaQzFFDn09vWXDYyf5v1CUs1gV8tjNvADZ5vH8SWk4HTjK4jRvbJBaDPF/kxwPQnO5ii3UONwhvjVaByFArCyrbGpn7zCoak/wBLUtgrsDERTyO0XMDnrh8X6tjxEQ/3gjtnpmpNkpThlqnajR2QVSWj/EGVJqEBIr97ZbZcuW4PF31haJO6l1zL63qXGEkVici/P+qVEtExUObieQIdtUG3kxn4tUuUqtznmLPbhUWnGE8JqTGEzoZ79KzLGXV60cT1SQ+ebv1e58jFdfbJibnk8zrd39QncI6v8sJOX73fYhMaOEf4SL/77Mf3Pc/4JB00Hw5wBy+AAAAAASUVORK5CYII=", - "btc_address": "1QFU1svgpSfvKrXsLHmECf92D9vn6tNwoy" - }, - { - "id": 4, - "first_name": "Urbanus", - "last_name": "Kille", - "email": "ukille3@google.ca", - "gender": "Male", - "country": "Solomon Islands", - "avatar": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHBSURBVDjLlVM9aMJQEP6eNEF0sbiUouLgoLRkKXS1IG4dC6Xg2LXQRXATHbqVzq4iQjc3sVscnUSnYIdIB9GC4L/xL333IEFsBj04jpf77nt3l+8x0zRxaMViMbTdbtXVahVer9dYLBY/0+k0mcvltEPsGRzMMIyPQCAQ9ng8IAJd14OdTuedp+4PsS4ngslkctFoNNBsNgWB2+3GaDQKOWEdCTgY2WyW9Xo9QbBcLoUfTSDLsoiMMUFgkRxNwHeAdDpt+nw+8EUKp29O5rhEvnEoigJJktBqteD3+0/rgINNulHTNCjzGR5++1Bvb67x+vLF/dmxg3K5HOZB2+12MncxfzAYxJ25wcXjE5ixZCu9m/wufybfUqnLUqmUtwmomAtKi0ajcrVaxWAwQKFQEHOfK1dQajUwrwdSrw8ZEiKRSC4ej0NV1TwjJXI2IxaLyZwA4/FYFHL12T6fz+3o9XrhcrmQyWTQbreZ6IAnZS5dVCoVEpFYmFVEPpvNxJm+0zmRSIhoj0AJunU4HNogq3C/EwtHuqBfaxNQkhJ8NpGwAPtxs9n8c5ug2+2iXq/bojl0S41URKPuv2Dm9JxPsT8W0mO2IJm2EgAAAABJRU5ErkJggg==", - "btc_address": "1PWkrbbLAqyjbAa9H2wFMKuyWG5bd4TgpN" - }, { "id": 5, "first_name": "Shea", @@ -70,26 +30,6 @@ "avatar": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAGSSURBVCjPVVFNSwJhEF78Ad79Cf6PvXQRsotUlzKICosuRYmR2RJR0KE6lBFFZVEbpFBSqKu2rum6llFS9HHI4iUhT153n6ZtIWMOM+/MM88z7wwH7s9Ub16SJcnbmrNcxVm2q7Z8/QPvEOtntpj92NkCqITLepEpjix7xQtiLOoQ2b6+E7YAN/5nfOEJ2WbKqOIOJ4bYVMEQx4LfBBQDsvFMhUcCVU1/CxVXmDBGA5ZETrhDCQVcYAPbyEJBhvrnBVPiSpNr6cYDNCQwo4zzU/ySckkgDYuNuVpI42T9k4gLKGMPs/xPzzovQiY2hQYe0jlJfyNNhTqiWDYBq/wBMcSRpnyPzu1oS7WtxjVBSthU1vgVksiQ3Dn6Gp5ah2YOKQo5GiuHPA6xT1EKpxQNCNYejgIR457KKio0S56YckjSa9jo//3mrj+BV0QQagqGTOo+Y7gZIf1puP3WHoLhEb2PjTlCTCWGXtbp8DCX3hZuOdaIc9A+aQvWk4ihq95p67a7nP+u+Ws+r0dql9z/zv0NCYhdCPKZ7oYAAAAASUVORK5CYII=", "btc_address": "1CZXCy88sbPxThH3fvpWSA34hhLoVzWBwT" }, - { - "id": 8, - "first_name": "Christean", - "last_name": "McAleese", - "email": "cmcaleese7@earthlink.net", - "gender": "Agender", - "country": "Vietnam", - "avatar": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJQSURBVDjLpZNLiI1xGMZ//+98Zy6G4zIJkyg0xEyWLlkMC6JkIYoke1kQUrKwsJGFlaVLsbBAuYSJBTEJCTkZQ8clJsYxx5y5fZfzfx+Lk8swbDz1rt635/319rxOEv+j4F/NzzeW5Xval/5zg5NE6c5yyYSkRZhmybRK0ra6prVIYujNBWS6JLOrMnWYtw6ZxszY+Ng5SfTeblNt01oqpTxB7WTCCQupm7oCMmMBQ2mJ6FMHUc8jkt4X1E9v4+vTk8zc9NSFADLlou728sTFx0GGfD9p3z3C3BKcC0l6zpId00LN3C0gT/H+Yczbyh83aGy71W/pIMhIi+dIi1ew6C3IAGHxR+LuMwy9PAAy4t4CMnsIEH4/hkxVXJ+ApeAMG+7AZVLko2pVYpAnyOaoDJWnAaWfBt5AAkuQT3GBB4bBpTjFoAgsrhJ5j3mzPwlUJZBSUAaIgBgRI58iHyMZmEPesiNyIG+YxQT1s8ESkIcggaBKISUgQIaP+7GKlUYamB0tPz9FOH4xLjsJFzpcmOLChKBG4FIaFhyh72U7cbn4bN72wvsRBk3rHu4cfHOdctdZaqasJ6hvIKhJceEgmbEhDc2HiHry9HXdwCfphlGjLG+TBwrXGChcJ9u4GRfOwQWDZBv3ERW7KHVeY/jzuw0tu953jojyr3p9umV+kM3lc82ryc1fQ6a2jnLXTb48uczA2/y61t0fLv7xC7/r1Yl5U+RtRxA27B/X3EbxwfmCTypbW/d8uDvqM/1NncdmTfJJ5aAllb2te7uHR5v5BtnsZt4skcPVAAAAAElFTkSuQmCC", - "btc_address": "19sQuXkrNyVXB2D8i3SbBci4AHnLobpsqs" - }, - { - "id": 9, - "first_name": "Max", - "last_name": "de Tocqueville", - "email": "mdetocqueville8@oaic.gov.au", - "gender": "Agender", - "country": "Indonesia", - "avatar": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJcSURBVDjLbZPfa85xFMdf36/nebbGBcLaMmtM2DybElsjQm5c+PEnoKSQCzfEnZtduLRdSJFc4UK5sEizSLtQNCYXJMXKlMeG7fv5cc5x8X02w06dzqdPn/M673M6n8TM2H/6WruZ3TaoYPQYhhlgRh5s1lUCwU18GLpxfjVAgfzBMYP15bZVyfjXCcxmkiCHKabwfeIX085QK7RQtRwAO8ptTcmujiZWNZSxnICa5lU1r758cR11tQW2HTjOXwDMlpTbm7n//B2VyhSmCoDOqDDD1Pg+OUXmPHOt2gJJoVRg7cZmWuuXIgJmiqohYogqUY3pLHDrzuP5AIaI8nF8klJaJMsygvNEze8jCygUSyxbWIOazQMAVJQoAecch7a25vJzdZgZ1wffEmqL/JP/R0EQRUIkSsrNx29wIRLFkKhEEoqlEj7mQ50XEKPiQ8ArWFpDUixCamiiqCpeErz8D0irQyREIWYRF4QsClkQXIi4KDgvuKlnfP50iZZ1A5R3j7PvXOeFvxWIElzABcnbEcOLEkWR6ac01r9h84YuVi5dy+DoXYZfP7nYfbJxcTq3heBzgI/KdBB8EFxUpn48YtP6TiQVOhv2Ikmgu9wDcCKdWRgfhegiLihZEELQXL4TKj+/UEwWsX/DKQDO7LnCmhUdALWzMxAxxAsu5J6FiHOK98q3yQqjY8/ofXgYgN4Hh3k/PgKQzc6ANGVLVweWJIgYUQytxsQdZHhkgJ6O7dx71U8pKfD05RBAX2Jm7DzSd9WMo/nPm7P/GFTP1A5BzQtIPMAPoH/48tjZ3wRCz4QMKdc8AAAAAElFTkSuQmCC", - "btc_address": "18U4YqWvv5EGgh9mxUNEswFUkWTDspgKFi" - }, { "id": 10, "first_name": "Fernande", @@ -120,16 +60,6 @@ "avatar": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAALeSURBVDjLjZNLTxNRGIb5A2Xh0rULjJqw1BCDprXQAuICDBEBE7xFJQY1giCKEARCF9rUljuEFiOIBokFhYIFK6Q2Ei6V3oW21BKFdnq/93VmQomACyd5M+d8Oc9zvjM5kwQg6e/Mzs6myeVywcTExLxUKv09PDzsHBwc1EkkElG/WHRq7/qdgUqlYpCwkITDFosFDocDbrcbPp8PLpcLGs0KRC8aIm3CerGA35S8S7ANfzCZTIjH4wgEAqAkZrMZm5ubiEajiEf9iPh1kMteoqW54nNTY03yjoDamYLD4TCoJxKJgJobjUYQBEFLQ/6fCHpXEAsaMD7ai7rHZWJaQMLHybZjXq+XBjweDy2x2WzQarWg6tFoBD6XFiGvhu4iTOZO+fXYvbs305JIWGi1WkFFp9PREHVmSmS32+lxKOgiBWq4Vgeg7S+A4V0DFrrY6HzEmUxKTU3F/+T2pSOwT1WAWHoPeGxwLg3hUzM3QgvUajX0ej0UCgX6+vpogHqvr6/T9bFXFfi1+BAh6wjs8hb4l98iuqYgu7gapwXUogRESahQNSql54/Boa5BzK+A33QLW1/LoBGXYqn3Gi4X5RP7BFQSsGG+H47lB4gF5uAzliBgKYR7pQqmnlxMymXIzM1b2XeEhKg4OwV2VcU2XIyA+QJc6mroW7lQqRTofD2KzOzcjn9+xItZh7EkLSfbnkFgtRRBSxEIshODiIMZpRLfzE6kn+HGWOyME/RF4vP5wunpaWwQVkxLefg+WoXFsWdYV+bDt1qIrYVK6NvP4odaCfPGJhoFXWBmcDt2biKPx2PUP62TDYxIMNjMBNxr0LbnYarqIL60kru2MKFZ+Ain04nu7m4wWezx9PR0xq6fqba2llFZfb+j/spRhOYECCmfQ9lwGkM3DmFmSgzJmx5wuJwwi8USJuBdgkTyTx4INZakxGRNnLjkCTtSXJBJ5JzLUmflcNpIOG3v+j9k/eSwcE1V7wAAAABJRU5ErkJggg==", "btc_address": "15v7JuRYocw4djokjJPQrt7HPohoEjyDMV" }, - { - "id": 13, - "first_name": "Glenine", - "last_name": "Duffit", - "email": "gduffitc@addthis.com", - "gender": "Female", - "country": "Syria", - "avatar": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAEZSURBVCjPY/jPgB9iEVoqPefllFPdNk2GWBUsVpz9ctL1rkcNW/v+59VhKFgkPfP+xI0dF+uC/jPkWCR/Q1MwX2TGvf7Nretr/UG8BO2I5ygK5olP/dCzpWV+dVAhd+bB+JawrT7ICubIT3nbvaFpVkVqgVDa0diO4CneN91E4Qpmq0560jW/YXp5XB5nyq2YrqCFno9cJeG+mKk48UHHjLruMu8czuSbkfUBizxeucrDw2GGev/71uW1jMVrsq4nPIto8F/g8caFDymgetxbHlVLgDjxnWExPjPdb7sIoYRkk17FywJRECdY1Xux201nMbSgLufO25qyJUY1yNrzsus9JxkscZHMG+kVcN7jqWueowARkUWiAgBEUvolGfpITwAAAABJRU5ErkJggg==", - "btc_address": "17APzB8nXDDo3MVfSRuKR9YneMLrFUAiJM" - }, { "id": 14, "first_name": "Rae", @@ -999,6 +929,36 @@ "country": "Colombia", "avatar": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAACwSURBVDjLY/j//z8DJZhh1ADsBuRPiazJmxLxKa3P/39ki8Mnzwq9GqINyOgPbGhcnfh/y5Wp/y882/W/f3fW//B+3f/m2ZI9RBkQ2+7yfePlCf83Xpv0HwR69qT+79+TDjLgO1EG+FQb/t92Zc5/ZLDp0lSQAf+JMsAyR/p7966k/+27EsCa23cmkOYCoMKW4B6N/727UsA2g2gQn+gwgBrSAcSfQM6G0h2jSRk3BgASP+M7I0sypgAAAABJRU5ErkJggg==", "btc_address": "12tTumUNmtwbrLz3Xf6mDXn3qqBuNN2UPB" + }, + { + "avatar": "123123", + "email": "lspals@gmail.com", + "btc_address": "12312312", + "country": "21312", + "first_name": "123312", + "last_name": "123123", + "gender": "male", + "id": 101 + }, + { + "avatar": "123123", + "email": "lspals@gmail.com", + "btc_address": "12312312", + "country": "213", + "first_name": "123312", + "last_name": "123123", + "gender": "male", + "id": 102 + }, + { + "avatar": "3123", + "email": "lspals@gmail.com", + "btc_address": "3123123", + "country": "12312", + "first_name": "312312", + "last_name": "31231", + "gender": "other", + "id": 103 } ] -} +} \ No newline at end of file diff --git a/server/server.js b/server/server.js index 724d025..6bb9385 100644 --- a/server/server.js +++ b/server/server.js @@ -1,64 +1,64 @@ -const jsonServer = require('json-server') -const server = jsonServer.create() -const router = jsonServer.router('db.json') -const middlewares = jsonServer.defaults() +const jsonServer = require("json-server"); +const server = jsonServer.create(); +const router = jsonServer.router("db.json"); +const middlewares = jsonServer.defaults(); -const PORT = 4000 -const DELAY = 8000 +const PORT = 4000; +const DELAY = 8000; const validateEmail = (email) => { return String(email) .toLowerCase() .match( /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ - ) -} + ); +}; // Set default middlewares (logger, static, cors and no-cache) -server.use(middlewares) +server.use(middlewares); // To handle POST, PUT and PATCH you need to use a body-parser // You can use the one used by JSON Server -server.use(jsonServer.bodyParser) +server.use(jsonServer.bodyParser); server.use((req, res, next) => { - if (['POST', 'PUT', 'PATCH'].includes(req.method)) { + if (["POST", "PUT", "PATCH"].includes(req.method)) { if (!validateEmail(req.body.email)) { return res.status(422).send({ error: { - email: 'Email không đúng định dạng' - } - }) + email: "Email không đúng định dạng", + }, + }); } - if (req.body.last_name === 'admin') { + if (req.body.last_name === "admin") { return res.status(500).send({ - error: 'Server bị lỗi' - }) + error: "Server bị lỗi", + }); } } setTimeout(() => { - next() - }, DELAY) -}) + next(); + }, DELAY); +}); router.render = (req, res) => { - let data = res.locals.data - const { originalUrl } = req + let data = res.locals.data; + const { originalUrl } = req; if ( - req.method === 'GET' && - (originalUrl === '/students' || /^\/students\?.*$/.test(originalUrl)) + req.method === "GET" && + (originalUrl === "/students" || /^\/students\?.*$/.test(originalUrl)) ) { data = data.map((student) => ({ id: student.id, avatar: student.avatar, last_name: student.last_name, - email: student.email - })) + email: student.email, + })); } - res.jsonp(data) -} + res.jsonp(data); +}; // Use default router -server.use(router) +server.use(router); server.listen(PORT, () => { - console.log(`JSON Server is running at http://localhost:${PORT}`) -}) + console.log(`JSON Server is running at http://localhost:${PORT}`); +}); diff --git a/starter-template/package.json b/starter-template/package.json index fcb6627..1a89da0 100644 --- a/starter-template/package.json +++ b/starter-template/package.json @@ -3,6 +3,8 @@ "version": "0.1.0", "private": true, "dependencies": { + "@tanstack/react-query": "^5.56.2", + "@tanstack/react-query-devtools": "^5.56.2", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^13.0.0", "@testing-library/user-event": "^13.2.1", @@ -11,10 +13,12 @@ "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "axios": "^1.1.3", + "classnames": "^2.5.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.4.2", "react-scripts": "5.0.1", + "react-toastify": "^10.0.5", "typescript": "^4.4.2", "web-vitals": "^2.1.0" }, diff --git a/starter-template/src/App.tsx b/starter-template/src/App.tsx index ef30c96..b230f98 100644 --- a/starter-template/src/App.tsx +++ b/starter-template/src/App.tsx @@ -1,3 +1,5 @@ +import { useIsFetching, useIsMutating } from '@tanstack/react-query' +import Spinner from 'components/Spinner' import MainLayout from 'layouts/MainLayout' import About from 'pages/About' import AddStudent from 'pages/AddStudent' @@ -5,6 +7,8 @@ import Dashboard from 'pages/Dashboard' import NotFound from 'pages/NotFound' import Students from 'pages/Students' import { useRoutes } from 'react-router-dom' +import { ToastContainer } from 'react-toastify' +import 'react-toastify/dist/ReactToastify.css' function App() { const elements = useRoutes([ @@ -34,8 +38,13 @@ function App() { } ]) + const isFetching = useIsFetching() + const isMutating = useIsMutating() + return (