diff --git a/.firebase/hosting..cache b/.firebase/hosting..cache new file mode 100644 index 000000000..efc290e6a --- /dev/null +++ b/.firebase/hosting..cache @@ -0,0 +1,151 @@ +package-lock.json,1692202990815,01d669b14b3ea9a74b2e5fcbc1c2c7edfcb11f65c4f8d31c7558ffe7f8204355 +package.json,1692253486441,ea74a7fbf612efaac6dcc02503d8dab7f5fc7a67313aac5577e06b6cdcc56030 +README.md,1692370351922,0eb5929cef3443c9833241fe32900ab171424a4fe27d3ce1bb20487cbc137acf +.git/COMMIT_EDITMSG,1692370717297,a52154b97a7d66f799891eadac5fd81c672acfc21192d2ff5c05d1a91cdc34da +.git/config,1691976600370,d1829687a1935feed55a298a52d897618060c7161ae6521033bc8bf4e5b5cb25 +.git/description,1691976592132,82f2436d331ddc1123e2c797669bec173d77c86477f087e1134ca09d91a0d852 +.git/HEAD,1691976640798,d12882553fb73d308e183b694006f27226e5072cd19d3946de3520cc79e083b0 +.git/index,1692673329643,23eaf4b5eeb90301093d5766a9d7db916c8941afc900db82cfb945d40e518d7f +.git/packed-refs,1691976600359,e2f092677ede21df8aa0666ee0b81cec203cc815c11100a2a964abb94b3188fe +.git/hooks/applypatch-msg.sample,1691976592133,159513c8ea7e79b52b19383e22c9b658a2d945432119c08295b7a7e0bb3a1784 +.git/hooks/commit-msg.sample,1691976592134,e57048340ae7ab73a9981e08e0dc33ac4c9ce12fbb1d4e36f0088b48bfb45dd3 +.git/hooks/fsmonitor-watchman.sample,1691976592135,a1d7cf483df6f75410516c4603a0b65163ceea3bd7e851102edfe16c80511050 +.git/hooks/post-update.sample,1691976592135,186590add780eec85c8e17f7b2726a6450113db3d709f49ed731aecf3b81465a +.git/hooks/pre-applypatch.sample,1691976592136,93353290a9b7afc06d5e6788dcbaeac204cb675a5d36fa2fd37d9564804e50f0 +.git/hooks/pre-commit.sample,1691976592137,0f1b8bcd57419856b52e2fea5965a5c47b98844f63f553f03f672f08e91f9ac3 +.git/hooks/pre-merge-commit.sample,1691976592137,f6ec777f95c3a2703f5a60b43f0450811ac294a6aca051922651c74d910a718f +.git/hooks/pre-push.sample,1691976592138,19bf363d5c1e6bf385375d25405d404c81f48b7d23aaf7ac14a1474748dbcfb6 +.git/hooks/pre-rebase.sample,1691976592139,9d8f25c53691dbf1d631c984ff20abcd073efba327b1aee045cca769c3dd73f1 +.git/hooks/pre-receive.sample,1691976592139,925ccbe4b2d5692094cb38a1daace52763f91e55ca85f133abff4b811a229f80 +.git/hooks/prepare-commit-msg.sample,1691976592141,3eff30b4f023ca3b2fa331a45fd227f6857177f773418a54bc0a513c5332f0f3 +.git/hooks/update.sample,1691976592141,b0c2c19c5afd90c0db973f3db201a2c3037f10672c7fb293168d56e64d04a8fd +.git/info/exclude,1691976592142,77e7e1ad67e1708c9434f9f596056e24819c6111399ce06bbddb35133f598f61 +.git/logs/HEAD,1692370717305,f3334e46a01d34da1481bf73b2a5391d931d8b84af7ba7bbbc4dec67e57e0031 +.git/logs/refs/heads/KDT0_NamHyeonJun,1692370717305,5bd0570bb08ee73a50b6822d6eb4dba45b08f1bed2a8efb4c928e7e2532dee99 +.git/logs/refs/heads/main,1691976600367,ba155975be4d186eefc044f1fead2ddc06f61b37ad21460ed596e3cf6d98bcc6 +.git/logs/refs/remotes/origin/HEAD,1691976600363,ba155975be4d186eefc044f1fead2ddc06f61b37ad21460ed596e3cf6d98bcc6 +.git/logs/refs/remotes/origin/KDT0_NamHyeonJun,1692370729314,9527b4cb6a658f8df3dcb582f87689e95791e8e7dbc785165cff702c50083aa4 +.git/objects/00/d217037b6703880f03db4e0632c786b56f2b22,1692369812705,a47b64985521cd69df7041352b890e1119df25ea064d69ce8db3732fd862b68c +.git/objects/00/dffc12ab0a2e077260ef133c37fc3db950236e,1692112843752,e1afe20a8ebff6e8720b1d0bd688c994c8c082f73f4711d216cce0d8acce7cfb +.git/objects/05/5ff3e9a63f774701356b10111cd10abf48cbeb,1692369842201,7b51dc8eb8b9de0d69fc19e7f2c9684a3eb4836cb162e02fceec7c1b3e5e7d7e +.git/objects/0a/3c08ce203d70b86c29ee66ea7017757fdc66ec,1692292207961,5c30ccb15e7e9524d1e533417538171abc97d18da7b57297de13183c5ecc5467 +.git/objects/0c/7b1a049e1cb2e4fec04d2019544059bbeaab6f,1692295135396,8bd37247fa19c1767be012aebb44aae8c80aba76da7d35fc0d9f7b0cb171ad7d +.git/objects/0c/d92fa645e3ffbd8d4b981f0698d44a1756c924,1692351812923,98a20e7d65fa4458a69c7e40ca233d4df72f7923f60e2bfae013352ffc1431b1 +.git/objects/0e/b5c4b00cd3f54cb276ff700905bea08bef301a,1692366034701,d9641b4c911a6d3719de1d0bd474c290c125ac6d5a08b8431d08837e56b07f2b +.git/objects/11/0b355517de2ed2fba9716dc19d274976f37e7b,1692202785634,3b9cb68db8b6b5b963cedc80f2c43d4c050ce3e56ec7cd2d81f4ea268575da50 +.git/objects/11/8aaf919f23e0615ea79a76966d7591efda5148,1692370698194,5304172cd1ec0b2b655eaf2520adce1fecd384b7a60766161bd84c1ade4f98ca +.git/objects/16/1c893e49e3887d3395b4cbbd834dd4bee5cbb5,1692115227779,c1d96163a1bb6acfeddc5fc15b2945d19838b622565939d2416bc5acf60a5c08 +.git/objects/19/92f4712785759dc186016a6c604dfb5281a2ae,1692292189984,722725187af1e4521187649b0dec177b32661457ca0078063da359d9d1416f23 +.git/objects/19/d2757e458650edf35579044f5011e85bd9a512,1692295106395,fde0c5dc8085a2488e5315890098d51bd5f8d012a1f61f2250da521c5cf2c04e +.git/objects/1b/793b82292b6dacf74a616505697eeee5521556,1692292189987,0939e7d92ee824d893af7a4ba7affa8a225557e1d53a858c04c022b8ed3859f7 +.git/objects/1b/8d68829ca166cbcc89c3fbd9aba414880b2139,1692336606191,023110fd764d1d76325db56a6d5ccf8d17cce534d8232791aef1756df37ce523 +.git/objects/1f/5ca6e5dd7cb463e3e31e834001bf6c489cc5dd,1692112860979,002ef3c81b0884054481ff3cf7bf5cdf896e53622626750947c7c709030ea5e6 +.git/objects/23/a821d51ab2c26ef062e6cc9e60ecb948bfad18,1692366034692,7c1e5cc2c79946123df4f0a07114df8828375e0aed74ac1e198760aff5ce9694 +.git/objects/2a/a000a8b486efda00566b04d24533ec56e676ab,1692351072454,58ef2a0435a39bd6781aa185483db8a16a0c3c85542d804f4ac28dc7ec6f17a9 +.git/objects/2e/943559be16e9b3529b7e8605ed23c54a78c523,1692351798142,9fadd1bdb62d21db41f7069afdb0b197c2247d03444659b0d6aa7cb7ea785647 +.git/objects/31/e573f8ab92b6a03c8205a0734b7df860ff79a6,1692369853041,70b0409738f9f73aef9e37c069c6ac96983abf14d82915fab3a7dbf999e5dfcf +.git/objects/36/295334a9291ddd3b61d732750d8f7b6a03bbdf,1692351072466,a210bd629eaa217a1072ef9a914ba7edefd2870babef27d5703f343f7f5d55d3 +.git/objects/36/45cb34f367ca64c75d638cc7b8ce4ffe84fe7c,1692351072468,d25517c6a06f25d853a381830e3db38c709300372674e2bd91095b78930843c1 +.git/objects/39/8fde820486b95e69b3a7d56998cfcb4fbafa72,1692369853033,3f17c4cbc867beb0afdce4d8a0a4a778760f60941334c509d2da7728ffca9d36 +.git/objects/3d/cd05a3f841dc02d83c7217f42a2e61dac51bfd,1692369812740,0ae39800677011250c00ee3762d0cde2bbb601819aaa2668aee19cfa9aee2683 +.git/objects/3e/e779661142bd2366e4b84104a0ca53b0c728c7,1692336554792,9887ef91fddd4682ecfe916f03b792fd4f5a498c7ebc5b053c9883c73a70ee10 +.git/objects/4a/2deec80ca6762bc28cffa1883a6c2afc3407d3,1692115209843,89663cb03a4e0f7f98b6c0213c1425ef046b712b7c0c53f10aae24520e80d732 +.git/objects/4a/65cbafd02e88bfe4b1248881fa55be52636153,1692351126352,6e8cbca406992b1b3fe2969f201386cc42535d779169764c18d43764c620a23c +.git/objects/4b/6b9732ada1f1fa2cebd08229e70f355aceeae2,1692369812723,6e5aa4e22801755e4e51a0670ebcb2c4cba0246222d6a48a9ca6fa8500008854 +.git/objects/50/67b1e74dfbdaff3f6cabca7926c47ea11f6b76,1692366021071,d3a837f3616c3510f54c7b9afc1fc4a401f81ec76120e663719ace85e3333ee8 +.git/objects/5a/bdea811c9ae6009e5c60de4cd774c66fb7359d,1692336606201,87549f7a997227b5bf74b892ad850d4db666a19b498b31e83d11bcc91e241045 +.git/objects/5b/b5c8c2baabf6c6032d50372a6f90106a348f14,1692292189980,4c7bcfb74e3ed0fb43f84b15db6bb1e7454848f4e669b30668547567af25357c +.git/objects/5b/f2d8e8a9b1b5842e4d3eaf1cecea06a8472327,1692366021063,2e3d069db153fe9e31658192f66b35131ab97a12ca7dbcf20958455059cbf300 +.git/objects/66/061c8cab411a0cf3153da3c55b0ad7955ddd29,1692351072456,a2a8c88e1e4425efdbba50d4ddd48666b9625c3201a0f703925a74ba6ef355d6 +.git/objects/67/c5fe2dc4bd0b00e306de62b824cc833c3533b1,1692351072461,293689520e1d85257cdca9bb98f122184119fd53ca7a35d8cb13ed5a592ddc81 +.git/objects/68/220162ba78b2359b18fa8471846981980ecabb,1692292207971,c1cc2a86087e56cf08cc39affe0d7ab660dcc57605cd6b6b57f2c41f563f6338 +.git/objects/6c/ac8ffc581d0374049d828065dfa09d3efdcfc4,1692112843750,5606650ba0f7cdc27f0d0c3e6e8f38c8dbe64bbbd209e7e0d9e16fc0577d0f84 +.git/objects/6c/c030a8568905fc054bed59381a1375a7dceba0,1692112860971,a0169931e04761b43834af8468b38a46bc1fd9f610e644d448670df8bf5dd93b +.git/objects/6e/9076db2f706130a0e1abf593d272f2bb01ed72,1692351812914,9e824ab482b8722a4f51031154afcb213a0f004ba3c6589da41488b1374eb9d6 +.git/objects/6e/f02392cabca0d0885a7198a6ac5653465811f8,1692351798139,89529eee1eb3a8490402e64cb968d01e13b93c1ef94fd4dee4e9e528c0d84dfc +.git/objects/72/46bc1e0a729b5ae7d0f2c48d2bb172c8552f95,1692336554793,26eb6e32df05d4d75782ec80219867a7f01e243b6c28b04aaeb909338e2f931f +.git/objects/72/4d0c63358267934dd81feaa9bc2029fcd4e881,1692115227787,6c437e741110b75b9d69aa6f7b5171b254e455ad5910df1744b2797e5a3456aa +.git/objects/72/4f741de767a34fb2c07d7f1f0596b3933398b4,1692370698197,0c0b23514762884c3da5385a4dc5da319eaa1774ba8ca52ebf39cc30e70f35a7 +.git/objects/73/c32a929afd180fe2cd781c94041d8d2f92384d,1692295106398,144b6021ca395bfcb3a53ac57760c0be5bcf74493a586081b485d0ae3b1131f4 +.git/objects/7f/6d52b52dd6a585cfbf13f9dff6f68820dba676,1692336554783,ed3c61e40d72a14c1f8e7991338ebc1621813b4bfc37d772981cdcedc60d2629 +.git/objects/7f/e6f856ddd557376adbecbce98f439c6406f4ac,1692370698203,e59e1d1556d213bc9786f2b7bf1766a8fa4ca1f5209f1aeacd24db6b2dfa97a1 +.git/objects/82/7f136fc903d3d284d74cae538ebb42042ef6fd,1692336585324,a44ff7a1d7cb8141a5d94dc9c6adf3cafaf54dc6be4ad0e57ff6e49e0c9ef4ef +.git/objects/83/52efb8302b5ed7d07b23bd7d0bf222a89194d9,1692369812726,189a853349a24b53d3d4614b0a80e4dcf1d05b597c9205c77b29c8a8bb92e03c +.git/objects/83/61589d33a54b92ca1691124b618781548cf338,1692292189974,bdabd2f1399a2c03253b4cb867bbbb705edcce55bd16ef468e23cbcdb1a3a947 +.git/objects/87/e4420cae36abad8bad03eed3ec9c7233e872ea,1692336554790,24a0b06d402f998379482f85737dd854c2c286a05861374110863d0491bac559 +.git/objects/87/f1c3168a7193b5a831c9574d28fd2073974f1d,1692170078140,c7a5363cfe5ea67ace9c38925ba888e144386d8f577fa9ec3ac8fed1b42c200d +.git/objects/88/1c8eac888b2af5684ce427c7194ba390addca4,1692369853049,545e342233f793654c1d0ab13357ebcd6ac018899433a3f7751a5d5230b862f4 +.git/objects/8b/1c9f00d4d98a2bd7182caf6b813ea733ea2251,1692202785642,6f9e02d914e8f00bd5302b3c655acb6f407b3cb310b1b117cff4a8dd7c941e8f +.git/objects/94/513bbc49a5ad15e0517ef4cf7420921e379bf8,1692369812733,b4b356ae3fea15d06ab01d667183209c1ccdeb56b081c00edf6781addc4a2a4c +.git/objects/94/b1964a75b6c96daf1afd662c24472a5f7ef97a,1692170070691,6b56ab9406784aa1bdfef61a22e932f3670b7a34e5349e74211564117f964f7f +.git/objects/98/dd81a0a551218f398abed191869a3c1340fcdc,1692336554779,7c32d09db34c886dcb4830240b4561932d2bbddc277962fc355617745b7a4c96 +.git/objects/9a/436c8c8dd2e2662a45ec70a6ab2ad44ed2c312,1692170078132,1399ad81330f811fa25209a76db6aa626e09cba04c04cbfa7c4dbee2cad6e8da +.git/objects/9a/841da2dab70713183a2bc20a91a97f362e8501,1692369853036,09bda4df0513058912f754e517c64e663b89e02ec97aec71904a744dc43ffb3b +.git/objects/9c/740d9a05b36d7806bfaa8058baf75df82db647,1692369812707,e4ee1085aca21566fcc28eb9c21d0c31f712ca4152427276476b76880984d9da +.git/objects/9d/2b17315958fc973c6271b9e171c8906fcd94e5,1692170158368,d29b3c4879e1ab6c8411a861ff0b994394b66d220661ae3ea0dd8b7b72785c70 +.git/objects/9d/dcbea81ac2242e6ad75643e7ffed10ce4ef6e5,1692366021074,f3c1efb04d5a1566d80695d5053ba4050ff3f5dc38d2d1cb534e0dada301e655 +.git/objects/9e/aec8536fe9cdb44e736bffa72af2b6ec60318d,1692295106400,c2412848772c672022226d945f57d1edc136f042888569f11d39d3d031a6b4b1 +.git/objects/a2/2b84a7a8787f6aa727c3f97300d05edda47396,1692202759102,8c6878475c09fb7e92a6967d69f720c46f3b696a479bd0d1a5f8b284df151468 +.git/objects/a3/99a4c163da065af8700783dda21bb6e9be6f0f,1692369812714,0dc46034b5a5b46811f61f1fa5683335c3fb8a1ff71799e66daa71bb6f8bd324 +.git/objects/a5/ddaef3bf20d9dd7ef0a100f814155c099b3c40,1692170164724,97c0add73185536945684f91318c83493bad225d2de1f95985aead33cf7de435 +.git/objects/a7/b9318b99274e6c4d04242057f688283060ee89,1692370698200,d89ae36bccd8f28343247494587352327275f05f5a61d1d6a91058b2cfe5870b +.git/objects/a7/c6994fe1278790bc378ff1cbeae89fa196c639,1692366021068,3a1434631c5a276c52994122fe27a4d972df7873ecc8d39e67b954fdf732a34d +.git/objects/a7/df5ef1f0da1d5db9ff2f5f9b223111b8d3a0b1,1692351072448,40939afbb8ec93930efe5ee3d957b4dc2d0296f9c1b61896d60b21bb66ab1325 +.git/objects/b2/08e23d8edbb849ec3c9657f718f64df5b7637c,1692370717299,bfc7a1059ae350dbc467fe8ad4f17a9d5fde797d8992f85d93587237a72268fa +.git/objects/b3/6cb77972e7381709d718d9a78d9e4ba447a403,1692369812712,db05183da6bb6c3a967db2b52c446b8317e4392b94f4f4731b24ff67ab2e8cc8 +.git/objects/b3/beab46e7157d92bcd18aaa92dc11f430890f11,1692336554777,4d46e476c0957fee177acd32ae45b5f4c126728c0a6b9d484a44865abee125c7 +.git/objects/b6/7f8ab45334d1329a89a806c78d1b25e10d9c89,1692170070687,ce9197628e988b82b007c3895e9c64b4db0551e449ba92a04a28f082c08c2987 +.git/objects/b8/05667375957d11fa2d20a034b247c855b7ed23,1692336554795,b717f9d284bc80e9672078d33ced6ae2dcb0f5311504ef02512c4bffc2ab561d +.git/objects/b9/55a61f186af6a9c5c05d54afd186c9a99d74e7,1692295135388,c8f54a27c3858d636bd6097c5556670d08bf9d64a26b5ec2ff62de034661e517 +.git/objects/bb/4317958f639684737e1b1990bfe80ee5dc3ee7,1692336554786,d7c4040f262ca105b8ea17783a092a24224f20afeb03f8bf84984423b843580a +.git/objects/bd/ad558d01df72eb357742e7babcbead4c4f90b1,1692369812720,6777e5ad65bf6f98ff2b1f3c02dee89247de83f5d8eaeea487098c97848f1bcc +.git/objects/c1/cf0f0e193e61cbab87422bb6561c169c96352a,1692370698187,507d312182c05d35ed0f1c4eda64506d76ced727dea1f04def7a377e6639ebde +.git/objects/c4/999c93c19c6321df3489d3a769e662972fa070,1692370698189,dffd95c5c8452751cbfa61db0e3931eff52e381d5258a20a370e9998237ce7ac +.git/objects/cc/c2ed3067e25bfa87a8787d464fc2256cb043ee,1692115209845,fe5126216661717cd2ab668dd2cfe567e7acf177411845352c92de93bfe54d47 +.git/objects/ce/b043d3acacd8df0a14168522539f93b83828a1,1692351072452,a1dd28b5344de16ae087a1a349a4141d289372c3a2a78c5ddb04915b4f39d78d +.git/objects/d0/eda379e2b2588ff823d2d2263d5ce3e0d7617f,1692351072458,53f9264ed6c66e11f8aa1cc878844912b193c95dc6de16f25ad4bbcbd8f5fe4b +.git/objects/d2/0e4caab09d56789a81d8bdb00731cf2fc2b696,1692369812717,38a43ea4d5b46cb42a23126b691049227f3b33ace248b783e2459aa032d40759 +.git/objects/d2/49d89a09bff39a07a7d91a56ca93e93b56e329,1692351126362,88c00b6b7fc71f8652e12649e2ae3a22a886ac984ea481c1095430a7d29ab317 +.git/objects/da/d182b1c489c5722e576059387836ea9365e202,1692369812730,5e2dddea8d286a9371991036a36a9e186a84f54dc98207d261248cb42a225aa9 +.git/objects/db/28768c91427be8ba9fccb53420cc6bfe6ddc3e,1692369812736,f51a113da34c077982b6a43cd5079214bf9a6dee73850d78ecf630e20492d0b2 +.git/objects/db/e9c82b3610ccd58d1c681848dcd322e500051e,1692112843743,fbc9f3689e451660dd0b61add6569081d64ef80be33d34311d30dd6b5320313a +.git/objects/e0/1801b45e8bb7b9568374bd04435a78f2643977,1692370698192,d2ec3049e4829047ff33cb43abb09fd9dfcc5ed598dd4016be14fd7b5e6e8642 +.git/objects/e2/a4b323d4e05c090c03c88a4e6120a9c16f1f54,1692351072464,2ba92c26b4f070c15ef7d4b1983ae93a078c461a17351caae3faed5d72406625 +.git/objects/e3/05e4871625c453052cc7ce0624dc8d0e118511,1692295106402,4598ddd53d5fb570e989ae4a7923433adb3b4ffcbb41841d78d5cb8a1a86a984 +.git/objects/e9/f140360985a45a0c8d07fbeb2be9bd5dae69cf,1692292189982,28b56233d98cb51a001eb0e87fad3022ace855bb2d6d6f84b10393f30cdddf0f +.git/objects/ea/d01936b9bbebeb653b10c69df203f70f081ef2,1692370717289,307cfd0af6b0b7c0e1aef34783e16a033a1f0288060acd012e102bb38e25b886 +.git/objects/ec/eb15ec5dbece413a418896837a7f722100b9e4,1692112843746,fff2950df7b43181bc7e8b53e08ce77e2f3059f1446634ea0dcba292d0529df4 +.git/objects/ee/7dddec9ca195ee45fa48e29f67733023fee958,1692292189977,8c9b4a2e003da0d515df38eb0d1c62173c6eb8e0b01a00d0b7427bc160b4dc38 +.git/objects/f2/b242ae5de8441c5bffe59780757004412f4f92,1692366021066,5fa252d43ff9d819be9f3bc88351beef027bcc2379ecd28b829b33f07c031252 +.git/objects/f4/44febbb33828252433d23999305b9150ff7ffc,1692170070689,581989486b424b97a90534ece40127da2e88725925c09a1245746611df8fbd72 +.git/objects/f5/323a93337cdd6b4a3a6f92b02bc9691576a808,1692170164716,ac8adf4686b70d1d9bb56ccc1f384e829c1986c947f428dd9f8486df55150e99 +.git/objects/f8/74ec5c99a5f13352aac2b0228029aaa4fdedb4,1692202759100,ae6f34ccec3641623ff8b5ccfb76c0f63e6afbad23b4ea1bd1e8b6fa3796d0b8 +.git/objects/pack/pack-a419bdd7daf5dcf8c6086d00334ff04978bc5b05.idx,1691976600243,15f8ef48bbeea79581565d9df17fa08a4ce383db82bd401e719ca9fae2a4936f +.git/objects/pack/pack-a419bdd7daf5dcf8c6086d00334ff04978bc5b05.pack,1692112843745,01c55dcd7a80b7a02e2f1b0ecf604816195771899469a9858476156009f5ea25 +.git/refs/heads/KDT0_NamHyeonJun,1692370717304,b58df8d9bf2698d991c01219fcd6ab71eb6f1607b2c7a84f537af9a92960cfb0 +.git/refs/heads/main,1691976600366,d54d5c455f26e4dcdf2ed84e21b2258b00ec632a7c989ba28589f393b628914a +.git/refs/remotes/origin/HEAD,1691976600363,309067256ef321c6851b59e293ca58f7ccae3509e768e9597fd3348d34570b32 +.git/refs/remotes/origin/KDT0_NamHyeonJun,1692370729313,b58df8d9bf2698d991c01219fcd6ab71eb6f1607b2c7a84f537af9a92960cfb0 +.vscode/settings.json,1691991040227,bfddd6c3bcad48364a2f5aa61f268ec2f165477695b95eb0b1cc60d98360af6c +assets/images/detail.JPG,1692367535070,840aecb3d07dd0afa57cfc14b21b7ee41b2951a1e228d4e526a2148933822236 +assets/images/enroll info.JPG,1692367514870,c9c0710d3cabf901778e4dc4aa27c7f90ad03f925a602d31d04b53ef8c135e3c +assets/images/enroll page.JPG,1692367400883,809fabce5de0804ba451454714053d736c427d23d02858551431074f3bb5bc50 +assets/images/flow chart.JPG,1692367190544,41171a61bfd5a7ff88fae3ee9740fde651ed9c76c03ab981f064a43684c9994d +assets/images/index page.JPG,1692367352800,9857c2fc25d7f9f68ce193c14ce33c265dae8981ffae94ff49e914ba08e3671a +assets/images/update after.JPG,1692368328671,8878f9f9457831d19eac5804e1c663409e9548a5c62b894a95f56db0db6b222b +assets/images/update.JPG,1692368319746,04cc11a63caf6663d247865aa2bfce463a1b6c546bbc100d7e8091f5940ce493 +public/404.html,1692673802339,daa499dd96d8229e73235345702ba32f0793f0c8e5c0d30e40e37a5872be57aa +public/detail.css,1692673329633,ed08046fb2102959c49f65f877b7cabdde2cccc1bc100e4ebb7c7723e0c0b1a2 +public/detail.html,1692673329634,938c784030102a49024b251c496f2f7853784160cc31e430e2dec67f736cf2a7 +public/enroll.css,1692673329635,ff7bbafc00a76de16bdce2a68a2a00d6c98aca446857fcfb380de35f75006431 +public/main.css,1692673329639,6b698ae18feded02d695384f27916e0c7730ab3a7b8ac2f76b52dd77cda19db5 +public/enroll.html,1692673329635,e06bee323bb8b8227d00aaf4a91e2da3e4d3360e96e00949fa24048e0c09607e +public/index.html,1692674445964,2054d54e5b66b91b442d1caa5e3060a6ce310eaf6a95dd2a9ad1a9e34d515fb8 +public/update.css,1692673329640,a690d8818c70e9bb83ed02a2e38db96147c6d7171d70df657bca119678b79602 +public/update.html,1692673329641,478fb893131a4ff68a78ebd72637f4ac80e154f7d27dbb6ecbb640bbd87ba3c0 +public/js/detail.js,1692673329634,d87a9194a012a4a6f211bd62f6ae813519218604269fa52c75bed48e644ecb7f +public/js/enroll.js,1692673329636,5b9616879aa9c046555e50a7e4c5401f206a2458c907090f689930f9e54781b3 +public/js/image.js,1692673329638,9ec96abaf0b792c69999bfbb860e2baa411e28c533e378d52225c331cc073e8e +public/js/firebase.js,1692673329637,54016a093ee5e34fd63bce9a3fca59b2a6600e3a66ac1156fdd30c36d9d885f7 +public/js/index.js,1692673329639,0913a6944235148484748c0d1f7afbe10ab4b9b884ae809220ec0f4c4425163c +public/js/update.js,1692673329642,d0fb7d8414588833448f628387caa66262d482765c1193acda637c28914fa9da diff --git a/.firebase/hosting.cHVibGlj.cache b/.firebase/hosting.cHVibGlj.cache new file mode 100644 index 000000000..00756e102 --- /dev/null +++ b/.firebase/hosting.cHVibGlj.cache @@ -0,0 +1,15 @@ +404.html,1692673802339,daa499dd96d8229e73235345702ba32f0793f0c8e5c0d30e40e37a5872be57aa +detail.html,1693211975306,7e8f25e10c7a72901dc038f8cdac37579c84fe90dedda0f4953171dc581a52a2 +enroll.html,1693211979483,99e6c2ddb16f1f655207dbf1c941f68531254911140ef72d44957722185f3dd1 +index.html,1693211984539,2651ff09fa9692ebedd724096ae66da78b0b62083a2227eeb3e8810e497e5df6 +update.html,1693211991160,2b2235e89b607073e4b63f60e5ed6493a154bc81c365e87b13aaf42bf6071acb +css/detail.css,1692673329633,ed08046fb2102959c49f65f877b7cabdde2cccc1bc100e4ebb7c7723e0c0b1a2 +css/enroll.css,1692673329635,ff7bbafc00a76de16bdce2a68a2a00d6c98aca446857fcfb380de35f75006431 +css/main.css,1693216526029,f265a2c8f68f0fad5b5d60b981e4a4f43b8e8ffa202ebcb2c9cbaeddef92f7bb +css/update.css,1693212704193,93efc8d236665521f505ad805a0c2355e3d5a9c4fed98a8251359b095959f705 +js/detail.js,1692673329634,d87a9194a012a4a6f211bd62f6ae813519218604269fa52c75bed48e644ecb7f +js/enroll.js,1692673329636,5b9616879aa9c046555e50a7e4c5401f206a2458c907090f689930f9e54781b3 +js/firebase.js,1693216618204,00c0e8c0028acad19339226f0328bdd4253859b8ac4e3589dc677b8108324732 +js/image.js,1692673329638,9ec96abaf0b792c69999bfbb860e2baa411e28c533e378d52225c331cc073e8e +js/index.js,1692675926167,0913a6944235148484748c0d1f7afbe10ab4b9b884ae809220ec0f4c4425163c +js/update.js,1692673329642,d0fb7d8414588833448f628387caa66262d482765c1193acda637c28914fa9da diff --git a/.firebaserc b/.firebaserc new file mode 100644 index 000000000..7e8fc0dc8 --- /dev/null +++ b/.firebaserc @@ -0,0 +1,5 @@ +{ + "projects": { + "default": "nhj-js-homework" + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..8361589d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vscode/ +node_modules +package.json +package-lock.json \ No newline at end of file diff --git a/README.md b/README.md index b1efd6d14..8640f9d06 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,60 @@ -# :camera: 직원 사진 관리 서비스 +# :weight_lifting_man: 헬스장 회원 관리 서비스 직원들의 사진을 관리할 수 있는 사진 관리자 서비스를 만들어 보세요. -과제 수행 및 리뷰 기간은 별도 공지를 참고하세요! -## [과제 수행 및 제출 방법] -1. 현재 저장소를 로컬에 클론(Clone)합니다. -2. 자신의 본명으로 브랜치를 생성합니다.(구분 가능하도록 본명을 꼭 파스칼케이스로 표시하세요, git branch KDT0_이름) -3. 자신의 본명 브랜치에서 과제를 수행합니다. -4. 과제 수행이 완료되면, 자신의 본명 브랜치를 원격 저장소에 푸시(Push)합니다.(main 브랜치에 푸시하지 않도록 꼭 주의하세요, git push origin KDT0_이름) -5. 저장소에서 main 브랜치를 대상으로 Pull Request 생성하면, 과제 제출이 완료됩니다!(E.g, main <== KDT0_이름) -6. Pull Request 링크를 LMS로도 제출해 주셔야 합니다. -7. main 혹은 다른 사람의 브랜치로 절대 병합하지 않도록 주의하세요! -8. Pull Request에서 보이는 설명을 다른 사람들이 이해하기 쉽도록 꼼꼼하게 작성하세요! -9. Pull Request에서 과제 제출 후 절대 병합(Merge)하지 않도록 주의하세요! -10. 과제 수행 및 제출 과정에서 문제가 발생한 경우, 바로 담당 멘토나 강사에서 얘기하세요! +## 배포 주소 +https://velvety-puppy-c1029b.netlify.app/ ## [필수 요구사항] -- “AWS S3 / Firebase 같은 서비스”를 이용하여 사진을 관리할 수 있는 페이지를 구현하세요. -- 프로필 페이지를 개발하세요. -- 스크롤이 가능한 형태의 리스팅 페이지를 개발하세요. -- 전체 페이지 데스크탑-모바일 반응형 페이지를 개발하세요. -- 사진을 등록, 수정, 삭제가 가능해야 합니다. -- 유저 플로우를 제작하여 리드미에 추가하세요. -* CSS - * 애니메이션 구현 - * 상대수치 사용(rem, em) -* JavaScript - * DOM event 조작 +- [X] “AWS S3 / Firebase 같은 서비스”를 이용하여 사진을 관리할 수 있는 페이지를 구현하세요. +- [X] 프로필 페이지를 개발하세요. +- [X] 스크롤이 가능한 형태의 리스팅 페이지를 개발하세요. +- [X] 전체 페이지 데스크탑-모바일 반응형 페이지를 개발하세요. +- [X] 사진을 등록, 수정, 삭제가 가능해야 합니다. +- [X] 유저 플로우를 제작하여 리드미에 추가하세요. +- CSS + - [X] 애니메이션 구현 + - [X] 상대수치 사용(rem, em) +- JavaScript + - [X] DOM event 조작 ## [선택 요구사항] - 사진 관리 페이지와 관련된 기타 기능도 고려해 보세요. - 페이지가 보여지기 전에 로딩 애니메이션이 보이도록 만들어보세요. -- 직원을 등록, 수정, 삭제가 가능하게 해보세요. -- 직원 검색 기능을 추가해 보세요. +- [X] 직원을 등록, 수정, 삭제가 가능하게 해보세요. - infinity scroll 기능을 추가해 보세요. -- 사진을 편집할 수 있는 기능을 추가해 보세요. -- LocalStorage 사용 -## [화면 예시] -![111](https://github.com/KDT1-FE/Y_FE_JAVASCRIPT_PICTURE/assets/96465306/f1afed4b-547e-4289-8e83-2f0fa188cccb) -![222](https://github.com/KDT1-FE/Y_FE_JAVASCRIPT_PICTURE/assets/96465306/72f1ea35-8965-4050-9d0b-b9f27c933f64) +## 유저 플로우 +![user flow](./assets/images/flow%20chart.JPG) +## 화면 예시 +### 메인 페이지 +![메인 화면](./assets/images/enroll%20info.JPG) +- 회원 전체 정보 열람이 가능한 메인 페이지입니다. +- 좌측 상단의 등록 버튼을 통해 회원 신규 등록이 가능하고, 체크박스로 회원을 선택한 후 삭제할 수 있습니다. +- 회원 목록 영역 내에서 회원 번호를 선택해, 해당 회원의 프로필 페이지로 이동할 수 있습니다. +### 등록 페이지 +![등록 화면](./assets/images/enroll%20page.JPG) +- 회원 정보와, 사진 등록이 가능합니다. +- 삭제 버튼을 통해, 등록한 사진을 삭제할 수 있습니다. +- 회원 정보와 사진 등록을 완료한 뒤, 우측 상단의 등록 버튼을 통해 메인 페이지로 이동할 수 있습니다. -## [흐름] -![333](https://github.com/KDT1-FE/Y_FE_JAVASCRIPT_PICTURE/assets/96465306/44707a0e-6c5a-4d04-a6bd-58e46f02a9a9) +### 프로필 페이지 +![프로필 화면](./assets/images/detail.JPG) +- 등록한 회원의 정보를 열람할 수 있습니다. +- 등록된 정보는 수정할 수 없으며, 회원 정보 수정이 필요한 경우 우측 상단의 수정 버튼을 통해 수정 페이지로 진입합니다. +### 수정 페이지 +![수정 화면](./assets/images/update.JPG) +- 등록한 회원의 정보를 수정할 수 있습니다. +- 사진 하단의 삭제 버튼을 눌러 기존 등록된 사진을 삭제하고, 새로운 사진을 등록시킬 수 있습니다. +- 하단의 일지 영역 내에서 세션 추가 버튼을 통해 내용을 입력하고, 세션 저장 버튼을 통해 내용을 저장할 수 있습니다. +## 느낀 점 + +필수 기능을 먼저 빠르게 완성시켜 놓은 다음 이후 기능 구현을 진행했어야 했는데, 처음부터 기획을 너무 크게 잡고 진행해 속도도 나지 않았고, 목표로 한 기능들도 전부 구현하지 못해 스크립트 부분만 빠르게 진행하였고, css 스타일링 부분은 많이 진행하지 못했던 점이 아쉬웠습니다. + +현재 필수 기능 중 데스크탑-모바일 반응형 개발 부분은 미구현 상태입니다. +추후 리팩토링 진행하면서 구현 예정입니다. diff --git a/assets/images/detail.JPG b/assets/images/detail.JPG new file mode 100644 index 000000000..bdad558d0 Binary files /dev/null and b/assets/images/detail.JPG differ diff --git a/assets/images/enroll info.JPG b/assets/images/enroll info.JPG new file mode 100644 index 000000000..4b6b9732a Binary files /dev/null and b/assets/images/enroll info.JPG differ diff --git a/assets/images/enroll page.JPG b/assets/images/enroll page.JPG new file mode 100644 index 000000000..8352efb83 Binary files /dev/null and b/assets/images/enroll page.JPG differ diff --git a/assets/images/flow chart.JPG b/assets/images/flow chart.JPG new file mode 100644 index 000000000..dad182b1c Binary files /dev/null and b/assets/images/flow chart.JPG differ diff --git a/assets/images/index page.JPG b/assets/images/index page.JPG new file mode 100644 index 000000000..94513bbc4 Binary files /dev/null and b/assets/images/index page.JPG differ diff --git a/assets/images/update after.JPG b/assets/images/update after.JPG new file mode 100644 index 000000000..db28768c9 Binary files /dev/null and b/assets/images/update after.JPG differ diff --git a/assets/images/update.JPG b/assets/images/update.JPG new file mode 100644 index 000000000..3dcd05a3f Binary files /dev/null and b/assets/images/update.JPG differ diff --git a/firebase.json b/firebase.json new file mode 100644 index 000000000..e78293923 --- /dev/null +++ b/firebase.json @@ -0,0 +1,10 @@ +{ + "hosting": { + "public": "public", + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**" + ] + } +} diff --git a/public/404.html b/public/404.html new file mode 100644 index 000000000..829eda8fd --- /dev/null +++ b/public/404.html @@ -0,0 +1,33 @@ + + + + + + Page Not Found + + + + +
+

404

+

Page Not Found

+

The specified file was not found on this website. Please check the URL for mistakes and try again.

+

Why am I seeing this?

+

This page was generated by the Firebase Command-Line Interface. To modify it, edit the 404.html file in your project's configured public directory.

+
+ + diff --git a/public/css/detail.css b/public/css/detail.css new file mode 100644 index 000000000..3916521ae --- /dev/null +++ b/public/css/detail.css @@ -0,0 +1,56 @@ +.section__enroll--template > ul > li, div { + margin-bottom: 10px; +} + +.section__detail--pt_info { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 2rem; +} + +.section__detail--pt_list { + display: flex; + flex-direction: column; + background-color: lightblue; + width: 100%; + height: 100%; +} + +.section__detail--pt_template { + display: flex; + flex-direction: column; +} + +.section__detail--pt_template>ul { + display: grid; + list-style: none; + justify-content: space-between; + align-items: center; + text-align: center; + padding: 0 2rem; +} + +@media (max-width: 480px) { + .section__detail--pt_template>ul { + grid-template-columns: repeat(5, 1fr); + grid-template-rows: repeat(2, 1fr); + } +} + +@media (min-width: 481px) { + .section__detail--pt_template>ul { + grid-template-columns: 0.1fr 0.1fr 0.1fr 0.2fr 0.1fr 0.1fr 0.1fr 0.1fr; + } +} + +.section__detail--pt_template>ul>input { + text-align: center; +} + +.section__detail--pt_template>ul>input, +textarea { + width: 100%; + border: none; + resize: none; +} \ No newline at end of file diff --git a/public/css/enroll.css b/public/css/enroll.css new file mode 100644 index 000000000..20ae1b347 --- /dev/null +++ b/public/css/enroll.css @@ -0,0 +1,43 @@ +.section__enroll--nav { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 2rem; +} + +.section__enroll--article { + display: grid; + width: 100%; + padding: 0 2rem; +} + +@media (max-width: 480px) { + .section__enroll--article { + grid-template-rows: repeat(2, 0.3fr); + padding: 0; + justify-items: center; + } +} + +@media (min-width: 481px) { + .section__enroll--article { + grid-template-columns: 1fr 1fr; + } +} + +.section__enroll--template > ul { + display: flex; + flex-direction: column; + list-style: none; + margin: 0; + padding: 0; +} + +.section__enroll--image_upload { + display: flex; + flex-direction: column; +} + +.section__enroll--image_button { + display: flex; +} diff --git a/public/css/main.css b/public/css/main.css new file mode 100644 index 000000000..744bc0bb1 --- /dev/null +++ b/public/css/main.css @@ -0,0 +1,100 @@ +body { + margin: 0; + padding: 0; + height: 100%; + background-color: rgb(240, 240, 240); +} + +button { + border-radius: 10px; + margin-top: 1rem; + cursor: pointer; + transition: all 0.3s ease; + position: relative; + display: inline-block; + box-shadow: inset 2px 2px 2px 0px rgba(255, 255, 255, .5), + 7px 7px 20px 0px rgba(0, 0, 0, .1), + 4px 4px 5px 0px rgba(0, 0, 0, .1); + outline: none; +} + +button:after { + position: absolute; + content: " "; + top: 0; + left: 0; + z-index: -1; + width: 100%; + height: 100%; + transition: all 0.3s ease; + -webkit-transform: scale(.1); + transform: scale(.1); +} + +button:hover { + color: #fff; + border: none; + background: transparent; +} + +button:hover:after { + background: rgb(0, 3, 255); + background: linear-gradient(0deg, rgba(2, 126, 251, 1) 0%, rgba(0, 3, 255, 1)100%); + -webkit-transform: scale(1); + transform: scale(1); +} + +.section__customer--management { + display: flex; + flex-direction: column; +} + +.section__customer--nav { + display: flex; + justify-content: space-between; + padding: 0 2rem; +} + +.section__customer--search { + display: flex; +} + +.section__customer--list { + display: flex; + flex-direction: column; + background-color: lightblue; + width: 100%; + height: 100%; +} + +.section__customer--template { + display: flex; + flex-direction: column; +} + +.section__customer--template>ul { + display: grid; + list-style: none; + justify-content: space-between; + align-items: center; + text-align: center; + padding: 0 2rem; + justify-items: center; +} + +@media (max-width: 480px) { + .section__customer--template>ul { + grid-template-columns: repeat(5, 1fr); + grid-template-rows: repeat(2, 1fr); + } +} + +@media (min-width: 481px) { + .section__customer--template>ul { + grid-template-columns: 0.1fr 0.1fr 0.2fr 0.2fr 0.15fr 0.1fr 0.1fr 0.1fr 0.1fr; + } +} + +.section__customer--template>ul:nth-child(n+2)>li:nth-child(2) { + cursor: pointer; +} \ No newline at end of file diff --git a/public/css/update.css b/public/css/update.css new file mode 100644 index 000000000..849809530 --- /dev/null +++ b/public/css/update.css @@ -0,0 +1,19 @@ +/* .section__detail--pt_template>ul { + display: grid; + list-style: none; + justify-content: space-between; + align-items: center; + text-align: center; + padding: 0 2rem; + grid-template-columns: 0.1fr 0.1fr 0.1fr 0.2fr 0.1fr 0.1fr 0.1fr 0.1fr; +} */ + +.section__detail--pt_template>ul>input { + text-align: center; +} + +.section__detail--pt_template>ul>input, textarea { + width: 100%; + border: solid 1px black; + resize: none; +} \ No newline at end of file diff --git a/public/detail.html b/public/detail.html new file mode 100644 index 000000000..8c5c9faa9 --- /dev/null +++ b/public/detail.html @@ -0,0 +1,93 @@ + + + + + + + Document + + + + +
+
+ +
+
+
    +
  • + 이름 + +
  • +
  • + 연락처 + +
  • +
  • + 등록 기간 + + +
  • +
  • + PT 등록 여부 + +
  • +
    +
    + PT 잔여 세션 + +
    +
    + 담당 트레이너 + +
    +
    +
+
+
+

사진

+
+
+
+
+ +
+
+
+
    +
  • 세션 번호
  • +
  • 날짜
  • +
  • 부위
  • +
  • 내용
  • +
  • 중량
  • +
  • 횟수
  • +
  • 세트
  • +
  • 비고
  • +
+
+
+
+
+
+ + + + diff --git a/public/enroll.html b/public/enroll.html new file mode 100644 index 000000000..f4cce0cd8 --- /dev/null +++ b/public/enroll.html @@ -0,0 +1,102 @@ + + + + + + + Document + + + + +
+
+ +
+
+
    +
  • + 이름 + +
  • +
  • + 연락처 + +
  • +
  • + 등록 기간 + + +
  • +
  • + PT 등록 여부 + +
  • +
+
+
+ PT 잔여 세션 +
+ +
+
+
+ 담당 트레이너 +
+ +
+
+
+
+
+ 사진 +
+ +
+
+ +
+
+
+
+
+
+ + + + + + diff --git a/public/index.html b/public/index.html new file mode 100644 index 000000000..2ddf10d47 --- /dev/null +++ b/public/index.html @@ -0,0 +1,45 @@ + + + + + + + Document + + + +
+
+
+ +
+
+
+
+
    + +
  • 번호
  • +
  • 사진
  • +
  • 이름
  • +
  • 연락처
  • +
  • 회원권 기간
  • +
  • PT 등록 여부
  • +
  • 남은 세션
  • +
  • 담당 트레이너
  • +
+
+
+
+
+
+ + + + + + diff --git a/public/js/detail.js b/public/js/detail.js new file mode 100644 index 000000000..c4999c93c --- /dev/null +++ b/public/js/detail.js @@ -0,0 +1,99 @@ +import { readUserData, readPtData } from "./firebase.js"; + +const today = new Date(); +const year = today.getFullYear(); +const month = ("0" + (today.getMonth() + 1)).slice(-2); +const day = ("0" + today.getDate()).slice(-2); +const todayString = year + "-" + month + "-" + day; +const userIdx = document.createElement("div"); +const userName = document.getElementById("user_name"); +const userPhone = document.getElementById("user_phone"); +const startDate = document.getElementById("start_of_days"); +const endDate = document.getElementById("end_of_days"); +const isPt = document.getElementById("pt_check"); +const leftSession = document.getElementById("pt_session"); +const trainer = document.getElementById("pt_trainer"); +const imageFrame = document.getElementsByClassName("section__enroll--image")[0]; +readUserData().then((res) => { + userIdx.value = res.userIdx; + userName.value = res.username; + userPhone.value = res.phoneNumber; + startDate.value = res.startDate; + endDate.value = res.endDate; + if (res.leftSessionNumber || res.trainerName) { + isPt.checked = true; + } else isPt.checked = false; + leftSession.value = res.leftSessionNumber; + trainer.value = res.trainerName; + + const userImage = document.createElement("img"); + userImage.style = `width: 30vw; height: 30vh; background-size: cover`; + userImage.src = res.imagePath; + imageFrame.appendChild(userImage); + + readPtData(userIdx.value).then((res) => { + const ptArr = []; + if (res) { + for (let element in res) { + ptArr.push(res[element]); + } + } + + if (ptArr) { + console.log(ptArr); + ptArr.forEach((element) => { + let ptFrame = document.createElement("ul"); + let ptSessionId = document.createElement("input"); + let ptDate = document.createElement("input"); + let ptSubject = document.createElement("textarea"); + let ptWorkout = document.createElement("textarea"); + let ptWeight = document.createElement("textarea"); + let ptReps = document.createElement("textarea"); + let ptSets = document.createElement("textarea"); + let ptOther = document.createElement("textarea"); + + console.log(element); + ptSessionId.value = element.sessionIdx; + ptSessionId.disabled = true; + ptDate.value = todayString; + ptDate.disabled = true; + ptSubject.value = element.subject; + ptSubject.disabled = true; + ptWorkout.value = element.workout; + ptWorkout.rows = "10"; + ptWorkout.disabled = true; + ptWeight.value = element.weight; + ptWeight.rows = "10"; + ptWeight.disabled = true; + ptReps.value = element.reps; + ptReps.rows = "10"; + ptReps.disabled = true; + ptSets.value = element.sets; + ptSets.rows = "10"; + ptSets.disabled = true; + ptOther.value = element.other; + ptOther.rows = "10"; + ptOther.disabled = true; + + ptFrame.append( + ptSessionId, + ptDate, + ptSubject, + ptWorkout, + ptWeight, + ptReps, + ptSets, + ptOther + ); + document + .getElementsByClassName("section__detail--pt_template")[0] + .appendChild(ptFrame); + }); + } + }); +}); + +const updateButton = document.getElementById("go_update"); +updateButton.addEventListener("click", function (e) { + window.location.href = `update.html?number=${userIdx.value}`; +}); diff --git a/public/js/enroll.js b/public/js/enroll.js new file mode 100644 index 000000000..b5878e33f --- /dev/null +++ b/public/js/enroll.js @@ -0,0 +1,101 @@ +import { writeUserData, readUserData, userCount } from "./firebase.js"; + +window.onload = function () { + const pt = document.getElementsByClassName("section__enroll--is_pt")[0]; + const ptInfo = document.getElementsByClassName( + "section__enroll--pt_check" + )[0]; + + if (!pt.checked) { + ptInfo.style.display = "none"; + } else { + ptInfo.style.display = "block"; + } + + readUserData(); + const customerNum = document.getElementById("customer_number"); +}; + +const submitButton = document.getElementById("enroll_submit"); +submitButton.addEventListener("click", function (e) { + const name = document.getElementsByClassName("section__enroll--name")[0]; + const phone = document.getElementsByClassName("section__enroll--phone")[0]; + const startDay = document.getElementsByClassName( + "section__enroll--start_day" + )[0]; + const endDay = document.getElementsByClassName("section__enroll--end_day")[0]; + + const profileImage = document.getElementById("image_upload").files[0]; + const pt = document.getElementsByClassName("section__enroll--is_pt")[0]; + + if (pt.checked) { + try { + const sessionList = document.getElementById("pt_session"); + const trainerList = document.getElementById("pt_trainer"); + writeUserData( + userCount, + name.value, + phone.value, + startDay.value, + endDay.value, + profileImage?.msg, + sessionList.value, + sessionList.value, + trainerList.value + ); + } catch (err) { + console.log(err); + } + } else { + try { + writeUserData( + userCount, + name.value, + phone.value, + startDay.value, + endDay.value, + profileImage?.msg, + "", + "", + "" + ); + } catch (err) { + console.log(err); + } + } +}); + +const isPt = document.getElementsByClassName("section__enroll--is_pt")[0]; +isPt.addEventListener("click", function (e) { + const pt = document.getElementsByClassName("section__enroll--is_pt")[0]; + const ptInfo = document.getElementsByClassName( + "section__enroll--pt_check" + )[0]; + + if (!pt.checked) { + ptInfo.style.display = "none"; + } else { + ptInfo.style.display = "block"; + } + + const sessionList = document.getElementById("pt_session"); + if (sessionList.childNodes.length < 200) { + for (let i = 1; i < 201; i++) { + let session = document.createElement("option"); + session.value = i; + session.innerText = i; + sessionList.appendChild(session); + } + } + + const trainerList = document.getElementById("pt_trainer"); + const employee = ["홍길동", "김철수"]; + if (trainerList.childNodes.length < 5) { + employee.forEach(function (em) { + let trainer = document.createElement("option"); + trainer.value = em; + trainer.innerText = em; + trainerList.appendChild(trainer); + }); + } +}); diff --git a/public/js/firebase.js b/public/js/firebase.js new file mode 100644 index 000000000..b3e100db8 --- /dev/null +++ b/public/js/firebase.js @@ -0,0 +1,242 @@ +// Import the functions you need from the SDKs you need +import { initializeApp } from "https://www.gstatic.com/firebasejs/10.1.0/firebase-app.js"; +import { + getDatabase, + ref, + set, + get, + child, +} from "https://www.gstatic.com/firebasejs/10.1.0/firebase-database.js"; +import * as storageModule from "https://www.gstatic.com/firebasejs/10.1.0/firebase-storage.js"; + +// TODO: Add SDKs for Firebase products that you want to use +// https://firebase.google.com/docs/web/setup#available-libraries + +// Your web app's Firebase configuration +// For Firebase JS SDK v7.20.0 and later, measurementId is optional +const firebaseConfig = { + apiKey: "AIzaSyCa8XH8OjhbUUgIHcoSd4xWEUFkGfnuIdM", + authDomain: "nhj-js-homework.firebaseapp.com", + projectId: "nhj-js-homework", + storageBucket: "nhj-js-homework.appspot.com", + messagingSenderId: "741149984145", + appId: "1:741149984145:web:7ac61b0622986fec214630", + measurementId: "G-LWFHL30P81", + databaseURL: "https://nhj-js-homework-default-rtdb.firebaseio.com", + storageBucket: "gs://nhj-js-homework.appspot.com", +}; + +// Initialize Firebase +const app = initializeApp(firebaseConfig); +const database = getDatabase(app); +const storage = storageModule.getStorage(app); +// const storageRef = storageModule.ref(storage); +export let userCount; +export let ptCount; + +function writeUserData( + userId, + name, + phone, + start, + end, + image, + session, + leftSession, + trainer +) { + const db = getDatabase(); + try { + set(ref(db, "users/" + userId), { + userIdx: userId, + username: name, + phoneNumber: phone, + startDate: start, + endDate: end, + imagePath: image, + sessionNumber: session, + leftSessionNumber: leftSession, + trainerName: trainer, + }); + console.log("user data sent to database"); + } catch (err) { + console.log(err); + } +} + +function readUserData() { + return new Promise((resolve) => { + const dbRef = ref(getDatabase()); + // const customerNum = document.getElementById("customer_number"); + get(child(dbRef, "users/")) + .then((snapshot) => { + if (snapshot.exists()) { + if (window.location.pathname === "/index.html") { + displayUserData(snapshot.val()); + } + userCount = snapshot.val().length; + if ( + window.location.pathname.includes("/detail.html") || + window.location.pathname.includes("/update.html") + ) { + const url = new URL(window.location.href); + const userNum = url.searchParams.get("number"); + resolve(snapshot.val()[userNum]); + } + } else { + userCount = 1; + console.log("user data is not exist."); + } + }) + .catch((error) => { + console.error(error); + }); + }); +} + +function deleteUserData(userId) { + const db = getDatabase(); + set(ref(db, "users/" + userId), null); + deletePtData(userId); + + console.log(`user ${userId} was deleted`); +} + +function displayUserData(arr) { + const userBox = document.getElementsByClassName( + "section__customer--template" + )[0]; + console.log(arr); + if (arr) { + for (let element in arr) { + const userInfoFrame = document.createElement("ul"); + const userSelectBox = document.createElement("input"); + const userIndex = document.createElement("li"); + const userImage = document.createElement("img"); + const userName = document.createElement("li"); + const userphoneNumber = document.createElement("li"); + const userDate = document.createElement("li"); + const userPtCheck = document.createElement("li"); + const userPtSession = document.createElement("li"); + const userTrainer = document.createElement("li"); + if (arr[element].sessionNumber === "") { + userPtCheck.innerHTML = "X"; + } else { + userPtCheck.innerHTML = "O"; + } + userInfoFrame.className = "section__customer--added"; + userSelectBox.type = "checkbox"; + userSelectBox.className = "section__customer--checkbox"; + userImage.src = arr[element].imagePath; + userImage.style.width = "5vw"; + userIndex.innerHTML = arr[element].userIdx; + userIndex.addEventListener("click", function (e) { + window.location.href = `detail.html?number=${arr[element].userIdx}`; + }); + userName.innerHTML = arr[element].username; + userphoneNumber.innerHTML = arr[element].phoneNumber; + userDate.innerHTML = `${arr[element].startDate} ~ ${arr[element].endDate}`; + userPtSession.innerHTML = + arr[element].sessionNumber !== "" + ? `${arr[element].leftSessionNumber} / ${arr[element].sessionNumber}` + : "-"; + userTrainer.innerHTML = + arr[element].trainerName !== "" ? arr[element].trainerName : "-"; + + userInfoFrame.append( + userSelectBox, + userIndex, + userImage, + userName, + userphoneNumber, + userDate, + userPtCheck, + userPtSession, + userTrainer + ); + userBox.append(userInfoFrame); + } + } +} + +function writePtData( + userId, + sessionId, + date, + subject, + workout, + weight, + reps, + sets, + other +) { + const db = getDatabase(); + try { + set(ref(db, `user/${userId}/pt/` + sessionId), { + sessionIdx: sessionId, + date: date, + subject: subject, + workout: workout, + weight: weight, + reps: reps, + sets: sets, + other: other, + }); + console.log("pt session data sent to database"); + } catch (err) { + console.log(err); + } +} + +function readPtData(userId) { + return new Promise((resolve) => { + const dbRef = ref(getDatabase()); + get(child(dbRef, `user/${userId}/pt/`)) + .then((snapshot) => { + if (snapshot.exists()) { + console.log(snapshot.val()); + ptCount = snapshot.val().length; + resolve(snapshot.val()); + } else { + ptCount = 1; + resolve(ptCount); + console.log("pt session data is not exist."); + } + }) + .catch((error) => { + console.error(error); + }); + }); +} + +function deletePtData(userId) { + const db = getDatabase(); + set(ref(db, `user/${userId}/pt/`), null); + + console.log(`user ${userId} session info was deleted`); +} + +function uploadImageData(image, imageName) { + return new Promise((resolve) => { + const st = storageModule.getStorage(); + const storageRef = storageModule.ref(st, `image/${imageName}`); + console.log(image, imageName); + storageModule.uploadBytes(storageRef, image).then((snapshot) => { + storageModule.getDownloadURL(snapshot.ref).then((url) => { + console.log("url: ", url); + image.msg = url; + resolve(image.msg); + }); + }); + console.log("image sent to storage"); + }); +} + +export { + writeUserData, + readUserData, + deleteUserData, + uploadImageData, + writePtData, + readPtData, +}; diff --git a/public/js/image.js b/public/js/image.js new file mode 100644 index 000000000..67c5fe2dc --- /dev/null +++ b/public/js/image.js @@ -0,0 +1,44 @@ +import { uploadImageData } from "./firebase.js"; + +const parent = document.getElementById("image_location"); +const child = document.getElementsByClassName("imageFrame"); +const imageFile = document.getElementById("image_upload"); +if (imageFile) { + imageFile.addEventListener("change", function (e) { + while (child.length > 0) { + parent.removeChild(child[0]); + } + const selectedImage = e.target.files[0]; + const imageReader = new FileReader(); + imageReader.readAsDataURL(selectedImage); + + imageReader.onload = function () { + const imageFrame = document.createElement("img"); + imageFrame.style = `width: 30vw; height: 30vh; background-size: cover`; + imageFrame.className = "imageFrame"; + imageFrame.src = URL.createObjectURL(selectedImage); + const targetImage = document.getElementById("image_upload"); + uploadImageData(targetImage.files[0], targetImage.files[0].name).then( + (res) => { + console.log(res); + imageFrame.src = res; + console.log(imageFrame); + } + ); + console.log(imageFrame); + document.getElementById("image_location").appendChild(imageFrame); + }; + }); +} + +const imageForDelete = document.getElementsByClassName( + "section__enroll--image_delete" +)[0]; + +if (imageForDelete) { + imageForDelete.addEventListener("click", function (e) { + if (child.length > 0) { + parent.removeChild(child[0]); + } + }); +} diff --git a/public/js/index.js b/public/js/index.js new file mode 100644 index 000000000..724f741de --- /dev/null +++ b/public/js/index.js @@ -0,0 +1,27 @@ +import { readUserData, deleteUserData } from "./firebase.js"; + +readUserData(); +let deleteArr = []; +document.addEventListener("click", function (e) { + console.log(e.target); + const clickTarget = e.target; + if (clickTarget.classList.contains("section__customer--checkbox")) { + if (deleteArr.indexOf(clickTarget.nextSibling.innerHTML) === -1) { + deleteArr.push(clickTarget.nextSibling.innerHTML); + } else { + deleteArr.pop(clickTarget.nextSibling.innerHTML); + } + } +}); + +const deleteButton = document.getElementById("delete_customer_button"); +deleteButton.addEventListener("click", function (e) { + if (deleteArr.length === 0) { + alert("삭제할 회원이 없습니다."); + } else { + deleteArr.forEach((element) => { + deleteUserData(element); + }); + window.location.reload(); + } +}); diff --git a/public/js/update.js b/public/js/update.js new file mode 100644 index 000000000..7fe6f856d --- /dev/null +++ b/public/js/update.js @@ -0,0 +1,229 @@ +import { + writeUserData, + readUserData, + writePtData, + readPtData, +} from "./firebase.js"; + +const today = new Date(); +const year = today.getFullYear(); +const month = ("0" + (today.getMonth() + 1)).slice(-2); +const day = ("0" + today.getDate()).slice(-2); +const todayString = year + "-" + month + "-" + day; +let ptFrame = document.createElement("ul"); +let ptSessionId = document.createElement("input"); +let ptDate = document.createElement("input"); +let ptSubject = document.createElement("textarea"); +let ptWorkout = document.createElement("textarea"); +let ptWeight = document.createElement("textarea"); +let ptReps = document.createElement("textarea"); +let ptSets = document.createElement("textarea"); +let ptOther = document.createElement("textarea"); + +const imageFrame = document.createElement("img"); +const imageDeleteButton = document.createElement("button"); +const updateButton = document.getElementById("update_button"); + +const userIdx = document.createElement("div"); +const userPtIdx = document.createElement("div"); +const userName = document.getElementById("user_name"); +const userPhone = document.getElementById("user_phone"); +const startDate = document.getElementById("start_of_days"); +const endDate = document.getElementById("end_of_days"); +const isPt = document.getElementById("pt_check"); +const leftSession = document.getElementById("pt_session"); +const trainer = document.getElementById("pt_trainer"); +const userImage = document.getElementsByClassName("section__enroll--image")[0]; +const profileImage = document.getElementById("image_upload").files[0]; +readUserData().then((res) => { + console.log(res); + + userIdx.value = res.userIdx; + userName.value = res.username; + userPhone.value = res.phoneNumber; + startDate.value = res.startDate; + endDate.value = res.endDate; + if (res.leftSessionNumber || res.trainerName) { + isPt.checked = true; + } else isPt.checked = false; + leftSession.value = res.leftSessionNumber; + trainer.value = res.trainerName; + + imageFrame.style = `width: 30vw; height: 30vh; background-size: cover`; + imageFrame.src = res.imagePath; + + imageDeleteButton.classList = "section__enroll--image_delete"; + imageDeleteButton.style = "display: block"; + imageDeleteButton.innerHTML = "삭제"; + userImage.append(imageFrame, imageDeleteButton); + + readPtData(userIdx.value).then((res) => { + console.log(res); + for (let i = 1; i < res; i++) { + let ptFrame = document.createElement("ul"); + let ptSessionId = document.createElement("input"); + let ptDate = document.createElement("input"); + let ptSubject = document.createElement("textarea"); + let ptWorkout = document.createElement("textarea"); + let ptWeight = document.createElement("textarea"); + let ptReps = document.createElement("textarea"); + let ptSets = document.createElement("textarea"); + let ptOther = document.createElement("textarea"); + + userPtIdx.value = res[i].sessionIdx; + ptSessionId.value = i; + ptSessionId.disabled = true; + ptDate.value = todayString; + ptDate.disabled = true; + ptWorkout.value = res[i].workout; + ptWorkout.rows = "10"; + ptWeight.value = res[i].weight; + ptWeight.rows = "10"; + ptReps.value = res[i].reps; + ptReps.rows = "10"; + ptSets.value = res[i].sets; + ptSets.rows = "10"; + ptOther.value = res[i].other; + ptOther.rows = "10"; + + ptFrame.append( + ptSessionId, + ptDate, + ptSubject, + ptWorkout, + ptWeight, + ptReps, + ptSets, + ptOther + ); + document + .getElementsByClassName("section__detail--pt_template")[0] + .appendChild(ptFrame); + } + }); +}); + +updateButton.addEventListener("click", function (e) { + let changedImage = document.getElementsByClassName("imageFrame")[0]; + let msg = ""; + + if (changedImage) { + msg = changedImage.src; + } else { + msg = imageFrame.src; + } + console.log(msg); + + if (isPt.checked) { + writeUserData( + userIdx.value, + userName.value, + userPhone.value, + startDate.value, + endDate.value, + msg, + leftSession.value, + leftSession.value, + trainer.value + ); + } else { + writeUserData( + userIdx.value, + userName.value, + userPhone.value, + startDate.value, + endDate.value, + msg, + "", + "", + "" + ); + } + + window.location.href = `detail.html?number=${userIdx.value}`; +}); + +imageDeleteButton.addEventListener("click", function (e) { + imageFrame.remove(); + const deleteTarget = document.getElementsByClassName("imageFrame")[0]; + if (deleteTarget) { + deleteTarget.remove(); + } +}); + +const ptAddButton = document.getElementById("pt_add"); +ptAddButton.addEventListener("click", function (e) { + let ptFrame = document.createElement("ul"); + let ptSessionId = document.createElement("input"); + let ptDate = document.createElement("input"); + let ptSubject = document.createElement("textarea"); + let ptWorkout = document.createElement("textarea"); + let ptWeight = document.createElement("textarea"); + let ptReps = document.createElement("textarea"); + let ptSets = document.createElement("textarea"); + let ptOther = document.createElement("textarea"); + ptSessionId.value = ++userPtIdx.value; + if (!Boolean(userPtIdx.value)) { + ptSessionId.value = 1; + } + ptSessionId.disabled = true; + ptDate.value = todayString; + ptDate.disabled = true; + ptWorkout.rows = "10"; + ptWeight.rows = "10"; + ptReps.rows = "10"; + ptSets.rows = "10"; + ptOther.rows = "10"; + + ptFrame.append( + ptSessionId, + ptDate, + ptSubject, + ptWorkout, + ptWeight, + ptReps, + ptSets, + ptOther + ); + document + .getElementsByClassName("section__detail--pt_template")[0] + .appendChild(ptFrame); +}); + +const ptSubmitButton = document.getElementById("pt_submit"); +ptSubmitButton.addEventListener("click", function () { + const container = document.getElementsByClassName( + "section__detail--pt_template" + )[0]; + let ptSessionId = document.createElement("input"); + let ptDate = document.createElement("input"); + let ptSubject = document.createElement("textarea"); + let ptWorkout = document.createElement("textarea"); + let ptWeight = document.createElement("textarea"); + let ptReps = document.createElement("textarea"); + let ptSets = document.createElement("textarea"); + let ptOther = document.createElement("textarea"); + const lastSession = container.lastChild.childNodes; + + ptSessionId.value = lastSession[0].value; + ptDate.value = lastSession[1].value; + ptSubject.value = lastSession[2].value; + ptWorkout.value = lastSession[3].value; + ptWeight.value = lastSession[4].value; + ptReps.value = lastSession[5].value; + ptSets.value = lastSession[6].value; + ptOther.value = lastSession[7].value; + + writePtData( + userIdx.value, + ++ptSessionId.value, + ptDate.value, + ptSubject.value, + ptWorkout.value, + ptWeight.value, + ptReps.value, + ptSets.value, + ptOther.value + ); + window.location.href = `detail.html?number=${userIdx.value}`; +}); diff --git a/public/update.html b/public/update.html new file mode 100644 index 000000000..022584b58 --- /dev/null +++ b/public/update.html @@ -0,0 +1,94 @@ + + + + + + + Document + + + + + +
+
+ +
+
+
    +
  • + 이름 + +
  • +
  • + 연락처 + +
  • +
  • + 등록 기간 + + +
  • +
  • + PT 등록 여부 + +
  • +
    +
    + PT 잔여 세션 + +
    +
    + 담당 트레이너 + +
    +
    +
+
+
+

사진

+
+ +
+
+
+
+
+
+
+ +
+
+
+
    +
  • 세션 번호
  • +
  • 날짜
  • +
  • 부위
  • +
  • 내용
  • +
  • 중량
  • +
  • 횟수
  • +
  • 세트
  • +
  • 비고
  • +
+
+
+
+
+
+ + + + +