Compare commits
799 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5421091175 | |||
| 81bd79ecac | |||
| 996c2c5728 | |||
| 605b43a866 | |||
| 3e5d9f2555 | |||
| e8bb1374d9 | |||
| 8be4c6d08c | |||
| b519451a0c | |||
| 04d03aa736 | |||
| c71fe2b452 | |||
| ee45ef810b | |||
| 63bd801281 | |||
| ddb1abbe70 | |||
| e7b9298a3b | |||
| ea69a5f308 | |||
| 8fe612824b | |||
| e02f90634b | |||
| c9284e800a | |||
| 3e26ba8bca | |||
| f53743a03e | |||
| d90682c710 | |||
| 5456dfd4c4 | |||
| df81b18194 | |||
| ed9bfff65d | |||
| 39d29567ce | |||
| 10897f633d | |||
| 41916bc451 | |||
| 06e6b615b1 | |||
| ce95cb2d66 | |||
| fe1747ea90 | |||
| f6edb107b2 | |||
| 28ae59b7e4 | |||
| 65b6a9b9dc | |||
| d0ce6516dc | |||
| 12c3b2e1cd | |||
| 3fc5bc6424 | |||
| f0fe21a14e | |||
| 9c19993bcc | |||
| 00fdb164af | |||
| 6e6ac8e440 | |||
| 8259112aac | |||
| b0f66eb9fd | |||
| c08f3db680 | |||
| de1a56285d | |||
| 1e78256886 | |||
| 37c54c4dd0 | |||
| 21c61e6128 | |||
| 32e3826c27 | |||
| 9d647525b3 | |||
| ed19b99bba | |||
| 9c38c8c03d | |||
| f200235ced | |||
| 92a93452bb | |||
| 5626e2d592 | |||
| a52c855ec2 | |||
| 16e5218f16 | |||
| 68e5abb088 | |||
| b52f05002b | |||
| e1bb5de959 | |||
| aaf1226ea0 | |||
| e06cb60bfb | |||
| 11eedf3a8b | |||
| f9a8b598da | |||
| b488e3399c | |||
| c82cd3be1e | |||
| fed0d99e64 | |||
| 24e05ff7fc | |||
| 9af90d3fd0 | |||
| 0b3d5c9ebb | |||
| c3f4832b30 | |||
| 4bd6e8c580 | |||
| 8e896114bf | |||
| f757997392 | |||
| 67b3c97806 | |||
| ee636e27ff | |||
| ff5055c411 | |||
| d5b1fcd74a | |||
| 5ace82986f | |||
| c989b6ddfe | |||
| f3f94e9b51 | |||
| 6c34cad1e7 | |||
| cb5268bf27 | |||
| 7b77b2195d | |||
| dad7e6b2eb | |||
| 146d1a5061 | |||
| ed626137cf | |||
| 224cedac65 | |||
| b5b41b4849 | |||
| d1ee296684 | |||
| 6cf3bcc658 | |||
| b20efef730 | |||
| 459ff88e9d | |||
| dcdbfed2a3 | |||
| d235b08fe3 | |||
| e5b9f2b75d | |||
| 563107e649 | |||
| 5545dbfad0 | |||
| 353128fa8e | |||
| 2e9fa7e9d0 | |||
| c0e5ec6e90 | |||
| 33adc4c819 | |||
| ebe81cd588 | |||
| c3ced21cce | |||
| a156050184 | |||
| 535069bb64 | |||
| e4603f4ca8 | |||
| cab481cd2f | |||
| 34d1384fb7 | |||
| 4b2fabd4b4 | |||
| 130fb89c5f | |||
| eeee4d3f45 | |||
| 7f2c8374a4 | |||
| e380dec152 | |||
| 58bf654651 | |||
| ead5370495 | |||
| ce8f8660f3 | |||
| 28fbf3a013 | |||
| 726cd78bd3 | |||
| 70a0e47d28 | |||
| d338cfaad4 | |||
| 1815b2834e | |||
| 27ac00bafb | |||
| 6a7024d5ac | |||
| 485ccece1e | |||
| 1fd45a00a3 | |||
| 36571b5cca | |||
| 7ad96db928 | |||
| 5ce9f108cd | |||
| 99bb737647 | |||
| e2ef540aac | |||
| 6e6119ffaf | |||
| 473edf7472 | |||
| 96b08352a0 | |||
| 7a45d19d2b | |||
| c73b08c1aa | |||
| b6e4347abb | |||
| adb9d2ccde | |||
| edd7f705ab | |||
| ea372ba0f2 | |||
| 779b722662 | |||
| 6bb8baf636 | |||
| 083f7b9c16 | |||
| 0eed896aec | |||
| e8ae224414 | |||
| fa3dcd8fd2 | |||
| 2c0c0a2632 | |||
| 501ee57430 | |||
| 0f6ec17fef | |||
| 112541275b | |||
| e08b879691 | |||
| 527351c232 | |||
| 0ed8da11e1 | |||
| f522e4389e | |||
| efb6527b9b | |||
| ba43bcddc7 | |||
| 3523cc95ee | |||
| c0d32cee12 | |||
| 3b6aa331db | |||
| fe7932e5ae | |||
| 05b64ac44c | |||
| 446e13ceba | |||
| 6570e28bbd | |||
| d146da7ab3 | |||
| ae06e730ad | |||
| f386b93dd2 | |||
| cebdf4d1d2 | |||
| e6738a1565 | |||
| ce9b8b6031 | |||
| 00eac45913 | |||
| 89719a8bbc | |||
| 901280363e | |||
| 6612f91047 | |||
| 5e7fabe1ce | |||
| e05aadd5c3 | |||
| 567a282dcf | |||
| 3eb5f6852f | |||
| 7ddab7d95c | |||
| 400340aaef | |||
| 5a43a2a9e1 | |||
| 69848dbe38 | |||
| ad40f73997 | |||
| fbdc460ee0 | |||
| e30c7f8daf | |||
| 9a87bc6627 | |||
| a2042e48e7 | |||
| cc02119938 | |||
| b2affbd87b | |||
| 0526286554 | |||
| 2b5e024bd0 | |||
| ed74d6f882 | |||
| ff2225a47b | |||
| 23832d2c4f | |||
| 655bce3fca | |||
| 1c33d5f7cf | |||
| 3737e34f32 | |||
| 36644308b8 | |||
| 080deea1e5 | |||
| a0caba4009 | |||
| 3c1deffbf1 | |||
| c07482e340 | |||
| cc80821658 | |||
| b0cbafdf44 | |||
| 6869085f6d | |||
| 9f8e61069c | |||
| 0b6b8451d1 | |||
| 17041758cb | |||
| ddfbd344f6 | |||
| 64d750fb9e | |||
| ebe9f62a8f | |||
| fd8cb20f52 | |||
| 7526059543 | |||
| d0bd5103cf | |||
| c9a3ae62ce | |||
| 7d2ca2bad3 | |||
| ab59d8872d | |||
| 4da821ce79 | |||
| 501af4b3f6 | |||
| 3c61032cf0 | |||
| af4e3207b4 | |||
| 3b835a4461 | |||
| f5a1fce6ac | |||
| 604b030045 | |||
| 9857a2363f | |||
| 892084cd41 | |||
| 47fca4b73a | |||
| d1c865dbd8 | |||
| f35b9d2037 | |||
| a4e039706d | |||
| 13f4790a36 | |||
| 829b1476d6 | |||
| 5c579cb592 | |||
| 2464d4b6bc | |||
| cb6729aa77 | |||
| d396fcc83a | |||
| d888c173f4 | |||
| 9d0f25984e | |||
| f2550a2df7 | |||
| 8f034b61de | |||
| 53ccf11d87 | |||
| fcfae5408b | |||
| 370e58494c | |||
| 9d5fbedb2c | |||
| cf7d4fc6bc | |||
| a960426a6d | |||
| 87862a26df | |||
| c29681cb7c | |||
| f01af4813e | |||
| de9a4f7b38 | |||
| b394f5fa5d | |||
| 9d9c777c93 | |||
| bddf254005 | |||
| 1a90223e22 | |||
| b963814067 | |||
| 921030d6c0 | |||
| 80e03c29e9 | |||
| 6cb252e031 | |||
| bfbb31ce25 | |||
| 849e0a5b18 | |||
| 9f497b83d5 | |||
| 344bdca41c | |||
| a05780ee39 | |||
| f7ac5e669f | |||
| b28ec325b8 | |||
| 6a6bfa3e39 | |||
| 753c990fc6 | |||
| 8069a54d1a | |||
| 9e2e58d45c | |||
| e7c59003cf | |||
| 8c435db886 | |||
| 2d41de8568 | |||
| a4a5096eb8 | |||
| d7128d7ddc | |||
| e06b23e73a | |||
| 90aefa56c2 | |||
| 6ceae61685 | |||
| d8033ec4ef | |||
| b4b9a0f5c4 | |||
| d4933d9535 | |||
| 024c34753c | |||
| d348f0d618 | |||
| 4662d0b30d | |||
| e6b873b861 | |||
| 88d0f8a222 | |||
| 15b94ea080 | |||
| e4218c708e | |||
| 772aa99c21 | |||
| e1c6729d04 | |||
| 4bd910fe6b | |||
| fe1b554dce | |||
| a75b4509a0 | |||
| e36330bcc2 | |||
| 51b36943ef | |||
| 78f80b4d7b | |||
| 65beb482c2 | |||
| ec7cab4b98 | |||
| 2089bd5c76 | |||
| 36cfa25d09 | |||
| 2394319605 | |||
| fb002efaec | |||
| 4b49371b08 | |||
| b5261ff528 | |||
| 61f03f4208 | |||
| d140bfeb38 | |||
| edb1ba680a | |||
| b3f927a46f | |||
| 288b8b1f51 | |||
| 416eb4129c | |||
| 613f0e755f | |||
| ed8562f95b | |||
| c95775194d | |||
| 783b65b5e9 | |||
| 38fef5c514 | |||
| e6286c97e4 | |||
| 55a2979814 | |||
| b5dc00eb7b | |||
| 813c085e3b | |||
| 550688a99e | |||
| 061e756237 | |||
| d6091fb496 | |||
| 52221edbee | |||
| 4cf4347611 | |||
| 60c9fa9b6f | |||
| 80c48533d7 | |||
| 3dfd5d2c89 | |||
| ba4118be38 | |||
| 9967eab3c5 | |||
| 861a0bf45f | |||
| 1b7089a694 | |||
| d6e345b2f3 | |||
| d720b08ccb | |||
| b773d04e4d | |||
| bd247c9ebd | |||
| e08c0f3605 | |||
| f86fcfe3d8 | |||
| 6629cd8156 | |||
| 5a29559ee7 | |||
| eab5e57e4b | |||
| 90ce3b1e6d | |||
| 97a438ac39 | |||
| a804655113 | |||
| 079cc18f5f | |||
| 18abd46de6 | |||
| 4728107d9a | |||
| 52f5c361d2 | |||
| efcd8002d5 | |||
| 2d9017bd5d | |||
| 7637ffd11c | |||
| b7fa1c403e | |||
| 48936e7150 | |||
| 3dcd837a9e | |||
| a859e045cd | |||
| 3a4637bc1a | |||
| a230f02005 | |||
| 3c4e06a84e | |||
| 0c8b1b5fe5 | |||
| 74b4de0543 | |||
| 730a61cddb | |||
| df7f3604f9 | |||
| 15e74aab9f | |||
| 7dd7071a0a | |||
| 8393f22ea6 | |||
| 985ed33346 | |||
| c357846ecf | |||
| 7685f304bf | |||
| 327d9d05c4 | |||
| f577733522 | |||
| 2a82a3758e | |||
| 80f7ef2da4 | |||
| 1ac0b286a9 | |||
| 20805afd31 | |||
| 47376ff7b7 | |||
| a787a1f870 | |||
| 2ca49a9566 | |||
| a4961638f2 | |||
| 583ab9480f | |||
| 73bf25904f | |||
| 5206050f6a | |||
| 5ca4abd2ac | |||
| 9bfc3ac023 | |||
| 088ad46a2f | |||
| d115add2ea | |||
| 9cdb2889d5 | |||
| 5cd1391ade | |||
| e74e915060 | |||
| e94f20ef78 | |||
| 25a335f2f0 | |||
| 26d243f658 | |||
| 3c0702022d | |||
| 9bfe4fb198 | |||
| 90b56c0471 | |||
| 28bb8e5299 | |||
| a18accb39c | |||
| 092b6cb655 | |||
| 24d733b4f7 | |||
| e3170e07dd | |||
| bda41ff48b | |||
| bf9be45efd | |||
| 323fe4b2c1 | |||
| 81938e714d | |||
| 6ab1b74342 | |||
| 1bedb3e467 | |||
| b1cd82c346 | |||
| a8df08e2f2 | |||
| 6b2a99caee | |||
| fbaf665ce9 | |||
| 4cfd8bde6f | |||
| b6e1a8b864 | |||
| 80eeb91f79 | |||
| 0063ef68f5 | |||
| eb6d281332 | |||
| ff0bb50414 | |||
| fb528ebc84 | |||
| a0504ec5fb | |||
| e40110a038 | |||
| 7512ed04e2 | |||
| 5c23dc39bf | |||
| 5488844845 | |||
| 33670ee1d6 | |||
| f569559f56 | |||
| d4083e4701 | |||
| ee808cffb2 | |||
| 99f1c4d117 | |||
| a54e85d359 | |||
| d10d03e6bb | |||
| 1d959f88f2 | |||
| 31d566a9c7 | |||
| 127e5e9d8d | |||
| c57b1402e9 | |||
| 3c759d3572 | |||
| 51deea06b8 | |||
| b9ba409c99 | |||
| 77d1f9954e | |||
| a3ad2c0030 | |||
| bc95306a15 | |||
| 45efd6b556 | |||
| 1ddbc65e14 | |||
| da90a3283a | |||
| efaf7ef6dd | |||
| 9999cc3417 | |||
| f931c25a9e | |||
| 0ac6abb5b5 | |||
| 79b8223c8c | |||
| 0633ece7ba | |||
| a474f0740f | |||
| 65e2ab90d2 | |||
| a7d31d6f4d | |||
| 042394d87d | |||
| 9d2fefe4ed | |||
| 3a08038da5 | |||
| 4cfad7bbca | |||
| cf8f8086d7 | |||
| 36f7d5698b | |||
| b0fd71ee0f | |||
| 0f8fe8cfd8 | |||
| c0e209ab67 | |||
| 6c091c3fac | |||
| 8a7b425e90 | |||
| 7ee7ab7e90 | |||
| ae603ba41d | |||
| 58c36dbf2d | |||
| d70ab851aa | |||
| de57d33a17 | |||
| 3caa419579 | |||
| fd9bc060cc | |||
| d705f062ed | |||
| a15a2ad831 | |||
| 4372c7a1e5 | |||
| d0dd09cce6 | |||
| db5670ffe2 | |||
| dd6e2cdf4b | |||
| 154fe260dc | |||
| 583e568085 | |||
| 3a137d4282 | |||
| 9c47f93e17 | |||
| 2b585216da | |||
| 77be2fd0c9 | |||
| 96ccc64eae | |||
| 9e9527686f | |||
| 6b0cb02afc | |||
| 4f5b03cdff | |||
| 63042e0e83 | |||
| 35ef8f28c0 | |||
| a9c3d382cf | |||
| de45ba36c6 | |||
| 7b227fb1f5 | |||
| b2e75da6f8 | |||
| 7aaf059e55 | |||
| 608283a6e6 | |||
| 9235571dcb | |||
| 5e806b6c64 | |||
| 989d215ef8 | |||
| 9daacb05d6 | |||
| b152cb5aea | |||
| 9ec2bf5cb6 | |||
| b8b18d5403 | |||
| cfc895b5dd | |||
| 287170ac96 | |||
| 6b636d0af3 | |||
| bd0e394d8a | |||
| 7f3764ae67 | |||
| 7363e9133b | |||
| 4d17137922 | |||
| fa24a9b292 | |||
| 4d637240aa | |||
| 2b617226f6 | |||
| 988440f5fd | |||
| 9d0d9f04ff | |||
| ab76048563 | |||
| 62e8f483c9 | |||
| 0ab872a2db | |||
| ed38d28fc5 | |||
| 2368f3f520 | |||
| 7a861a77d1 | |||
| f21bbadb5b | |||
| beab21d889 | |||
| c77ec3c9b0 | |||
| d8c289a6a8 | |||
| 77ba7c5f94 | |||
| 39baa0ab66 | |||
| 1c05c16041 | |||
| 62d13d66e5 | |||
| 1db0fab8e1 | |||
| 7e39a35997 | |||
| 8f97f706f0 | |||
| f5a6e86c61 | |||
| 9eeee67f03 | |||
| 314407806e | |||
| 9b196e3106 | |||
| c380260645 | |||
| 06d620ecba | |||
| ba41a79caa | |||
| 0c443bc341 | |||
| 9db04e1f5b | |||
| 1be8ac03fe | |||
| dfaeb05bf4 | |||
| 0b0a94e98b | |||
| 8878c1c57a | |||
| afe458cefd | |||
| bf4fa0dd30 | |||
| 9407dab844 | |||
| e34cc49a4f | |||
| 1de11320fd | |||
| dffd974ba6 | |||
| 7f70c3951e | |||
| d8b66eda0d | |||
| 42ad13bb93 | |||
| 1bc5a9c2c8 | |||
| c3517cdced | |||
| baf8c7cea0 | |||
| 3d4d90e46b | |||
| c46cddcdaf | |||
| c5e631064a | |||
| e5bdbe0bc8 | |||
| 14e216d448 | |||
| 1a7d811e8a | |||
| af478d49bc | |||
| 902665f0af | |||
| c042ae0ef7 | |||
| 988f179f14 | |||
| 77ad925b02 | |||
| d1a6aef77f | |||
| 2daa191b90 | |||
| b02dcb5baf | |||
| acc007ca81 | |||
| 142f673a17 | |||
| 40725cef90 | |||
| 389d2f4fac | |||
| d70d27299c | |||
| a6b8a7f555 | |||
| 518e5e75dc | |||
| 91b056274e | |||
| ce9dbdfb1c | |||
| 878335ef6d | |||
| 064979dd90 | |||
| 87d283763b | |||
| 5ae3750c3f | |||
| ebbb380c71 | |||
| f430471cd4 | |||
| 4bca554c4f | |||
| 61f547494b | |||
| 3c74d6e809 | |||
| 8045f38eac | |||
| 94dd549943 | |||
| ae47b6a838 | |||
| 9de0a394d7 | |||
| ce29a6438d | |||
| ef93e66968 | |||
| e32903baa5 | |||
| 753e76ccb1 | |||
| 7a523c50a0 | |||
| 7f5e323cd9 | |||
| b9e6c2ad21 | |||
| b42ad17f06 | |||
| ca8999a2d1 | |||
| bbe4a2eaa7 | |||
| ee6923c0a7 | |||
| b97ff9cc7c | |||
| 64f1c40594 | |||
| 13b55f50d7 | |||
| 2bbbcbae82 | |||
| 0b49b1a07b | |||
| eb08fffb3e | |||
| 10180345d3 | |||
| dbeb6bac94 | |||
| bdfa5d911c | |||
| cb71bd841c | |||
| 3d9a4fb063 | |||
| 736b83d8d3 | |||
| 20b7ac31f4 | |||
| 9a7f9c3993 | |||
| 13fb868117 | |||
| 360bd1d60f | |||
| 4a75e4de1e | |||
| 55247fde6b | |||
| 0b2dd9a546 | |||
| 69906acd22 | |||
| 985ef46648 | |||
| e0af97ac41 | |||
| 73b5f427cd | |||
| 9e1449e7fa | |||
| 007fdd2fac | |||
| dc62eac5e4 | |||
| b921d3eb46 | |||
| c50f6fe858 | |||
| 7e08ee6b6f | |||
| 29e1c2550f | |||
| a96f83dca5 | |||
| dc8687b794 | |||
| c216aec6c0 | |||
| 97bb5d3a75 | |||
| 956deb7dc4 | |||
| 512e5cf74f | |||
| 8951d83423 | |||
| 3a0e9c1938 | |||
| eb27aa74ab | |||
| 20bf564648 | |||
| bda3eb3302 | |||
| 3ad44318b1 | |||
| f703a2bd8f | |||
| 55c921c214 | |||
| 6188dc60a8 | |||
| fd4bad6477 | |||
| 7fa2bb1e10 | |||
| 3c5b4f4f24 | |||
| dbcb06cac8 | |||
| af417f1b3d | |||
| 7d918ad5ec | |||
| 569f7aac9f | |||
| 92df989fe3 | |||
| ba116d0919 | |||
| 6e553077d2 | |||
| d2a87c0daa | |||
| abfe12415f | |||
| 57dac37437 | |||
| 4df163eb30 | |||
| 3b5bb425a1 | |||
| bbe9970485 | |||
| 037424f103 | |||
| 6f4530c63c | |||
| 551b6af2d5 | |||
| 570c8482f6 | |||
| fe84754a0e | |||
| 8cc797f2ca | |||
| 825e658401 | |||
| 416758c178 | |||
| 398b2ab85a | |||
| 40e272ade1 | |||
| fb3809039f | |||
| 199bfb3ccb | |||
| 7f571b3917 | |||
| d4640944ee | |||
| 61891d7cd7 | |||
| 035137df0f | |||
| 7354b66453 | |||
| 652d3bac27 | |||
| b6c35ba444 | |||
| 9bb874ae2f | |||
| 7ce22883d2 | |||
| 2d6210c1e7 | |||
| 8f6c22d109 | |||
| 2c4bff2e7d | |||
| 4f66501811 | |||
| 3ad52a1e0b | |||
| b3c335fb25 | |||
| f1383d875e | |||
| 648517180a | |||
| 539e2d301f | |||
| dfe4a9aeef | |||
| ddae8c9b82 | |||
| 0f1762312f | |||
| b22c9f7fbd | |||
| daeb381f8b | |||
| f19d065c37 | |||
| 258ad73daa | |||
| d2eb717aab | |||
| 860b420608 | |||
| 3f18f70649 | |||
| b6ab0bfd2b | |||
| b17f156f38 | |||
| 9a333d58c4 | |||
| 58c34e6c47 | |||
| 1869fa4a07 | |||
| 8a16b8a47a | |||
| 212a2a1afc | |||
| e4c2b7fe2c | |||
| 788c58ecad | |||
| 4860438487 | |||
| ec8d55640d | |||
| 1ac2510ca3 | |||
| 53a7045e43 | |||
| b368f477ca | |||
| 87346e9ac5 | |||
| 8565f2142e | |||
| 24b957365f | |||
| 39a86b5a62 | |||
| 6febb3a654 | |||
| 409c396e68 | |||
| ecf6605eb5 | |||
| d88c50e3bb | |||
| a1f8618843 | |||
| d9820e49e0 | |||
| 8b876369c3 | |||
| 86aa81bdcc | |||
| 23c38245a3 | |||
| 48b8851657 | |||
| 2ed985518d | |||
| 9d06e89f5f | |||
| 3a49f735b6 | |||
| 69b1e087f9 | |||
| 980fc787bc | |||
| 39f33690dc | |||
| 0f81c9bab8 | |||
| ad98b0513a | |||
| f891479456 | |||
| fcc5bcad86 | |||
| 9c4364f082 | |||
| ee8de0330e | |||
| 95d906066f | |||
| b42d5abbb1 | |||
| 5f886f2a10 | |||
| bfcf73ae74 | |||
| 769d07440d | |||
| 435e6ad725 | |||
| f569ff237e | |||
| b85a4c9085 | |||
| b3b953196e | |||
| baa0cfa8c1 | |||
| 9b82a9cf59 | |||
| 39cd6cba2a | |||
| 7b1aee8a44 | |||
| e04465a751 | |||
| 09b586d94d | |||
| 48ac5c7d2c | |||
| 43d9a05bd6 | |||
| 68f44ab006 | |||
| 554c641c33 | |||
| 633e89628c | |||
| 5012b1e97a | |||
| 6d72c814d0 | |||
| 57d1e641a5 | |||
| 0b392222cf | |||
| e05f5c2b8f | |||
| 9a3bd880fb | |||
| 07b5e79d2b | |||
| c1e3c17504 | |||
| 354fefdae6 | |||
| ba4aba6a6d | |||
| f392062ece | |||
| 927eb81017 | |||
| ee4ef59ed3 | |||
| 063fb19dbd | |||
| 9169ee38ad | |||
| e68b61ce35 | |||
| 1f901b9a0a | |||
| 3abfff129c | |||
| 1267aa15b1 | |||
| 60e22554a8 | |||
| 72d98e057c | |||
| 0706fda67c | |||
| 1bdbd2f77d | |||
| 4daa99a020 | |||
| 89221a04ed | |||
| 765075e99b | |||
| 245f09b20f | |||
| d2649fdc16 | |||
| 2c08e9e68b | |||
| 5009409a51 | |||
| a8e4e739a2 | |||
| e1579a9d1d | |||
| 21510e7b71 | |||
| 59782cda43 | |||
| 6947ba6b33 | |||
| 71ad5427cb | |||
| c14de8e119 | |||
| 7e67bdcb45 | |||
| 5a0267e20f | |||
| aa3ef3456d | |||
| 03c01d842d | |||
| 502490ced1 |
@@ -1,3 +0,0 @@
|
||||
nextjs/node_modules/
|
||||
/node_modules/
|
||||
/nextjs/node_modules/
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"git.ignoreLimitWarning": true
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
/volume/
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
CLIENT=tt-app
|
||||
|
||||
DOCKERCOMPOSE := $(shell command -v docker-compose 2> /dev/null)
|
||||
USAGE := Usage: make ENV={prod|preprod|dev} {SYS=windows|linux} {docker-build|docker-start|docker-stop|docker-restart}
|
||||
|
||||
ifndef DOCKERCOMPOSE
|
||||
$(error docker-compose is not available)
|
||||
endif
|
||||
|
||||
ifndef ENV
|
||||
$(info Environment variable is not set)
|
||||
$(info $(USAGE))
|
||||
$(error Exiting)
|
||||
endif
|
||||
|
||||
SYS=linux
|
||||
|
||||
DC_OVERRIDE := $(shell test -e conf/docker-compose.override.yml && echo "--file conf/docker-compose.override.yml")
|
||||
DC_OVERRIDE_ENV := $(shell test -e conf/docker-compose.$(ENV).yml && echo "--file conf/docker-compose.$(ENV).yml")
|
||||
|
||||
ifeq ($(SYS),linux)
|
||||
DC=ENV=$(ENV) CLIENT=$(CLIENT) "$(DOCKERCOMPOSE)" --project-name "$(CLIENT)_$(ENV)" --file conf/docker-compose.yml $(DC_OVERRIDE) $(DC_OVERRIDE_ENV)
|
||||
else
|
||||
DC=ENV=$(ENV) CLIENT=$(CLIENT) "$(DOCKERCOMPOSE)" --project-name "$(CLIENT)_$(ENV)" --file conf/docker-compose.yml $(DC_OVERRIDE) $(DC_OVERRIDE_ENV)
|
||||
endif
|
||||
|
||||
|
||||
default:
|
||||
$(info $(USAGE))
|
||||
$(error Exiting)
|
||||
|
||||
docker-build:
|
||||
$(DC) build
|
||||
$(DC) up -d
|
||||
|
||||
docker-start:
|
||||
$(DC) start
|
||||
|
||||
docker-stop:
|
||||
$(DC) stop
|
||||
|
||||
docker-restart: docker-stop docker-start
|
||||
|
||||
docker-rm: docker-stop
|
||||
$(DC) rm
|
||||
|
||||
sys:
|
||||
@echo $(SYS)
|
||||
@echo $(DC)
|
||||
@@ -0,0 +1,28 @@
|
||||
## 1. Droits
|
||||
|
||||
mot de pass de depart (juste pour info, pas d'utilité)
|
||||
Jenkins : 8c628b7abfe242a397ac7fbedfd4de8c
|
||||
|
||||
Besoin d'effectuer la commande sudo chmod 666 /var/run/docker.sock dans le container Jenkins.
|
||||
docker exec -it --user root $(containerName) /bin/bash
|
||||
|
||||
docker exec -it -u 0 60344f0b414b bash
|
||||
|
||||
## 2. post install
|
||||
Installer yarn
|
||||
|
||||
## 3. run
|
||||
localhost:8080
|
||||
|
||||
>stop curent TTapp dev run to free 3000 port
|
||||
|
||||
### 1. login:password
|
||||
>sglatz:yVqSfBDRPp07
|
||||
|
||||
### 2. gitea password
|
||||
>tt-jenkins:
|
||||
|
||||
#### 2. As Kanye West said:
|
||||
|
||||
> We're living the future so
|
||||
> the present is our past.
|
||||
@@ -0,0 +1,17 @@
|
||||
version: '2'
|
||||
services:
|
||||
|
||||
jenkins:
|
||||
hostname: jenkins
|
||||
image: jenkinsci/blueocean
|
||||
ports:
|
||||
- '8080:8080'
|
||||
- '50000:50000'
|
||||
privileged: true
|
||||
volumes:
|
||||
# enable persistent volume (warning: make sure that the local jenkins_home folder is created)
|
||||
- '../volume/jenkins_data:/var/jenkins_home'
|
||||
- '/var/run/docker.sock:/var/run/docker.sock'
|
||||
restart: always
|
||||
volumes:
|
||||
jenkins_data:
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"cypress": "^3.4.1"
|
||||
}
|
||||
}
|
||||
+1217
File diff suppressed because it is too large
Load Diff
-25
@@ -1,25 +0,0 @@
|
||||
SERVER_URL=http://localhost:80
|
||||
MONGO_URI=mongodb://declic:declic42@ds115653.mlab.com:15653/next-auth
|
||||
FACEBOOK_ID=2332071840142634
|
||||
FACEBOOK_SECRET=afb8bbca72bd8c517c64f81e998e4f12
|
||||
PROD_FACEBOOK_ID=1800752833559014
|
||||
PROD_FACEBOOK_SECRET=454de729b1e58f506f94c8b50ca5c011
|
||||
TT_LINKEDIN_ID=86m6hegwyj8lbo
|
||||
TT_LINKEDIN_SECRET=LIOibqDszsP2vQSr
|
||||
LINKEDIN_ID=77k1m8qx7w6ygj
|
||||
LINKEDIN_SECRET=mbcnVjyy2vqAZz1B
|
||||
GOOGLE_ID=
|
||||
GOOGLE_SECRET=
|
||||
TWITTER_KEY=
|
||||
TWITTER_SECRET=
|
||||
EMAIL_FROM=contact@application.bzh
|
||||
EMAIL_SERVER=mail.gandi.net
|
||||
EMAIL_PORT=587
|
||||
EMAIL_SECURE=true
|
||||
EMAIL_USERNAME=noreply@application.bzh
|
||||
EMAIL_PASSWORD=PWApwaPWApwa56!!!
|
||||
FIREBASE_API_KEY=AAAAHlF5rsI:APA91bHXvjGDJRLzVvqmBDPM1Et96Bw0Iuvc7EGe9wt4a_lSJijDlbZ3RT96seLDK-QM6Mf8qQ4dH6MI9iWt1_d3uzKG2bxr56zltglZ3Z9xU8gz2iJeRGmlOd0YdV43IumIVe6dIOr-
|
||||
RECAPTCHA_VERIFY_URL=https://www.google.com/recaptcha/api/siteverify
|
||||
RECAPTCHA_SECRET=6LcCvHcUAAAAAIG-_iR5AXqkwxINfgqxKZ_kG244
|
||||
MJ_APIKEY_PUBLIC=355697fac93fca865660734b4fdffaeb
|
||||
MJ_APIKEY_PRIVATE=ddecf75321ca89c09e561857b13534c8
|
||||
+6
-2
@@ -1,4 +1,8 @@
|
||||
|
||||
/node_modules/
|
||||
.next/
|
||||
.gitignore
|
||||
.env
|
||||
ecosystem.config.js
|
||||
yarn-error.log
|
||||
robots.txt
|
||||
/out/
|
||||
yarn.lock
|
||||
@@ -0,0 +1,18 @@
|
||||
FROM keymetrics/pm2:8-alpine
|
||||
|
||||
ENV TERM=xterm
|
||||
|
||||
|
||||
# RUN pm2 -V
|
||||
RUN apk --no-cache update \
|
||||
&& apk --no-cache add g++ make bash zlib-dev libpng-dev \
|
||||
&& rm -fr /var/cache/apk/*
|
||||
|
||||
RUN apk add --no-cache curl
|
||||
|
||||
RUN apk add --no-cache bash
|
||||
|
||||
RUN apk add --no-cache yarn
|
||||
|
||||
CMD cd /home/app/nextjs && yarn cache dir && yarn cache clean && yarn install && yarn build && pm2 startOrReload ecosystem.config.js --env production --no-daemon
|
||||
|
||||
Vendored
+43
@@ -0,0 +1,43 @@
|
||||
pipeline {
|
||||
agent {
|
||||
docker {
|
||||
image 'mhart/alpine-node:latest'
|
||||
args '-p 3000:3000'
|
||||
}
|
||||
// dockerfile true
|
||||
}
|
||||
environment {
|
||||
CI = 'true'
|
||||
}
|
||||
stages {
|
||||
stage('Prepare') {
|
||||
steps {
|
||||
// withEnv(['PATH+NODE=/usr/local/bin/node']) {
|
||||
// echo 'Prepare step started ... '
|
||||
// sh 'echo prefix = ~/.node >> ~/.npmrc'
|
||||
// sh 'whoami'
|
||||
// sh 'chown -R node:node /usr/local/lib/node_modules'
|
||||
sh 'cd /var/jenkins_home/workspace/tt-app_app_Saga/nextjs/'
|
||||
sh 'yarn install'
|
||||
// }
|
||||
}
|
||||
}
|
||||
stage('Build') {
|
||||
steps {
|
||||
echo 'Build step started ... '
|
||||
sh '/var/jenkins_home/workspace/tt-app_app_Saga/nextjs/scripts/start.sh'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh '/var/jenkins_home/workspace/tt-app_app_Saga/nextjs/scripts/test.sh'
|
||||
}
|
||||
}
|
||||
stage('Response') {
|
||||
steps {
|
||||
echo 'Vous pouvez pull sur la production'
|
||||
sh '/var/jenkins_home/workspace/tt-app_app_Saga/nextjs/scripts/kill.sh'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
-2
@@ -2,16 +2,17 @@
|
||||
|
||||
## How to use
|
||||
|
||||
Download the example [or clone the repo](https://github.com/mui-org/material-ui):
|
||||
Download the example [or clone the repo](https://git.e-declic.net/talents-tube/app.git):
|
||||
|
||||
```bash
|
||||
git clone
|
||||
git clone
|
||||
```
|
||||
|
||||
Install it and run:
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
yarn build
|
||||
yarn dev
|
||||
```
|
||||
|
||||
@@ -24,3 +25,44 @@ yarn dev
|
||||
[Redux-Saga]
|
||||
https://redux-saga.js.org/docs/basics/ErrorHandling.html
|
||||
is a library that aims to make application side effect asynchronous things like data fetching and impure things like accessing the browser cache
|
||||
|
||||
## Integration
|
||||
|
||||
### Naming conventions
|
||||
|
||||
style classes name syntax : Camel case
|
||||
Try to name without too much precision
|
||||
|
||||
### Material UI
|
||||
|
||||
[components/atoms/theme.js] Const file
|
||||
[components/atoms/] Atomic components
|
||||
[components/organisms] General components
|
||||
[components/templates] Layouts components
|
||||
|
||||
## MEP
|
||||
|
||||
=================================
|
||||
Mise en PRE-production de l’application PWA
|
||||
=================================
|
||||
Aller dans la preproduction et git pull dans le répertoire /app (pas www)
|
||||
Possibilité de devoir git stash
|
||||
Attention de bien avoir le .env
|
||||
Restart docker preproduction (sudo make ENV=preprod docker-restart)
|
||||
sudo docker exec -it frontnginx.nginx bash
|
||||
nginx -t && nginx -s reload
|
||||
|
||||
## Test
|
||||
|
||||
### Cypress
|
||||
|
||||
[Gmail-tester]
|
||||
https://github.com/levz0r/gmail-tester
|
||||
|
||||
## Continuous Integration
|
||||
|
||||
### Jenkins
|
||||
|
||||
> in case of emergency
|
||||
> make docker-restart ENV=dev
|
||||
> adduser jenkins root
|
||||
|
||||
+47
-27
@@ -1,63 +1,83 @@
|
||||
import {
|
||||
FETCH_ADS_REQUEST,
|
||||
FETCH_ADS_SUCCESS,
|
||||
FETCH_ADS_FAILURE,
|
||||
FETCH_AD_REQUEST,
|
||||
FETCH_AD_SUCCESS,
|
||||
FETCH_AD_FAILURE,
|
||||
FETCH_PROMOTED_ADS_REQUEST,
|
||||
FETCH_PROMOTED_ADS_SUCCESS,
|
||||
FETCH_PROMOTED_ADS_FAILURE,
|
||||
FETCH_JOBS_REQUEST,
|
||||
FETCH_JOBS_SUCCESS,
|
||||
FETCH_JOBS_FAILURE,
|
||||
FETCH_JOB_REQUEST,
|
||||
FETCH_JOB_SUCCESS,
|
||||
FETCH_JOB_FAILURE,
|
||||
FETCH_EMPHASIS_JOBS_REQUEST,
|
||||
FETCH_EMPHASIS_JOBS_SUCCESS,
|
||||
FETCH_EMPHASIS_JOBS_FAILURE,
|
||||
CLEAR_AD,
|
||||
COUNT_AD_VIEW,
|
||||
TOGGLE_PROMOTED_FILTER_ADS
|
||||
} from '../types'
|
||||
|
||||
//Ads stat count
|
||||
|
||||
export const countAdViewRequest = (id) => ({
|
||||
type: COUNT_AD_VIEW,
|
||||
id
|
||||
});
|
||||
|
||||
//Is ads promoted?
|
||||
|
||||
export const togglePromotedFilterRequest = () => ({
|
||||
type: TOGGLE_PROMOTED_FILTER_ADS
|
||||
});
|
||||
|
||||
//Ads list
|
||||
|
||||
export const fetchAdsRequest = (payload) => ({
|
||||
type: FETCH_ADS_REQUEST,
|
||||
export const fetchJobsRequest = (payload) => ({
|
||||
type: FETCH_JOBS_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const fetchAdsSuccess = res => ({
|
||||
type: FETCH_ADS_SUCCESS,
|
||||
export const fetchJobsSuccess = res => ({
|
||||
type: FETCH_JOBS_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
export const fetchAdsFailure = res => ({
|
||||
type: FETCH_ADS_FAILURE,
|
||||
export const fetchJobsFailure = res => ({
|
||||
type: FETCH_JOBS_FAILURE,
|
||||
res
|
||||
});
|
||||
|
||||
//Ads list
|
||||
|
||||
export const fetchPromotedAdsRequest = (payload) => ({
|
||||
type: FETCH_PROMOTED_ADS_REQUEST,
|
||||
export const fetchEmphasisJobsRequest = (payload) => ({
|
||||
type: FETCH_EMPHASIS_JOBS_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const fetchPromotedAdsSuccess = res => ({
|
||||
type: FETCH_PROMOTED_ADS_SUCCESS,
|
||||
export const fetchEmphasisJobsSuccess = res => ({
|
||||
type: FETCH_EMPHASIS_JOBS_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
export const fetchPromotedAdsFailure = res => ({
|
||||
type: FETCH_PROMOTED_ADS_FAILURE,
|
||||
export const fetchEmphasisJobsFailure = res => ({
|
||||
type: FETCH_EMPHASIS_JOBS_FAILURE,
|
||||
res
|
||||
});
|
||||
|
||||
//Single ad
|
||||
|
||||
export const fetchAdRequest = payload => ({
|
||||
type: FETCH_AD_REQUEST,
|
||||
export const fetchJobRequest = payload => ({
|
||||
type: FETCH_JOB_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const fetchAdSuccess = res => ({
|
||||
type: FETCH_AD_SUCCESS,
|
||||
export const fetchJobSuccess = res => ({
|
||||
type: FETCH_JOB_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
export const fetchAdFailure = res => ({
|
||||
type: FETCH_AD_FAILURE,
|
||||
export const fetchJobFailure = res => ({
|
||||
type: FETCH_JOB_FAILURE,
|
||||
res
|
||||
});
|
||||
|
||||
//clear ad
|
||||
export const clearAd = res => ({
|
||||
type: CLEAR_AD
|
||||
});
|
||||
@@ -0,0 +1,94 @@
|
||||
import {
|
||||
POST_AD_ANSWER_REQUEST,
|
||||
POST_AD_ANSWER_FAILURE,
|
||||
POST_AD_ANSWER_SUCCESS,
|
||||
FETCH_JOBS_ANSWER_REQUEST,
|
||||
FETCH_JOBS_ANSWER_SUCCESS,
|
||||
FETCH_JOBS_ANSWER_FAILURE,
|
||||
FETCH_ANSWER_REQUEST,
|
||||
FETCH_ANSWER_SUCCESS,
|
||||
FETCH_ANSWER_FAILURE,
|
||||
POST_MESSAGE_ANSWER_REQUEST,
|
||||
POST_MESSAGE_ANSWER_FAILURE,
|
||||
POST_MESSAGE_ANSWER_SUCCESS,
|
||||
FETCH_ANSWER_MESAGES_REQUEST,
|
||||
FETCH_ANSWER_MESAGES_FAILURE,
|
||||
FETCH_ANSWER_MESAGES_SUCCESS,
|
||||
} from "../types";
|
||||
|
||||
export const postAdAnswerRequest = payload => ({
|
||||
type: POST_AD_ANSWER_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const postAdAnswerRequestFailure = errors => ({
|
||||
type: POST_AD_ANSWER_FAILURE,
|
||||
errors
|
||||
});
|
||||
|
||||
export const postAdAnswerRequestSuccess = res => ({
|
||||
type: POST_AD_ANSWER_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
export const postMessageAnswerRequest = payload => ({
|
||||
type: POST_MESSAGE_ANSWER_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const postMessageAnswerFailure = errors => ({
|
||||
type: POST_MESSAGE_ANSWER_FAILURE,
|
||||
errors
|
||||
});
|
||||
|
||||
export const postMessageAnswerSuccess = res => ({
|
||||
type: POST_MESSAGE_ANSWER_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
|
||||
export const fetchJobsAnsweredRequest = payload => ({
|
||||
type: FETCH_JOBS_ANSWER_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const fetchJobsAnsweredSuccess = res => ({
|
||||
type: FETCH_JOBS_ANSWER_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
|
||||
export const fetchJobsAnsweredFailure = errors => ({
|
||||
type: FETCH_JOBS_ANSWER_FAILURE,
|
||||
errors
|
||||
});
|
||||
|
||||
export const fetchAnswerRequest = payload => ({
|
||||
type: FETCH_ANSWER_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const fetchAnswerSuccess = res => ({
|
||||
type: FETCH_ANSWER_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
export const fetchAnswerFailure = errors => ({
|
||||
type: FETCH_ANSWER_FAILURE,
|
||||
errors
|
||||
});
|
||||
|
||||
export const fetchAnswerMessagesRequest = payload => ({
|
||||
type: FETCH_ANSWER_MESAGES_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const fetchAnswerMessagesSuccess = res => ({
|
||||
type: FETCH_ANSWER_MESAGES_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
export const fetchAnswerMessagesFailure = errors => ({
|
||||
type: FETCH_ANSWER_MESAGES_FAILURE,
|
||||
errors
|
||||
});
|
||||
+64
-13
@@ -2,22 +2,73 @@ import {
|
||||
FETCH_COMPANIES_REQUEST,
|
||||
FETCH_COMPANIES_SUCCESS,
|
||||
FETCH_COMPANIES_FAILURE,
|
||||
FETCH_COMPANY_REQUEST,
|
||||
FETCH_COMPANY_SUCCESS,
|
||||
FETCH_COMPANY_FAILURE,
|
||||
FETCH_EMPHASIS_COMPANIES_REQUEST,
|
||||
FETCH_EMPHASIS_COMPANIES_SUCCESS,
|
||||
FETCH_EMPHASIS_COMPANIES_FAILURE,
|
||||
CLEAR_COMPANY,
|
||||
COUNT_COMPANY_VIEW,
|
||||
} from '../types'
|
||||
|
||||
|
||||
//COMPANIES list
|
||||
|
||||
export const fetchCompaniesRequest = (payload) => ({
|
||||
type: FETCH_COMPANIES_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const fetchCompaniesSuccess = res => ({
|
||||
type: FETCH_COMPANIES_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
export const fetchCompaniesFailure = res => ({
|
||||
type: FETCH_COMPANIES_FAILURE,
|
||||
res
|
||||
});
|
||||
type: FETCH_COMPANIES_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const fetchCompaniesSuccess = res => ({
|
||||
type: FETCH_COMPANIES_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
export const fetchCompaniesFailure = res => ({
|
||||
type: FETCH_COMPANIES_FAILURE,
|
||||
res
|
||||
});
|
||||
|
||||
//COMPANY single
|
||||
export const countCompanyViewRequest = (id) => ({
|
||||
type: COUNT_COMPANY_VIEW,
|
||||
id
|
||||
});
|
||||
|
||||
export const fetchCompanyRequest = payload => ({
|
||||
type: FETCH_COMPANY_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const fetchCompanySuccess = res => ({
|
||||
type: FETCH_COMPANY_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
export const fetchCompanyFailure = res => ({
|
||||
type: FETCH_COMPANY_FAILURE,
|
||||
res
|
||||
});
|
||||
|
||||
//EMPHASIS 'aka mise en avant'
|
||||
|
||||
export const fetchEmphasisCompaniesRequest = (payload) => ({
|
||||
type: FETCH_EMPHASIS_COMPANIES_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const fetchEmphasisCompaniesSuccess = res => ({
|
||||
type: FETCH_EMPHASIS_COMPANIES_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
export const fetchEmphasisCompaniesFailure = res => ({
|
||||
type: FETCH_EMPHASIS_COMPANIES_FAILURE,
|
||||
res
|
||||
});
|
||||
|
||||
//clear ad
|
||||
export const clearCompany = res => ({
|
||||
type: CLEAR_COMPANY
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
import {
|
||||
UPLOAD_MEDIA_REQUEST,
|
||||
UPLOAD_MEDIA_FAILURE,
|
||||
UPLOAD_MEDIA_SUCCESS,
|
||||
UPLOAD_MEDIA_PRES_REQUEST,
|
||||
UPLOAD_MEDIA_PRES_FAILURE,
|
||||
UPLOAD_MEDIA_PRES_SUCCESS,
|
||||
|
||||
} from "../types";
|
||||
|
||||
export const uploadMedia = payload => ({
|
||||
type: UPLOAD_MEDIA_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const uploadMediaFailure = errors => ({
|
||||
type: UPLOAD_MEDIA_FAILURE,
|
||||
errors
|
||||
});
|
||||
|
||||
export const uploadMediaSuccess = res => ({
|
||||
type: UPLOAD_MEDIA_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
export const uploadMediaPres = payload => ({
|
||||
type: UPLOAD_MEDIA_PRES_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const uploadMediaPresFailure = errors => ({
|
||||
type: UPLOAD_MEDIA_PRES_FAILURE,
|
||||
errors
|
||||
});
|
||||
|
||||
export const uploadMediaPresSuccess = res => ({
|
||||
type: UPLOAD_MEDIA_PRES_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import {
|
||||
UPLOAD_MEDIA_CV_REQUEST,
|
||||
UPLOAD_MEDIA_CV_FAILURE,
|
||||
UPLOAD_MEDIA_CV_SUCCESS,
|
||||
|
||||
} from "../types";
|
||||
|
||||
|
||||
|
||||
export const uploadMediaCv = payload => ({
|
||||
type: UPLOAD_MEDIA_CV_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const uploadMediaCvFailure = errors => ({
|
||||
type: UPLOAD_MEDIA_CV_FAILURE,
|
||||
errors
|
||||
});
|
||||
|
||||
export const uploadMediaCvSuccess = res => ({
|
||||
type: UPLOAD_MEDIA_CV_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
|
||||
+127
-4
@@ -7,8 +7,45 @@ import {
|
||||
SUBSCRIBE_NEWSLETTER_FAILURE,
|
||||
REQUEST_REGISTER,
|
||||
REQUEST_REGISTER_SUCCESS,
|
||||
REQUEST_REGISTER_FAILURE
|
||||
REQUEST_REGISTER_FAILURE,
|
||||
ACCOUNT_CONFIRMATION_REQUEST,
|
||||
ACCOUNT_CONFIRMATION_SUCCESS,
|
||||
ACCOUNT_CONFIRMATION_FAILURE,
|
||||
SEND_CONFIRMATION_EMAIL_REQUEST,
|
||||
SEND_CONFIRMATION_EMAIL_SUCCESS,
|
||||
SEND_CONFIRMATION_EMAIL_FAILURE,
|
||||
UPDATE_USER_REQUEST,
|
||||
UPDATE_USER_SUCCESS,
|
||||
UPDATE_USER_FAILURE,
|
||||
RESET_PASSWORD_REQUEST,
|
||||
RESET_PASSWORD_SUCCESS,
|
||||
RESET_PASSWORD_FAILURE,
|
||||
SUBSCRIBE_USER_TO_PUSH_REQUEST,
|
||||
SUBSCRIBE_USER_TO_PUSH_SUCCESS,
|
||||
SUBSCRIBE_USER_TO_PUSH_FAILURE,
|
||||
FETCH_USER_SUBSCRIPTION_TO_PUSH_REQUEST,
|
||||
FETCH_USER_SUBSCRIPTION_TO_PUSH_SUCCESS,
|
||||
FETCH_USER_SUBSCRIPTION_TO_PUSH_FAILURE,
|
||||
UPDATE_USER_PICTURE_REQUEST,
|
||||
UPDATE_USER_PICTURE_SUCCESS,
|
||||
UPDATE_USER_PICTURE_FAILURE
|
||||
} from '../types'
|
||||
|
||||
|
||||
export const resetPasswordRequest = (payload) => ({
|
||||
type: RESET_PASSWORD_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const resetPasswordSuccess = () => ({
|
||||
type: RESET_PASSWORD_SUCCESS,
|
||||
});
|
||||
|
||||
export const resetPasswordFailure = (err) => ({
|
||||
type: RESET_PASSWORD_FAILURE,
|
||||
err
|
||||
});
|
||||
|
||||
export const fetchCurrentUserRequest = () => ({
|
||||
type: FETCH_CURRENT_USER_REQUEST
|
||||
});
|
||||
@@ -30,7 +67,7 @@ export const registerUserRequest = (payload) => ({
|
||||
|
||||
export const registerUserSuccess = () => ({
|
||||
type: REQUEST_REGISTER_SUCCESS,
|
||||
|
||||
|
||||
});
|
||||
|
||||
export const registerUserFailure = (err) => ({
|
||||
@@ -38,6 +75,20 @@ export const registerUserFailure = (err) => ({
|
||||
err
|
||||
});
|
||||
|
||||
export const sendConfirmationEmailRequest = (payload) => ({
|
||||
type: SEND_CONFIRMATION_EMAIL_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const sendConfirmationEmailSuccess = (payload) => ({
|
||||
type: SEND_CONFIRMATION_EMAIL_SUCCESS,
|
||||
});
|
||||
|
||||
export const sendConfirmationEmailFailure = (err) => ({
|
||||
type: SEND_CONFIRMATION_EMAIL_FAILURE,
|
||||
err
|
||||
});
|
||||
|
||||
export const subscribeToNewsletterRequest = (payload) => ({
|
||||
type: SUBSCRIBE_NEWSLETTER_REQUEST,
|
||||
payload
|
||||
@@ -47,6 +98,78 @@ export const subscribeToNewsletterSuccess = () => ({
|
||||
type: SUBSCRIBE_NEWSLETTER_SUCCESS,
|
||||
});
|
||||
|
||||
export const subscribeToNewsletterFailure = () => ({
|
||||
export const subscribeToNewsletterFailure = (err) => ({
|
||||
type: SUBSCRIBE_NEWSLETTER_FAILURE,
|
||||
});
|
||||
err
|
||||
});
|
||||
|
||||
export const requestConfirmationAccountRequest = (payload) => ({
|
||||
type: ACCOUNT_CONFIRMATION_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const requestConfirmationAccountSuccess = () => ({
|
||||
type: ACCOUNT_CONFIRMATION_SUCCESS,
|
||||
});
|
||||
|
||||
export const requestConfirmationAccountFailure = (err) => ({
|
||||
type: ACCOUNT_CONFIRMATION_FAILURE,
|
||||
err
|
||||
});
|
||||
|
||||
export const updateUserRequest = (payload) => ({
|
||||
type: UPDATE_USER_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const updateUserRequestSuccess = () => ({
|
||||
type: UPDATE_USER_SUCCESS,
|
||||
});
|
||||
|
||||
export const updateUserRequestFailure = (err) => ({
|
||||
type: UPDATE_USER_FAILURE,
|
||||
err
|
||||
});
|
||||
|
||||
export const subscribeUserToPushRequest = (payload) => ({
|
||||
type: SUBSCRIBE_USER_TO_PUSH_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const subscribeUserToPushSuccess = () => ({
|
||||
type: SUBSCRIBE_USER_TO_PUSH_SUCCESS,
|
||||
});
|
||||
|
||||
export const subscribeUserToPushFailure = (err) => ({
|
||||
type: SUBSCRIBE_USER_TO_PUSH_FAILURE,
|
||||
err
|
||||
});
|
||||
|
||||
export const fetchUserSubscriptionToPushRequest = (payload) => ({
|
||||
type: FETCH_USER_SUBSCRIPTION_TO_PUSH_REQUEST,
|
||||
payload
|
||||
});
|
||||
|
||||
export const fetchUserSubscriptionToPushSuccess = (res) => ({
|
||||
type: FETCH_USER_SUBSCRIPTION_TO_PUSH_SUCCESS,
|
||||
res
|
||||
});
|
||||
|
||||
export const fetchUserSubscriptionToPushFailure = (err) => ({
|
||||
type: FETCH_USER_SUBSCRIPTION_TO_PUSH_FAILURE,
|
||||
err
|
||||
});
|
||||
export const updateUserPictureRequest = (payload) => ({
|
||||
type: UPDATE_USER_PICTURE_REQUEST,
|
||||
payload
|
||||
})
|
||||
|
||||
export const updateUserPictureSuccess = (data) => ({
|
||||
type: UPDATE_USER_PICTURE_SUCCESS,
|
||||
data
|
||||
})
|
||||
|
||||
export const updateUserPictureFailure = (err) => ({
|
||||
type: UPDATE_USER_PICTURE_FAILURE,
|
||||
err
|
||||
})
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { withRouter } from 'next/router';
|
||||
import Link from 'next/link';
|
||||
import React, { Children } from 'react';
|
||||
|
||||
const ActiveLink = ({ router, children, ...props }) => {
|
||||
const child = Children.only(children);
|
||||
|
||||
let className = child.props.className || '';
|
||||
if (router.pathname === props.href && props.activeClassName) {
|
||||
className = `${className} ${props.activeClassName}`.trim();
|
||||
}
|
||||
|
||||
delete props.activeClassName;
|
||||
|
||||
return <Link {...props}>{React.cloneElement(child, { className })}</Link>;
|
||||
};
|
||||
|
||||
export default withRouter(ActiveLink);
|
||||
@@ -0,0 +1,94 @@
|
||||
import React, { Fragment } from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { Typography } from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import VideoVimeo from './VideoVimeo'
|
||||
import ChatCardMessage from './ChatCardMessage'
|
||||
import _ from "lodash"
|
||||
import Ar from "lodash/array"
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
card: {
|
||||
width: '100%',
|
||||
},
|
||||
userMessage: {
|
||||
display: 'flex',
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
messageSender: {
|
||||
fontSize: '0.9em',
|
||||
fontWeight: '300',
|
||||
color: theme.palette.primary.important,
|
||||
},
|
||||
messageContent: {
|
||||
fontWeight: '300',
|
||||
color: theme.palette.secondary.main,
|
||||
},
|
||||
messageDate: {
|
||||
fontSize: '0.8em',
|
||||
fontWeight: '300',
|
||||
color: theme.palette.primary.dark,
|
||||
padding: theme.spacing(2,0),
|
||||
},
|
||||
currentUserBubble: {
|
||||
background: theme.palette.primary.important,
|
||||
alignSelf: 'flex-end',
|
||||
},
|
||||
currentMessageSender: {
|
||||
color: theme.palette.primary.important,
|
||||
},
|
||||
otherUserBubble: {
|
||||
background: theme.palette.primary.main,
|
||||
alignSelf: 'flex-start',
|
||||
},
|
||||
otherMessageSender: {
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
avatar: {
|
||||
width: '2.5em',
|
||||
borderRadius: '50%',
|
||||
margin: theme.spacing(0,1),
|
||||
},
|
||||
videoVimeo: {
|
||||
[theme.breakpoints.up('md')]: {
|
||||
paddingBottom: '55%',
|
||||
},
|
||||
|
||||
},
|
||||
}));
|
||||
|
||||
export default function ChatCard(props) {
|
||||
const classes = useStyles();
|
||||
const userFirstName = useSelector(state => state.user.firstname);
|
||||
const userLastName = useSelector(state => state.user.lastname);
|
||||
const userPicture = useSelector(state => state.user.picture);
|
||||
const bubbleClass = (userFirstName === props.message.sender.firstname && userLastName === props.message.sender.lastname) ? classes.currentUserBubble : classes.otherUserBubble
|
||||
const messageSenderClass = (userFirstName === props.message.sender.firstname && userLastName === props.message.sender.lastname) ? classes.currentMessageSender : classes.otherMessageSender
|
||||
const bubbleSide = (userFirstName === props.message.sender.firstname && userLastName === props.message.sender.lastname) ? 'right' : 'left'
|
||||
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<ChatCardMessage side={bubbleSide} firstname={props.message.sender.firstname} lastname={props.message.sender.lastname} picture={userPicture}
|
||||
video={
|
||||
(props.message.video)
|
||||
? true :
|
||||
false}
|
||||
message={
|
||||
(props.message.video)
|
||||
? (<VideoVimeo classesOverride={ classes.videoVimeo } videoId={Ar.last(_.split(props.message.video.cdn_url, '/'))} />)
|
||||
: props.message.content}
|
||||
messageTexte = {props.message.content}
|
||||
messageSenderClass={messageSenderClass} bubbleClass={bubbleClass}/>
|
||||
|
||||
<Typography
|
||||
className={classes.messageDate}
|
||||
align="center"
|
||||
>
|
||||
Envoyé le {(new Date(props.message.c_time)).toLocaleDateString("fr-FR")} à {(new Date(props.message.c_time)).toLocaleTimeString("fr-FR")}
|
||||
</Typography>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import React from 'react'
|
||||
import { Typography } from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import _ from "lodash"
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
userMessageLeft: {
|
||||
display: 'flex',
|
||||
alignItems: 'flex-end',
|
||||
justifyContent: 'flex-start',
|
||||
},
|
||||
userMessageRight: {
|
||||
display: 'flex',
|
||||
alignItems: 'flex-end',
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
messageSender: {
|
||||
fontSize: '0.9em',
|
||||
fontWeight: '300',
|
||||
color: theme.palette.primary.important,
|
||||
},
|
||||
messageContent: {
|
||||
fontWeight: '300',
|
||||
color: theme.palette.secondary.main,
|
||||
},
|
||||
userBubble: {
|
||||
width: 'auto',
|
||||
borderRadius: '5px',
|
||||
padding: theme.spacing(2),
|
||||
wordBreak: 'break-word',
|
||||
},
|
||||
userBubbleVideo: {
|
||||
minWidth: '60vw',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
minWidth: '45vw',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
minWidth: '30vw',
|
||||
},
|
||||
},
|
||||
currentUserBubble: {
|
||||
background: theme.palette.primary.main,
|
||||
alignSelf: 'flex-end',
|
||||
},
|
||||
otherUserBubble: {
|
||||
background: theme.palette.primary.important,
|
||||
alignSelf: 'flex-start',
|
||||
},
|
||||
avatar: {
|
||||
width: '2.5em',
|
||||
height: '2.5em',
|
||||
borderRadius: '50%',
|
||||
margin: theme.spacing(0,1),
|
||||
},
|
||||
first: {
|
||||
order: 1,
|
||||
},
|
||||
second: {
|
||||
order: 2,
|
||||
}
|
||||
}));
|
||||
|
||||
export default function ChatCardMessage(props) {
|
||||
const { side, firstname, lastname, picture, message, messageTexte, video, messageSenderClass, bubbleClass } = props;
|
||||
const classes = useStyles();
|
||||
|
||||
const userBubble = (video) ? classes.userBubble +' '+ classes.userBubbleVideo : classes.userBubble
|
||||
return (
|
||||
<section className={(side==='left')? classes.userMessageLeft : classes.userMessageRight }>
|
||||
|
||||
{picture ?
|
||||
<img alt="talents-tube" src={`http://recruteur.talentstube.com/uploads/img/${picture}`} className={(side==='left')? classes.first+' '+classes.avatar : classes.second +' '+classes.avatar} />
|
||||
:
|
||||
<img alt="talents-tube" src='/static/images/default/account-avatar-default.svg' className={(side==='left')? classes.first +' '+ classes.avatar : classes.second+' '+classes.avatar } />
|
||||
}
|
||||
<div className={(side==='left')? classes.second : classes.first}>
|
||||
<Typography
|
||||
className={classes.messageSender +' '+ messageSenderClass}
|
||||
>
|
||||
{firstname + ' ' + lastname}
|
||||
</Typography>
|
||||
<div className={userBubble + ' ' + bubbleClass}>
|
||||
<Typography
|
||||
className={classes.messageContent}
|
||||
>
|
||||
{message}
|
||||
{messageTexte}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import React from "react";
|
||||
import { Slide } from "@material-ui/core";
|
||||
|
||||
function getScrollY(scroller) {
|
||||
return scroller.pageYOffset !== undefined
|
||||
? scroller.pageYOffset
|
||||
: scroller.scrollTop !== undefined
|
||||
? scroller.scrollTop
|
||||
: (document.documentElement || document.body.parentNode || document.body)
|
||||
.scrollTop;
|
||||
}
|
||||
|
||||
const useHideOnScroll = options => {
|
||||
const { threshold, scroller } = options;
|
||||
|
||||
const scrollRef = React.useRef();
|
||||
const [hide, setHide] = React.useState(false);
|
||||
|
||||
const handleScroll = React.useCallback(() => {
|
||||
const scrollY = getScrollY(scroller || window);
|
||||
const prevScrollY = scrollRef.current;
|
||||
scrollRef.current = scrollY;
|
||||
|
||||
setHide(
|
||||
scrollY < prevScrollY
|
||||
? false
|
||||
: scrollY > prevScrollY &&
|
||||
scrollY > (threshold != null ? threshold : 100)
|
||||
? true
|
||||
: false
|
||||
);
|
||||
}, [scroller, threshold]);
|
||||
|
||||
React.useEffect(() => {
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
return () => {
|
||||
window.removeEventListener("scroll", handleScroll);
|
||||
};
|
||||
}, [handleScroll]);
|
||||
|
||||
return hide;
|
||||
};
|
||||
|
||||
export default function HideOnScroll(props) {
|
||||
const { children, threshold, scroller, ...other } = props;
|
||||
|
||||
const hide = useHideOnScroll({ threshold, scroller });
|
||||
|
||||
return (
|
||||
<Slide appear={false} direction="down" in={!hide} {...other}>
|
||||
{children}
|
||||
</Slide>
|
||||
);
|
||||
}
|
||||
@@ -1,29 +1,58 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import SvgIcon from '@material-ui/core/SvgIcon';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import AssignmentIcon from '@material-ui/icons/Assignment';
|
||||
import RoomIcon from '@material-ui/icons/Room';
|
||||
import LocationOnIcon from '@material-ui/icons/LocationOn';
|
||||
import BusinessCenterIcon from '@material-ui/icons/BusinessCenter';
|
||||
import Business from '@material-ui/icons/Business';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import WatchLater from '@material-ui/icons/WatchLater';
|
||||
import Home from '@material-ui/icons/Home';
|
||||
import People from '@material-ui/icons/People';
|
||||
|
||||
const variantIcon = {
|
||||
assignment: AssignmentIcon,
|
||||
room: RoomIcon,
|
||||
location_on: LocationOnIcon,
|
||||
business_center: BusinessCenterIcon,
|
||||
business: Business,
|
||||
watch_later: WatchLater,
|
||||
home: Home,
|
||||
people: People,
|
||||
};
|
||||
|
||||
const styles = theme => ({
|
||||
card: {
|
||||
display: 'flex',
|
||||
position: 'relative',
|
||||
height: '60vh',
|
||||
width: '100%',
|
||||
root: {
|
||||
alignItems: 'flex-start',
|
||||
justifyContent: 'center',
|
||||
marginLeft: theme.spacing(3),
|
||||
marginRight: theme.spacing(3),
|
||||
},
|
||||
icon: {
|
||||
fontSize: '1.1em',
|
||||
},
|
||||
text: {
|
||||
fontSize: '0.9em',
|
||||
fontWeight: '200',
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
class IconText extends React.Component {
|
||||
|
||||
render() {
|
||||
|
||||
const { classes, variant, text } = this.props;
|
||||
const Icon = variantIcon[variant];
|
||||
return (
|
||||
<Fragment>
|
||||
<SvgIcon>
|
||||
<path d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z" />
|
||||
</SvgIcon>
|
||||
</Fragment>
|
||||
<Grid container className={classes.root}>
|
||||
<Grid item xs={1}>
|
||||
<Icon className={classes.icon} />
|
||||
</Grid>
|
||||
<Grid item xs={9}>
|
||||
<Typography className={classes.text}>{text}</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -31,6 +60,7 @@ class IconText extends React.Component {
|
||||
IconText.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
text: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default withStyles(styles, { withTheme: true })(IconText);
|
||||
@@ -0,0 +1,62 @@
|
||||
import React from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import AssignmentIcon from '@material-ui/icons/Assignment';
|
||||
import RoomIcon from '@material-ui/icons/Room';
|
||||
import LocationOnIcon from '@material-ui/icons/LocationOn';
|
||||
import HomeOnIcon from '@material-ui/icons/Home';
|
||||
import WatchLater from '@material-ui/icons/WatchLater';
|
||||
import BusinessCenterIcon from '@material-ui/icons/BusinessCenter';
|
||||
import People from '@material-ui/icons/People';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Business from '@material-ui/icons/Business';
|
||||
|
||||
const variantIcon = {
|
||||
assignment: AssignmentIcon,
|
||||
room: RoomIcon,
|
||||
location_on: LocationOnIcon,
|
||||
home: HomeOnIcon,
|
||||
watch_later: WatchLater,
|
||||
business_center: BusinessCenterIcon,
|
||||
business: Business,
|
||||
people: People,
|
||||
};
|
||||
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
marginRight: theme.spacing(1),
|
||||
},
|
||||
icon: {
|
||||
fontSize: '1.1em',
|
||||
},
|
||||
text: {
|
||||
fontSize: '0.9em',
|
||||
fontWeight: '200',
|
||||
},
|
||||
});
|
||||
|
||||
class IconTextInline extends React.Component {
|
||||
|
||||
render() {
|
||||
const { classes, variant, text } = this.props;
|
||||
const Icon = variantIcon[variant];
|
||||
return (
|
||||
<section className={classes.root}>
|
||||
<Icon className={classes.icon} />
|
||||
<Typography className={classes.text}>{text}</Typography>
|
||||
</section>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
IconTextInline.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
text: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default withStyles(styles, { withTheme: true })(IconTextInline);
|
||||
@@ -0,0 +1,39 @@
|
||||
import React from 'react'
|
||||
import { JobPostingJsonLd } from 'next-seo';
|
||||
|
||||
const JobPosting = props => {
|
||||
return (
|
||||
|
||||
<JobPostingJsonLd
|
||||
datePosted={props.job_date}
|
||||
description={props.job_description}
|
||||
hiringOrganization={{
|
||||
name: props.job_brand,
|
||||
sameAs: props.job_brand_link,
|
||||
}}
|
||||
jobLocation={{
|
||||
addressLocality: props.job_ville,
|
||||
addressRegion: props.job_dept,
|
||||
// postalCode: props.job_location,
|
||||
streetAddress: props.job_location,
|
||||
addressCountry: props.job_pays,
|
||||
|
||||
}}
|
||||
title={props.job_title}
|
||||
validThrough={props.job_date_fin}
|
||||
applicantLocationRequirements="FR"
|
||||
employmentType = {props.job_contract_type + ","+props.job_temps_type }
|
||||
/>
|
||||
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
JobPosting.propTypes = {
|
||||
// seo_title: PropTypes.string.isRequired,
|
||||
// seo_description: PropTypes.string.isRequired,
|
||||
// seo_url: PropTypes.string.isRequired,
|
||||
// image: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
export default JobPosting
|
||||
@@ -0,0 +1,113 @@
|
||||
import React, { Component, Fragment } from 'react'
|
||||
import { Snackbar } from '@material-ui/core';
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
|
||||
const styles = theme => ({
|
||||
close: {
|
||||
padding: theme.spacing.unit / 2,
|
||||
},
|
||||
});
|
||||
var EdeclicLib = null
|
||||
class Messager extends Component {
|
||||
state = {
|
||||
openSnack: false,
|
||||
title: '',
|
||||
body: '',
|
||||
link: '',
|
||||
tokenStopListener: null,
|
||||
messageStopListener: null,
|
||||
}
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
EdeclicLib = (await import('./firebase-client.js')).default
|
||||
if (!EdeclicLib.messaging)
|
||||
return
|
||||
this.setState({ tokenStopListener: EdeclicLib.messaging.onTokenRefresh(this.RefreshToken) })
|
||||
this.setState({ messageStopListener: EdeclicLib.messaging.onMessage(this.MessageReceiver) })
|
||||
|
||||
}
|
||||
componentWillUnmount() {
|
||||
|
||||
if (process.browser) {
|
||||
if (!EdeclicLib.messaging)
|
||||
return
|
||||
if (!!this.state.tokenStopListener)
|
||||
this.state.tokenStopListener();
|
||||
if (!!this.state.messageStopListener)
|
||||
this.state.messageStopListener();
|
||||
}
|
||||
}
|
||||
|
||||
RefreshToken = () => {
|
||||
EdeclicLib.messaging.getToken().then(function (refreshedToken) {
|
||||
console.info('Token refreshed.');
|
||||
// Indicate that the new Instance ID token has not yet been sent to the
|
||||
// app server.
|
||||
EdeclicLib.setTokenSentToServer(false);
|
||||
// Send Instance ID token to app server.
|
||||
EdeclicLib.sendTokenToServer(refreshedToken);
|
||||
|
||||
}).catch(function (err) {
|
||||
console.warning('Unable to retrieve refreshed token ', err);
|
||||
|
||||
});
|
||||
}
|
||||
// Handle incoming messages. Called when:
|
||||
// - a message is received while the app has focus
|
||||
// - the user clicks on an app notification created by a service worker
|
||||
// `messaging.setBackgroundMessageHandler` handler.
|
||||
MessageReceiver = (payload) => {
|
||||
console.info('Message received in Messager. ', payload);
|
||||
|
||||
this.setState({
|
||||
openSnack: true,
|
||||
title: payload.notification.title,
|
||||
body: payload.notification.body,
|
||||
link: payload.notification.click_action
|
||||
});
|
||||
|
||||
}
|
||||
handleClose = () => {
|
||||
this.setState({ openSnack: false });
|
||||
|
||||
}
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<Fragment>
|
||||
|
||||
<Snackbar
|
||||
anchorOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'right',
|
||||
}}
|
||||
open={this.state.openSnack}
|
||||
autoHideDuration={6000}
|
||||
onClose={this.handleClose}
|
||||
ContentProps={{
|
||||
'aria-describedby': 'message-id',
|
||||
}}
|
||||
message={<span id="message-id">{this.state.title + " : " + this.state.body}</span>}
|
||||
action={[
|
||||
<a href={this.state.link}>Voir</a>,
|
||||
<IconButton
|
||||
key="close"
|
||||
aria-label="Close"
|
||||
color="inherit"
|
||||
className={classes.close}
|
||||
onClick={this.handleClose}
|
||||
>
|
||||
<CloseIcon />
|
||||
</IconButton>,
|
||||
]}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
}
|
||||
export default withStyles(styles)(Messager);
|
||||
@@ -0,0 +1,36 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
const styles = theme => ({
|
||||
container: {
|
||||
padding: theme.spacing(0, 4),
|
||||
},
|
||||
text: {
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
fontSize: '1,2em',
|
||||
fontWeight: '500',
|
||||
color: theme.palette.primary.main,
|
||||
textAlign: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
function NoResult(props) {
|
||||
const { classes } = props;
|
||||
|
||||
return (
|
||||
<div className={ classes.container }>
|
||||
<Typography className={ classes.text }>
|
||||
{props.text}
|
||||
</Typography>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
NoResult.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
text: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default withStyles(styles)(NoResult)
|
||||
@@ -0,0 +1,47 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Head from 'next/head'
|
||||
|
||||
const OgHead = props => {
|
||||
return (
|
||||
<Head>
|
||||
<title key="title">{props.seo_title}</title>
|
||||
|
||||
<meta name="description" kenoindexy="description" content={props.seo_description} />
|
||||
<meta name="keywords" content={props.seo_key}/>
|
||||
<meta key="og:url" property="og:url" content={props.seo_url} />
|
||||
<meta key="og:type" property="og:type" content="article" />
|
||||
<meta key="og:title" property="og:title" content={props.seo_title} />
|
||||
<meta property="fb:app_id" content="1800752833559014" data-react-helmet="true"></meta>
|
||||
<meta
|
||||
key="og:description"
|
||||
property="og:description"
|
||||
content={props.seo_description}
|
||||
/>
|
||||
<meta name="keywords" content={props.seo_key}/>
|
||||
<meta key="og:image" property="og:image" content={props.image} />
|
||||
<meta key="og:image:width" property="og:image:width" content="355" />
|
||||
<meta key="og:image:height" property="og:image:height" content="200" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:site" content="@TalentsTube"/>
|
||||
<meta name="twitter:title" content={props.seo_title}/>
|
||||
<meta name="twitter:description" content={props.seo_description}/>
|
||||
<meta name="twitter:image" content={props.image}/>
|
||||
<meta name="robots" content="noindex, nofollow"></meta>
|
||||
{/* <meta httpEquiv='cache-control' content='no-store,no-cache'></meta>
|
||||
<meta httpEquiv='expires' content='0'></meta>
|
||||
<meta httpEquiv='pragma' content='no-cache'></meta> */}
|
||||
<link rel="canonical" href={ props.seo_url} />
|
||||
</Head>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
OgHead.propTypes = {
|
||||
// seo_title: PropTypes.string.isRequired,
|
||||
// seo_description: PropTypes.string.isRequired,
|
||||
// seo_url: PropTypes.string.isRequired,
|
||||
// image: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
export default OgHead
|
||||
@@ -0,0 +1,51 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100%',
|
||||
},
|
||||
start: {
|
||||
alignItems: 'flex-start',
|
||||
},
|
||||
center: {
|
||||
alignItems: 'center',
|
||||
},
|
||||
end: {
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
});
|
||||
|
||||
class RootContainer extends React.Component {
|
||||
|
||||
render() {
|
||||
const { classes, children, align } = this.props;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{(() => {
|
||||
switch(align) {
|
||||
case 'start':
|
||||
return <section className={classes.root + ' ' + classes.start}>{children}</section>;
|
||||
case 'center':
|
||||
return <section className={classes.root + ' ' + classes.center}>{children}</section>;
|
||||
case 'end':
|
||||
return <section className={classes.root + ' ' + classes.end}>{children}</section>;
|
||||
default:
|
||||
return <section className={classes.root}>{children}</section>;
|
||||
}
|
||||
})()}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RootContainer.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
export default withStyles(styles)(RootContainer);
|
||||
@@ -0,0 +1,129 @@
|
||||
import React from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import clsx from 'clsx';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import CardHeader from '@material-ui/core/CardHeader';
|
||||
import CardMedia from '@material-ui/core/CardMedia';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
import CardActions from '@material-ui/core/CardActions';
|
||||
import Collapse from '@material-ui/core/Collapse';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { red } from '@material-ui/core/colors';
|
||||
import FavoriteIcon from '@material-ui/icons/Favorite';
|
||||
import ShareIcon from '@material-ui/icons/Share';
|
||||
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
||||
import MoreVertIcon from '@material-ui/icons/MoreVert';
|
||||
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
card: {
|
||||
width: '100%',
|
||||
},
|
||||
media: {
|
||||
height: 0,
|
||||
paddingTop: '56.25%', // 16:9
|
||||
},
|
||||
expand: {
|
||||
transform: 'rotate(0deg)',
|
||||
transition: theme.transitions.create('transform', {
|
||||
duration: theme.transitions.duration.shortest,
|
||||
}),
|
||||
width: '0.7em',
|
||||
height: '0.7em',
|
||||
fill: theme.palette.primary.dark,
|
||||
},
|
||||
expandOpen: {
|
||||
transform: 'rotate(180deg)',
|
||||
width: '0.7em',
|
||||
height: '0.7em',
|
||||
fill: theme.palette.primary.dark,
|
||||
},
|
||||
rootCard: {
|
||||
boxShadow: 'none !important',
|
||||
},
|
||||
rootCardAction: {
|
||||
margin: theme.spacing(1,0),
|
||||
'& button': {
|
||||
padding: theme.spacing(2,0),
|
||||
borderRadius: 0,
|
||||
}
|
||||
},
|
||||
rootCardContent: {
|
||||
padding: 0 + '!important',
|
||||
},
|
||||
containerCollapse: {
|
||||
position: 'relative',
|
||||
'&:before': {
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
content: '""',
|
||||
background: 'linear-gradient(to top,rgba(255, 255, 255, 1) 8%, rgba(255, 255, 255, 0) 50%)',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
},
|
||||
containerCollapseDefault: {
|
||||
position: 'relative',
|
||||
'&:before': {
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
content: '""',
|
||||
background: ' rgba(255, 255, 255, 0)',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
},
|
||||
displayMore: {
|
||||
color: theme.palette.primary.dark,
|
||||
fontWeight: '600',
|
||||
fontSize: '0.8rem',
|
||||
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}));
|
||||
|
||||
export default function SimpleCollapse(props) {
|
||||
const classes = useStyles();
|
||||
const [expanded, setExpanded] = React.useState(true);
|
||||
|
||||
function handleExpandClick() {
|
||||
setExpanded(!expanded);
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className={classes.card} classes={{ root: classes.rootCard }}>
|
||||
<Collapse in={expanded} timeout="auto" collapsedHeight={isWidthUp('sm', props.width) ? '28vh' : '30vh'} className={clsx(classes.containerCollapse, {
|
||||
[classes.containerCollapseDefault]: expanded,
|
||||
})}>
|
||||
<CardContent classes={{ root: classes.rootCardContent }}>
|
||||
{props.children}
|
||||
</CardContent>
|
||||
</Collapse>
|
||||
|
||||
<CardActions disableSpacing classes={{ root: classes.rootCardAction }}>
|
||||
<IconButton
|
||||
onClick={handleExpandClick}
|
||||
aria-expanded={expanded}
|
||||
aria-label="Afficher plus "
|
||||
> <Typography className={classes.displayMore}>
|
||||
{(!expanded) ? 'Afficher plus' : 'Afficher moins'}
|
||||
</Typography>
|
||||
<ExpandMoreIcon className={clsx(classes.expand, {
|
||||
[classes.expandOpen]: expanded,
|
||||
})} />
|
||||
</IconButton>
|
||||
|
||||
</CardActions>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import Link from 'next/link';
|
||||
import clsx from 'clsx';
|
||||
import { loadCSS } from 'fg-loadcss';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { red } from '@material-ui/core/colors';
|
||||
import Icon from '@material-ui/core/Icon';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import ButtonGroup from '@material-ui/core/ButtonGroup';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
icon: {
|
||||
fontSize: '1em',
|
||||
},
|
||||
externalButton: {
|
||||
'& .MuiButtonGroup-groupedContained': {
|
||||
border: '0',
|
||||
},
|
||||
margin: theme.spacing(1,0),
|
||||
margin: theme.spacing(1,1.2),
|
||||
width: 'auto',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
minWidth: '20vw',
|
||||
width: '50%',
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
width: '45%',
|
||||
},
|
||||
},
|
||||
linkedinButton: {
|
||||
backgroundColor: theme.palette.authSocial.linkedin,
|
||||
padding: theme.spacing(1),
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.authSocial.linkedin,
|
||||
}
|
||||
},
|
||||
facebookButton: {
|
||||
backgroundColor: theme.palette.authSocial.facebook,
|
||||
padding: theme.spacing(1),
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.authSocial.facebook,
|
||||
}
|
||||
},
|
||||
linkedinIconButton: {
|
||||
backgroundColor: theme.palette.authSocial.linkedinDark,
|
||||
color: theme.palette.authSocial.linkedinDark,
|
||||
border: 0,
|
||||
},
|
||||
facebookIconButton: {
|
||||
backgroundColor: theme.palette.authSocial.facebookDark,
|
||||
color: theme.palette.authSocial.facebookDark,
|
||||
border: 0,
|
||||
},
|
||||
textButton: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
width: '100%',
|
||||
fontWeight: '400',
|
||||
color: theme.palette.secondary.main,
|
||||
textTransform: 'inherit',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
minWidth: '15vw',
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export default function SocialButtonsAuth(props) {
|
||||
const classes = useStyles();
|
||||
|
||||
React.useEffect(() => {
|
||||
loadCSS(
|
||||
'https://use.fontawesome.com/releases/v5.1.0/css/all.css',
|
||||
document.querySelector('#font-awesome-css'),
|
||||
);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<ButtonGroup variant="contained" onClick={props.linkedInAuth} className={classes.externalButton}>
|
||||
<Button className={classes.linkedinIconButton}>
|
||||
<Icon className={clsx(classes.icon, 'fab fa-linkedin-in')} color="secondary" />
|
||||
</Button>
|
||||
|
||||
<Button className={classes.textButton +' '+ classes.linkedinButton+ ' cypLinkedInConnexion'} >
|
||||
Connexion avec Linkedin
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<ButtonGroup variant="contained" onClick={props.facebookAuth} className={classes.externalButton}>
|
||||
<Button className={classes.facebookIconButton}>
|
||||
<Icon className={clsx(classes.icon, 'fab fa-facebook-f')} color="secondary" />
|
||||
</Button>
|
||||
|
||||
<Button className={classes.textButton +' '+ classes.facebookButton} >
|
||||
Connexion avec Facebook
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
export const payloadFromSubscription = function(subscription) {
|
||||
var key = subscription.getKey ? subscription.getKey('p256dh') : '';
|
||||
var auth = subscription.getKey ? subscription.getKey('auth') : '';
|
||||
// NOTE: p256dg and auth are encoded into std base64, NOT urlsafe base64
|
||||
return {
|
||||
endpoint: subscription.endpoint,
|
||||
keys: {
|
||||
p256dh: key ? btoa(String.fromCharCode.apply(null, new Uint8Array(key))) : '',
|
||||
auth: auth ? btoa(String.fromCharCode.apply(null, new Uint8Array(auth))) : ''
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const urlB64ToUint8Array= function(base64String) {
|
||||
const padding = '='.repeat((4 - base64String.length % 4) % 4)
|
||||
const base64 = (base64String + padding)
|
||||
.replace(/\-/g, '+')
|
||||
.replace(/_/g, '/')
|
||||
|
||||
const rawData = window.atob(base64)
|
||||
const outputArray = new Uint8Array(rawData.length)
|
||||
|
||||
for (let i = 0; i < rawData.length; ++i) {
|
||||
outputArray[i] = rawData.charCodeAt(i)
|
||||
}
|
||||
return outputArray
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
function redirect(params) {
|
||||
const { Router, ctx, location, status = 302 } = params
|
||||
|
||||
if (ctx.res) {
|
||||
// Seems to be the version used by zeit
|
||||
ctx.res.writeHead(status, {
|
||||
Location: location,
|
||||
// Add the content-type for SEO considerations
|
||||
'Content-Type': 'text/html; charset=utf-8',
|
||||
})
|
||||
ctx.res.end()
|
||||
return
|
||||
}
|
||||
|
||||
Router.replace(location)
|
||||
}
|
||||
|
||||
export default redirect
|
||||
@@ -0,0 +1,87 @@
|
||||
import React, { Fragment } from 'react'
|
||||
import { Typography } from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import _ from "lodash"
|
||||
import Ar from "lodash/array"
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
video: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'relative',
|
||||
paddingBottom: '56%', /* 16:9 58%*/
|
||||
'& iframe': {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 'calc(50% - 50vw)',
|
||||
width: '100vw',
|
||||
height: '100%',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'relative',
|
||||
paddingBottom: '36%', /* 16:9 */
|
||||
'& iframe': {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 'calc(50% - 32vw)',
|
||||
width: '64vw',
|
||||
height: '100%',
|
||||
},
|
||||
},
|
||||
},
|
||||
videoPresentation: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'relative',
|
||||
paddingBottom: '56%', /* 16:9 58%*/
|
||||
'& iframe': {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 'calc(50% - 50vw)',
|
||||
width: '100vw',
|
||||
height: '100%',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'relative',
|
||||
paddingBottom: '56.5%', /* 16:9 */
|
||||
'& iframe': {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 'calc(50% - 32vw)',
|
||||
width: '64vw',
|
||||
height: '100%',
|
||||
},
|
||||
},
|
||||
}
|
||||
}));
|
||||
|
||||
export default function VideoVimeo(props) {
|
||||
|
||||
const {videoId, title, options, classesOverride, autoplay} = props;
|
||||
const classes = useStyles();
|
||||
let className = classes.video;
|
||||
if (classesOverride) {
|
||||
className = classes.videoPresentation;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
<section className={className +' '+classesOverride}>
|
||||
<iframe className='player'
|
||||
src={"https://player.vimeo.com/video/"+ videoId + options+"?texttrack=fr&autoplay="+autoplay}
|
||||
frameBorder="0"
|
||||
title={title}
|
||||
webkitallowfullscreen="true" mozallowfullscreen="true" allowFullScreen></iframe>
|
||||
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
VideoVimeo.defaultProps = {
|
||||
options: "",
|
||||
};
|
||||
@@ -0,0 +1,177 @@
|
||||
import React, { Component, Fragment } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from "react-redux";
|
||||
import { subscribeUserToPushRequest } from '../../actions/user'
|
||||
import getConfig from 'next/config'
|
||||
|
||||
|
||||
import { urlB64ToUint8Array, payloadFromSubscription } from './Utility'
|
||||
|
||||
var swRegistration = null
|
||||
|
||||
const WebPushContext = React.createContext()
|
||||
|
||||
function WebPushConsumer(props) {
|
||||
return (
|
||||
<WebPushContext.Consumer {...props}>
|
||||
{context => {
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
`Webpush.Consumer cannot be rendered outside the Webpush component`,
|
||||
)
|
||||
}
|
||||
return props.children(context)
|
||||
}}
|
||||
</WebPushContext.Consumer>
|
||||
)
|
||||
}
|
||||
|
||||
const { publicRuntimeConfig } = getConfig()
|
||||
class WebPush extends Component {
|
||||
static Consumer = WebPushConsumer;
|
||||
|
||||
state = {
|
||||
on: false,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (swRegistration === null) {
|
||||
this.onRegisterServiceWorker()
|
||||
}
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
console.log("isUserSubscribedToPush ::: " + nextProps.isUserSubscribedToPush);
|
||||
if (this.props.subscriveUserEnabled != nextProps.subscriveUserEnabled && nextProps.subscriveUserEnabled) {
|
||||
this.onSubscribeUser()
|
||||
}
|
||||
if (!!nextProps.isUserSubscribedToPush) {
|
||||
this.setState({ on: true })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onUpdateSubscriptionOnServer = (subscription) => {
|
||||
console.log("onUpdateSubscriptionOnServer:", subscription)
|
||||
var payload = payloadFromSubscription(subscription)
|
||||
console.log("payload:", JSON.stringify(payload))
|
||||
this.setState({ subscription: subscription })
|
||||
|
||||
this.props.subscribeUserToPushRequest(payload);
|
||||
|
||||
this.setState(({ on }) => ({ on: !on }))
|
||||
}
|
||||
|
||||
onSubscriptionFailed = (error) => {
|
||||
console.log("onSubscriptionFailed:", error)
|
||||
this.setState(({ on }) => ({ on: false }))
|
||||
}
|
||||
|
||||
toggleSubscription = () => {
|
||||
console.log(this.state.on)
|
||||
if (!this.state.on) {
|
||||
this.onSubscribeUser()
|
||||
}
|
||||
else {
|
||||
this.onUnSubscribeUser()
|
||||
}
|
||||
}
|
||||
|
||||
onSubscribeUser = () => {
|
||||
if (swRegistration == null) {
|
||||
return
|
||||
}
|
||||
|
||||
swRegistration.pushManager.getSubscription()
|
||||
.then((subscription) => {
|
||||
var isSubscribed = !(subscription === null)
|
||||
if (isSubscribed) {
|
||||
this.onUpdateSubscriptionOnServer(subscription)
|
||||
} else {
|
||||
const applicationServerKey = urlB64ToUint8Array(publicRuntimeConfig.applicationServerPublicKey)
|
||||
swRegistration.pushManager.subscribe({
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: applicationServerKey
|
||||
})
|
||||
.then((subscription) => {
|
||||
console.log('User is subscribed.')
|
||||
if (this.onUpdateSubscriptionOnServer) {
|
||||
this.onUpdateSubscriptionOnServer(subscription)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('Failed to subscribe the user: ', err)
|
||||
if (onSubscribeFailed) {
|
||||
this.onSubscriptionFailed(err)
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onUnSubscribeUser = () => {
|
||||
swRegistration.pushManager.getSubscription()
|
||||
|
||||
.then((subscription) => {
|
||||
if (subscription) {
|
||||
|
||||
return subscription.unsubscribe();
|
||||
}
|
||||
})
|
||||
.then(() =>
|
||||
this.setState(({ on }) => ({ on: false })))
|
||||
//TODO: facultatif update DB
|
||||
// .then(() => {
|
||||
// return fetch(//, {
|
||||
// method: 'POST',
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json'
|
||||
// },
|
||||
// body: JSON.stringify(subscription)
|
||||
// })
|
||||
// .then((response) => {
|
||||
// if (!response.ok) {
|
||||
// throw new Error('Bad status code from server.');
|
||||
// }
|
||||
// ///TODO bind UI
|
||||
// return true;
|
||||
// })
|
||||
|
||||
// })
|
||||
.catch((err) => {
|
||||
console.error('Failed to unsubscribe the user.', err);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
onRegisterServiceWorker = () => {
|
||||
navigator.serviceWorker.register('/static/js/Edeclic-service-worker.js')
|
||||
.then(function (swReg) {
|
||||
console.info('Service Worker is registered', swReg);
|
||||
|
||||
swRegistration = swReg;
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<WebPushContext.Provider
|
||||
value={{ on: this.state.on, toggleSubscription: this.toggleSubscription }}
|
||||
{...this.props}
|
||||
/>)
|
||||
}
|
||||
}
|
||||
|
||||
WebPush.propTypes = {
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
isUserSubscribedToPush: state.user.isUserSubscribedToPush
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, { subscribeUserToPushRequest })(WebPush);
|
||||
@@ -0,0 +1,138 @@
|
||||
//var firebase = require("firebase");
|
||||
import firebase from "firebase/app"
|
||||
import 'firebase/database'
|
||||
import 'firebase/messaging'
|
||||
//based on
|
||||
//https://stackoverflow.com/questions/1479319/simplest-cleanest-way-to-implement-singleton-in-javascript
|
||||
class Singleton {
|
||||
// Properties & Methods
|
||||
messaging;
|
||||
fcmToken;
|
||||
|
||||
constructor() {
|
||||
console.log('firebase-client constructor')
|
||||
if (!Singleton.instance) {
|
||||
Singleton.instance = this
|
||||
}
|
||||
// Initialize object
|
||||
if (!firebase.messaging.isSupported()) {
|
||||
console.log('firebase.messaging not supported')
|
||||
return;
|
||||
}
|
||||
|
||||
let config = {
|
||||
apiKey: "AIzaSyArZab_4hUDgksQ4Dqdwv970JyRSlbGaKY",
|
||||
authDomain: "edeclicpwa.firebaseapp.com",
|
||||
databaseURL: "https://edeclicpwa.firebaseio.com",
|
||||
projectId: "edeclicpwa",
|
||||
storageBucket: "edeclicpwa.appspot.com",
|
||||
messagingSenderId: "130215947970"
|
||||
}
|
||||
firebase.initializeApp(config);
|
||||
|
||||
navigator.serviceWorker
|
||||
.register('/service-worker.js')
|
||||
.then((registration) => {
|
||||
firebase.messaging().useServiceWorker(registration);
|
||||
});
|
||||
this.messaging = firebase.messaging();
|
||||
this.messaging.usePublicVapidKey('BEiMSVYvblP5oKcIY7b90r-5xLk1QYDra1sSdZHdaynihcb3Hx9wdZdI9IUHmbqureB_-IpOFKpm7arBB93J3rk');
|
||||
console.log('FireBase Singleton Initialized')
|
||||
return Singleton.instance
|
||||
}
|
||||
|
||||
isSupported() {
|
||||
this.messaging.app.firebase_.messaging.isSupported()
|
||||
}
|
||||
|
||||
async requestPermission() {
|
||||
console.log('Requesting permission...');
|
||||
|
||||
return this.messaging.requestPermission().then(function () {
|
||||
console.log('Notification permission granted.');
|
||||
return true
|
||||
}).catch(function (err) {
|
||||
console.log('Unable to get permission to notify.', err);
|
||||
return false
|
||||
});
|
||||
}
|
||||
|
||||
async askForToken() {
|
||||
var res = await this.messaging.getToken().then(async (currentToken) => {
|
||||
if (currentToken) {
|
||||
console.log(currentToken)
|
||||
// this.fcmToken = currentToken;
|
||||
await this.sendTokenToServer(currentToken);
|
||||
return currentToken;
|
||||
}
|
||||
else {
|
||||
// Show permission request.
|
||||
console.log('No Instance ID token available. Request permission to generate one.');
|
||||
let hasPerm = await this.requestPermission()
|
||||
if (hasPerm)
|
||||
{
|
||||
debugger;
|
||||
return await this.askForToken()
|
||||
}
|
||||
else
|
||||
await this.setTokenSentToServer(false);
|
||||
}
|
||||
}).catch(async (err) => {
|
||||
console.log('An error occurred while retrieving token. ', err);
|
||||
// showToken('Error retrieving Instance ID token. ', err);
|
||||
await this.setTokenSentToServer(false);
|
||||
})
|
||||
console.log("Token : ")
|
||||
console.log(res);
|
||||
return res
|
||||
}
|
||||
|
||||
async deleteToken() {
|
||||
// Delete Instance ID token.
|
||||
// [START delete_token]
|
||||
this.messaging.getToken().then(async (currentToken) => {
|
||||
this.messaging.deleteToken(currentToken).then(async () => {
|
||||
console.log('Token deleted.');
|
||||
await this.setTokenSentToServer(false);
|
||||
// [START_EXCLUDE]
|
||||
// Once token is deleted update UI.
|
||||
//resetUI();
|
||||
// [END_EXCLUDE]
|
||||
}).catch((err) => {
|
||||
console.log('Unable to delete token. ', err);
|
||||
});
|
||||
// [END delete_token]
|
||||
}).catch((err) => {
|
||||
console.log('Error retrieving Instance ID token. ', err);
|
||||
//showToken('Error retrieving Instance ID token. ', err);
|
||||
});
|
||||
}
|
||||
|
||||
async sendTokenToServer(currentToken) {
|
||||
var tokenSent = await this.isTokenSentToServer()
|
||||
if (!tokenSent) {
|
||||
console.log('Sending token to server...');
|
||||
firebase.database().ref('subscription/' + currentToken).set({
|
||||
general: true
|
||||
});
|
||||
|
||||
this.setTokenSentToServer(true);
|
||||
} else {
|
||||
console.log('Token already sent to server so won\'t send it again ' +
|
||||
'unless it changes');
|
||||
}
|
||||
}
|
||||
|
||||
async isTokenSentToServer() {
|
||||
return window.localStorage.getItem('sentToServer') === '1';
|
||||
}
|
||||
|
||||
async setTokenSentToServer(sent) {
|
||||
window.localStorage.setItem('sentToServer', sent ? '1' : '0');
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new Singleton()
|
||||
Object.freeze(instance)
|
||||
|
||||
export default instance
|
||||
@@ -0,0 +1,106 @@
|
||||
|
||||
|
||||
import Snackbar from '@material-ui/core/Snackbar';
|
||||
import SnackbarContent from '@material-ui/core/SnackbarContent';
|
||||
import React, { Component } from 'react';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import ErrorIcon from '@material-ui/icons/Error';
|
||||
import InfoIcon from '@material-ui/icons/Info';
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import CheckCircleIcon from '@material-ui/icons/CheckCircle';
|
||||
import WarningIcon from '@material-ui/icons/Warning';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import clsx from 'clsx';
|
||||
import { amber, green } from '@material-ui/core/colors';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
|
||||
const useStyles1 = makeStyles(theme => ({
|
||||
success: {
|
||||
backgroundColor: green[600],
|
||||
},
|
||||
error: {
|
||||
backgroundColor: theme.palette.error.dark,
|
||||
},
|
||||
info: {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
warning: {
|
||||
backgroundColor: amber[700],
|
||||
},
|
||||
icon: {
|
||||
fontSize: 20,
|
||||
},
|
||||
iconVariant: {
|
||||
opacity: 0.9,
|
||||
marginRight: theme.spacing(1),
|
||||
},
|
||||
message: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
}));
|
||||
const variantIcon = {
|
||||
success: CheckCircleIcon,
|
||||
warning: WarningIcon,
|
||||
error: ErrorIcon,
|
||||
info: InfoIcon,
|
||||
};
|
||||
|
||||
function MySnackbarContentWrapper(props) {
|
||||
const classes = useStyles1();
|
||||
const { className, message, onClose, variant, ...other } = props;
|
||||
const Icon = variantIcon[variant];
|
||||
|
||||
return (
|
||||
<SnackbarContent
|
||||
className={clsx(classes[variant], className)}
|
||||
aria-describedby="client-snackbar"
|
||||
message={
|
||||
<span id="client-snackbar" className={classes.message}>
|
||||
<Icon className={clsx(classes.icon, classes.iconVariant)} />
|
||||
{message}
|
||||
</span>
|
||||
}
|
||||
action={[
|
||||
<IconButton key="close" aria-label="Close" color="inherit" onClick={onClose}>
|
||||
<CloseIcon className={classes.icon} />
|
||||
</IconButton>,
|
||||
]}
|
||||
{...other}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = theme => ({
|
||||
container: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100%',
|
||||
},
|
||||
|
||||
|
||||
});
|
||||
|
||||
class Snack extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Snackbar
|
||||
anchorOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'right',
|
||||
}}
|
||||
open={this.props.openSnack}
|
||||
autoHideDuration={7000}
|
||||
>
|
||||
<MySnackbarContentWrapper
|
||||
variant={this.props.variant}
|
||||
message={this.props.message}
|
||||
onClose={this.props.onClose} />
|
||||
</Snackbar>
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(Snack);
|
||||
|
||||
@@ -3,29 +3,184 @@ import red from '@material-ui/core/colors/red';
|
||||
|
||||
// Create a theme instance.
|
||||
const theme = createMuiTheme({
|
||||
|
||||
// COLORS
|
||||
palette: {
|
||||
primary: {
|
||||
main: '#155EE4',
|
||||
main: '#1689FB',
|
||||
darkMain: '#155EE4',
|
||||
dark: '#1E2327',
|
||||
important: '#25D89A',
|
||||
conditional: '#D2D3D3',
|
||||
},
|
||||
secondary: {
|
||||
main: '#19857b',
|
||||
},
|
||||
flash: {
|
||||
main: '#25D89A',
|
||||
main: '#FFFFFF',
|
||||
dark: '#BBBCBD',
|
||||
important: '#FF5A5F',
|
||||
text: '#787B7D',
|
||||
},
|
||||
error: {
|
||||
main: red.A400,
|
||||
},
|
||||
background: {
|
||||
default: '#fff',
|
||||
offerlistitem: {
|
||||
title: '#1E2327',
|
||||
icon: '#1E2327',
|
||||
text: '#1E2327',
|
||||
},
|
||||
answer: {
|
||||
main: '#E8E8E8',
|
||||
},
|
||||
background: {
|
||||
default: '#ffffff',
|
||||
grid: '#FCFCFC',
|
||||
dark: '#1E2327',
|
||||
grey: '#F3F9FF',
|
||||
videotheque: '#54D7E6',
|
||||
blog: '#1689FB',
|
||||
recruteur: '#1E2327',
|
||||
},
|
||||
menu: {
|
||||
darkText: '#1E2327',
|
||||
lightText: '#F3F9FF',
|
||||
darkDivider: '#32383C',
|
||||
lightDivider: '#E2E2E2',
|
||||
backArrow: 'rgba(30, 35, 39, 0.4)',
|
||||
emailText: '#E8E8E9'
|
||||
},
|
||||
tags: {
|
||||
main: '#E7F3FF',
|
||||
},
|
||||
input: {
|
||||
main: '#F0F0F0',
|
||||
},
|
||||
authSocial: {
|
||||
facebook: '#3064B7',
|
||||
facebookDark: '#2C59A0',
|
||||
linkedin: '#0276B5',
|
||||
linkedinDark: '#025C8D',
|
||||
},
|
||||
social: {
|
||||
facebook: '#334F8D',
|
||||
twitter: '#1A97F0',
|
||||
linkedin: '#006CAC',
|
||||
mail: '#BBBCBD',
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
//OVERRIDE
|
||||
overrides: {
|
||||
|
||||
MuiDrawer: {
|
||||
paperAnchorLeft: {
|
||||
right: '25%',
|
||||
backgroundColor: '#1E2327',
|
||||
},
|
||||
paperAnchorRight: {
|
||||
left: '25%',
|
||||
backgroundColor: '#1E2327',
|
||||
}
|
||||
},
|
||||
|
||||
MuiAppBar: {
|
||||
colorPrimary: {
|
||||
color: '#1689FB',
|
||||
backgroundColor: '#FFFFFF',
|
||||
},
|
||||
colorDefault: {
|
||||
boxShadow: 'none',
|
||||
backgroundColor: '#F8FBFF',
|
||||
}
|
||||
},
|
||||
|
||||
MuiPaper: {
|
||||
elevation1: {
|
||||
transition: 'box-shadow .25s',
|
||||
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.2)',
|
||||
boxShadow: '0px 6px 16px rgba(30, 35, 39, 0.15)',
|
||||
transition: 'box-shadow 2s',
|
||||
'&:hover': {
|
||||
boxShadow: '0px 6px 16px rgba(35, 40, 45, 0.25)',
|
||||
transition: 'box-shadow 1.2s',
|
||||
}
|
||||
},
|
||||
elevation4: {
|
||||
transition: 'box-shadow .25s',
|
||||
boxShadow: '0px 6px 16px rgba(30, 35, 39, 0.15)',
|
||||
},
|
||||
},
|
||||
|
||||
MuiButton: {
|
||||
root: {
|
||||
'&:hover': {
|
||||
backgroundColor: 'none',
|
||||
},
|
||||
'&:active': {
|
||||
boxShadow: '0px',
|
||||
},
|
||||
},
|
||||
|
||||
contained: {
|
||||
boxShadow: '0px',
|
||||
'&:hover': {
|
||||
backgroundColor: 'none',
|
||||
},
|
||||
'&:active': {
|
||||
boxShadow: '0px',
|
||||
},
|
||||
},
|
||||
outlined: {
|
||||
border: '2px solid',
|
||||
'&:hover': {
|
||||
backgroundColor: 'none',
|
||||
},
|
||||
'&:active': {
|
||||
boxShadow: '0px',
|
||||
},
|
||||
},
|
||||
outlinedPrimary: {
|
||||
border: '2px solid',
|
||||
borderColor: '#1689FB',
|
||||
'&:hover': {
|
||||
border: '2px solid',
|
||||
},
|
||||
},
|
||||
outlinedSecondary: {
|
||||
border: '2px solid',
|
||||
borderColor: '#FFFFFF',
|
||||
'&:hover': {
|
||||
border: '2px solid',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
MuiButtonGroup: {
|
||||
contained: {
|
||||
boxShadow: 'inherit',
|
||||
},
|
||||
},
|
||||
|
||||
MuiLink: {
|
||||
underlineHover: {
|
||||
'&:hover': {
|
||||
textDecoration: 'none',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
MuiCheckbox: {
|
||||
colorSecondary: {
|
||||
'&.Mui-checked': {
|
||||
color: "#1689FB",
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
MuiFilledInput: {
|
||||
underline: {
|
||||
'&:before, &:after': {
|
||||
display: 'none',
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,503 @@
|
||||
import React, { useState, Component, Fragment } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import { Alert, AlertTitle } from '@material-ui/lab';
|
||||
import Snackbar from '@material-ui/core/Snackbar';
|
||||
import { connect } from 'react-redux'
|
||||
import { updateUserRequest } from '../../actions/user'
|
||||
import getConfig from 'next/config'
|
||||
import Validator from "validator";
|
||||
import AccountProfile from '../organisms/AccountProfile';
|
||||
import ReactHtmlParser, { processNodes, convertNodeToElement, htmlparser2 } from 'react-html-parser';
|
||||
import {
|
||||
Button,
|
||||
} from '@material-ui/core';
|
||||
|
||||
const styles = theme => ({
|
||||
container: {
|
||||
width: '85%',
|
||||
},
|
||||
form: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: '24px',
|
||||
paddingBottom: theme.spacing(8),
|
||||
marginBottom: theme.spacing(8),
|
||||
'&>div': {
|
||||
marginTop: theme.spacing(1.5),
|
||||
marginBottom: theme.spacing(1.5),
|
||||
}
|
||||
|
||||
},
|
||||
textField: {
|
||||
width: '85%',
|
||||
'&:disabled': {
|
||||
color: theme.palette.secondary.dark,
|
||||
},
|
||||
'& label': {
|
||||
color: theme.palette.primary.dark,
|
||||
},
|
||||
'& fieldset:hover': {
|
||||
borderColor: theme.palette.primary.main + ' !important',
|
||||
},
|
||||
},
|
||||
textFieldSmall: {
|
||||
width: '48%',
|
||||
'&:disabled': {
|
||||
color: theme.palette.secondary.dark,
|
||||
},
|
||||
'& label': {
|
||||
color: theme.palette.primary.dark,
|
||||
},
|
||||
'& fieldset:hover': {
|
||||
borderColor: theme.palette.primary.main + ' !important',
|
||||
},
|
||||
padding: '5px',
|
||||
},
|
||||
});
|
||||
|
||||
const { publicRuntimeConfig } = getConfig();
|
||||
|
||||
//https://xd.adobe.com/view/ba98331a-9145-4d67-7e27-25a36e519ef4-cca9/screen/a96779d7-bdb3-410a-8f19-e6987acb98ee/Candidature-Step-3
|
||||
class AccountEtape1 extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
// This binding is necessary to make `this` work in the callback
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.handleClose = this.handleClose.bind(this);
|
||||
this.onBlur = this.onBlur.bind(this)
|
||||
this.onSubmit = this.onSubmit.bind(this);
|
||||
}
|
||||
|
||||
state = {
|
||||
file: null,
|
||||
firstname: '',
|
||||
lastname: '',
|
||||
email:'',
|
||||
phone: '',
|
||||
currentJob: '',
|
||||
address1:'',
|
||||
address2 : '',
|
||||
zipCode : '',
|
||||
city : '',
|
||||
country : '',
|
||||
linkedin: '',
|
||||
twitter: '',
|
||||
website: '',
|
||||
mediaId: null,
|
||||
companyId: null,
|
||||
|
||||
};
|
||||
|
||||
handleChange = (e) => {
|
||||
this.setState({ [e.target.name]: e.target.value });
|
||||
|
||||
//console.log(this.refs.myTextField.input.value);
|
||||
//this.soumettre(e);
|
||||
|
||||
}
|
||||
|
||||
handleClose = (e, reason) => {
|
||||
|
||||
if (reason === 'clickaway') {
|
||||
return;
|
||||
}
|
||||
|
||||
//setOpen(false);
|
||||
};
|
||||
|
||||
onBlur(e) {
|
||||
console.log("blur")
|
||||
this.setState({ [e.target.name]: e.target.value });
|
||||
|
||||
this.soumettre(e.target.name, "unitaire");
|
||||
}
|
||||
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
this.setState({
|
||||
firstname: nextProps.user.firstname,
|
||||
lastname: nextProps.user.lastname,
|
||||
phone: nextProps.user.phone,
|
||||
email: nextProps.user.email,
|
||||
currentJob: nextProps.user.currentJob,
|
||||
address1 : nextProps.user.address1,
|
||||
address2 : nextProps.user.address2,
|
||||
zipCode : nextProps.user.zipCode,
|
||||
city : nextProps.user.city,
|
||||
country : nextProps.user.country,
|
||||
linkedin: nextProps.user.linkedin,
|
||||
twitter: nextProps.user.twitter,
|
||||
website: nextProps.user.website,
|
||||
companyId: nextProps.companyId,
|
||||
errors: !!!nextProps.errors ? { errors: { message: "" } } : nextProps.errors,
|
||||
})
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({
|
||||
firstname: this.props.user.firstname,
|
||||
lastname: this.props.user.lastname,
|
||||
phone: this.props.user.phone,
|
||||
email: this.props.user.email,
|
||||
address1: this.props.user.address1,
|
||||
address2 : this.props.user.address2,
|
||||
zipCode : this.props.user.zipCode,
|
||||
city : this.props.user.city,
|
||||
country : this.props.user.country,
|
||||
currentJob: this.props.user.currentJob,
|
||||
linkedin: this.props.user.linkedin,
|
||||
twitter: this.props.user.twitter,
|
||||
website: this.props.user.website,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
onSubmit = (e) => {
|
||||
|
||||
e.preventDefault();
|
||||
console.log("submit")
|
||||
console.log(e.keyCode)
|
||||
|
||||
this.soumettre(e.target.name, "global")
|
||||
|
||||
}
|
||||
soumettre(champ, type){
|
||||
console.log("soumettre");
|
||||
console.log(champ);
|
||||
const errors = this.validate(this.state, champ, type);
|
||||
const success = {};
|
||||
this.setState({ errors });
|
||||
if (!this.state.errors || !this.state.errors.message){
|
||||
|
||||
success.message ="Profil mis à jour";
|
||||
this.setState({ success });
|
||||
const data = new FormData()
|
||||
data.append('firstname', this.state.firstname)
|
||||
data.append('lastname', this.state.lastname)
|
||||
data.append('phone', this.state.phone)
|
||||
//data.append('email', this.state.email)
|
||||
data.append('currentJob', this.state.currentJob)
|
||||
data.append('address1', this.state.address1)
|
||||
data.append('address2', this.state.address2)
|
||||
data.append('zipCode', this.state.zipCode)
|
||||
data.append('city', this.state.city)
|
||||
data.append('country', this.state.country)
|
||||
data.append('linkedin', this.state.linkedin)
|
||||
data.append('twitter', this.state.twitter)
|
||||
data.append('website', this.state.website)
|
||||
|
||||
//TODO:maybe add this two in a single transactionnal saga
|
||||
this.props.updateUserRequest(data)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
validate(data,champ, type){
|
||||
console.log("valdiate")
|
||||
console.log(champ);
|
||||
const errors = {};
|
||||
errors.message ="";
|
||||
//if (!Validator.isEmail(data.currentJob)) errors.message += "Le poste actuel doit etre un email\n";
|
||||
if (type=="global" || (champ=="firstname" && data.firstname=="")) errors.message += "Veuillez saisir votre prénom<br />";
|
||||
if (type=="global" || (champ=="lastname" && data.lastname=="")) errors.message += " Veuillez saisir votre nom<br />";
|
||||
if (type=="global" || (champ=="phone" && data.phone=="")) errors.message += "Veuillez saisir un numéro de téléphone<br />";
|
||||
if (type=="global" || (champ=="currentJob" && data.currentJob=="")) errors.message += "Veuillez saisir votre intitulé de poste actuel ou poste recherché<br />";
|
||||
if (type=="global" || (champ=="zipCode" && (data.zipCode && data.zipCode!="") && !Validator.isPostalCode(data.zipCode, "FR"))) errors.message += "Le code postal n'est pas correct<br />";
|
||||
// if ((data.website && data.website!="") && !Validator.isURL(data.website)) errors.message += " Veuillez ajouter un site internet avec une url valide<br />";
|
||||
if (!Validator.isMobilePhone(data.phone, "fr-FR") && !Validator.isNumeric(data.phone, "fr-FR")) errors.message += "Le téléphone n'est pas correct<br />";
|
||||
//console.log(errors.email);
|
||||
|
||||
return errors;
|
||||
};
|
||||
AfficherErreurs() {
|
||||
if (!this.state.errors || !this.state.errors.message){
|
||||
return "";
|
||||
}else if (this.state.errors.length != 0 && this.state.errors.message!="") {
|
||||
return (
|
||||
<Alert severity="error">
|
||||
{ ReactHtmlParser(this.state.errors.message)}
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
AfficherSuccess() {
|
||||
// if (this.state.success && this.state.success.length != 0 && this.state.success.message != "") {
|
||||
// return (
|
||||
// <Snackbar open={open} autoHideDuration={1000} onClose={() => this.setState({open: false})}>
|
||||
// <Alert onClose={() => this.setState({open: false})} severity="success">
|
||||
// {ReactHtmlParser(this.state.success.message)}
|
||||
// </Alert>
|
||||
// </Snackbar>
|
||||
|
||||
|
||||
// );
|
||||
|
||||
// }
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
inputFilesystemChange = (e) => {
|
||||
|
||||
console.log("inputFilesystemChange");
|
||||
var file = e.target.files[0]
|
||||
this.setState({ picture: file })
|
||||
|
||||
const data = new FormData()
|
||||
data.append('file', file)
|
||||
this.props.updateUserPictureRequest(data)
|
||||
}
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
const { classes, user } = this.props
|
||||
const logoUrl = user.picture;
|
||||
function refresh() {
|
||||
document
|
||||
.location
|
||||
.reload(true);
|
||||
|
||||
}
|
||||
return (
|
||||
<section className={classes.container}>
|
||||
<form className={classes.form}
|
||||
autoComplete="off" focused="true" name="monForm" ref="formToSubmit">
|
||||
{/* {!!logoUrl && <Avatar className={classes.logo}
|
||||
classes={{ img: classes.MuiAvatarImg }}
|
||||
src={publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.postedContentUrl + logoUrl} alt="candidatLogo" />} */}
|
||||
|
||||
{/* {!!user.pictureLoading && <Loader />}
|
||||
{!!!user.pictureLoading && !!!logoUrl &&
|
||||
(<Fragment><input
|
||||
type="file" accept="image/*" capture="filesystem"
|
||||
className={classes.input}
|
||||
style={{ display: 'none' }}
|
||||
id="raised-button-file"
|
||||
multiple
|
||||
type="file"
|
||||
onChange={this.inputFilesystemChange}
|
||||
/>
|
||||
<label htmlFor="raised-button-file">
|
||||
<Button component="span" className={classes.importButton} classes={{ root: classes.rootButton }}>
|
||||
<img alt="talents-tube" src='/static/images/default/account-avatar-default.svg'
|
||||
className={classes.iconButton} />
|
||||
<Typography align="left" className={classes.textButton}>
|
||||
J'<span className={classes.underlined}>importe</span> ma photo de profil
|
||||
</Typography>
|
||||
<KeyboardArrowRightIcon className={classes.InputKeyboardArrowRightIcon} />
|
||||
</Button>
|
||||
</label></Fragment>)
|
||||
} */}
|
||||
{this.AfficherErreurs()}
|
||||
{this.AfficherSuccess()}
|
||||
|
||||
|
||||
<TextField
|
||||
name="firstname"
|
||||
required
|
||||
id="outlined-required"
|
||||
label="Prénom"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
value={this.state.firstname}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.onBlur}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
name="lastname"
|
||||
required
|
||||
id="outlined-required"
|
||||
label="Nom"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
value={this.state.lastname}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.onBlur}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
disabled
|
||||
name="email"
|
||||
id="outlined"
|
||||
label="E-mail"
|
||||
required
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
value={this.state.email}
|
||||
onChange={this.handleChange}
|
||||
type="mail"
|
||||
onBlur={this.onBlur}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
name="phone"
|
||||
id="outlined"
|
||||
label="Téléphone"
|
||||
required
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
value={this.state.phone ? this.state.phone: ''}
|
||||
onChange={this.handleChange}
|
||||
type="tel"
|
||||
onBlur={this.onBlur}
|
||||
/>
|
||||
|
||||
|
||||
|
||||
<TextField
|
||||
name="currentJob"
|
||||
id="outlined"
|
||||
label="Poste actuel"
|
||||
required
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
value={this.state.currentJob =='null' || this.state.currentJob =='' ? '' :this.state.currentJob}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.onBlur}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
name="address1"
|
||||
id="outlined"
|
||||
label="Adresse"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
value={this.state.address1 ? this.state.address1 : ''}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.onBlur}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
name="address2"
|
||||
id="outlined"
|
||||
label="Adresse complémentaire"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
value={this.state.address2 ? this.state.address2 : ''}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.onBlur}
|
||||
/>
|
||||
<div className={classes.container}>
|
||||
<TextField
|
||||
name="zipCode"
|
||||
id="outlined"
|
||||
label="Code postal"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.textFieldSmall }}
|
||||
variant="outlined"
|
||||
value={this.state.zipCode ? this.state.zipCode : ''}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.onBlur}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
name="city"
|
||||
id="outlined"
|
||||
label="Ville"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.textFieldSmall }}
|
||||
variant="outlined"
|
||||
value={this.state.city ? this.state.city : ''}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.onBlur}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
name="country"
|
||||
id="outlined"
|
||||
label="Pays"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.textFieldSmall }}
|
||||
variant="outlined"
|
||||
value={this.state.country ? this.state.country : ''}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.onBlur}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TextField
|
||||
name="linkedin"
|
||||
id="outlined"
|
||||
label="Linkedin"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
placeholder="http://www.linkedin.com/in/"
|
||||
value={this.state.linkedin =='null' || this.state.linkedin =='' ? '' :this.state.linkedin}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.onBlur}
|
||||
|
||||
/>
|
||||
|
||||
<TextField
|
||||
name="twitter"
|
||||
id="outlined"
|
||||
label="Twitter"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
placeholder="http://twitter.com/.."
|
||||
value={this.state.twitter =='null' || this.state.twitter =='' ? '' :this.state.twitter}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.onBlur}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
name="website"
|
||||
id="outlined"
|
||||
label="Site internet"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
placeholder="http://monsite.fr"
|
||||
value={this.state.website =='null' || this.state.website =='' ? '' :this.state.website}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.onBlur}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
|
||||
className={classes.button}>
|
||||
Enregistrer
|
||||
</Button>
|
||||
</form>
|
||||
{/* <div id="F" className={classes.foot}>
|
||||
<Button variant="contained" className={classes.button + ' cypButtonSendApplication'} onClick={this.onSubmit}>Mettre à jour!</Button>
|
||||
</div> */}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
user: state.user ,
|
||||
loading: !!state.user.loading,
|
||||
pictureLoading: !!state.user.pictureLoading,
|
||||
errors: state.user.errors || ownProps.errors,
|
||||
mediaId: state.media.message && state.media.message.mediaId,
|
||||
};
|
||||
}
|
||||
|
||||
export default withStyles(styles)(connect(mapStateToProps, { updateUserRequest })(AccountEtape1));
|
||||
@@ -0,0 +1,362 @@
|
||||
import React, {Fragment} from 'react'
|
||||
import {connect} from "react-redux";
|
||||
import {makeStyles} from '@material-ui/styles';
|
||||
import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight';
|
||||
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
|
||||
import {Button, Typography} from '@material-ui/core';
|
||||
import dynamic from 'next/dynamic'
|
||||
import {withStyles} from '@material-ui/core/styles'
|
||||
import {uploadMediaPres} from '../../actions/media'
|
||||
import {errorMessageSelector} from '../../reducers/media'
|
||||
import {fetchCompanyRequest} from '../../actions/companies'
|
||||
import {fetchCurrentUserRequest} from '../../actions/user'
|
||||
import VideoVimeo from '../atoms/VideoVimeo'
|
||||
import Router from 'next/router'
|
||||
import LoaderVideo from '../templates/loaderVideo'
|
||||
import Ar from "lodash/array"
|
||||
import Snackbar from '@material-ui/core/Snackbar';
|
||||
import { Alert, AlertTitle } from '@material-ui/lab';
|
||||
import ReactHtmlParser, { processNodes, convertNodeToElement, htmlparser2 } from 'react-html-parser';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Container from '@material-ui/core/Container';
|
||||
import Hidden from '@material-ui/core/Hidden';
|
||||
|
||||
const styles = theme => ({
|
||||
container: {
|
||||
width: '100%',
|
||||
},
|
||||
root: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
margin: theme.spacing(1),
|
||||
flexWrap: 'wrap',
|
||||
overflow: 'hidden',
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
},
|
||||
|
||||
recorderContainer: {
|
||||
//display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%'
|
||||
},
|
||||
rootButton: {
|
||||
textTransform: 'inherit'
|
||||
},
|
||||
underlined: {
|
||||
textDecoration: 'underline'
|
||||
},
|
||||
textButton: {
|
||||
fontWeight: '700',
|
||||
fontSize: '1.15em',
|
||||
paddingLeft: theme.spacing(2)
|
||||
},
|
||||
videoPresentation: {
|
||||
width: "100%",
|
||||
height: "100%"
|
||||
},
|
||||
conseilButton: {
|
||||
color: "#ffffff",
|
||||
backgroundColor: "#25D89A",
|
||||
padding: theme.spacing(3, 2),
|
||||
margin: theme.spacing(1),
|
||||
width: "100%",
|
||||
textAlign: "right",
|
||||
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1' +
|
||||
'px rgba(0, 0, 0, 0.14)',
|
||||
'&:hover': {
|
||||
color: "#ffffff",
|
||||
backgroundColor: "#25D89A",
|
||||
}
|
||||
},
|
||||
captureButton: {
|
||||
color: theme.palette.secondary.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
padding: theme.spacing(5, 2),
|
||||
margin: theme.spacing(1),
|
||||
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 4px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.14)',
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
},
|
||||
importButton: {
|
||||
color: theme.palette.primary.main,
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
padding: theme.spacing(3, 2),
|
||||
margin: theme.spacing(1),
|
||||
width: "100%",
|
||||
textAlign: "right",
|
||||
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1' +
|
||||
'px rgba(0, 0, 0, 0.14)',
|
||||
'&:hover': {
|
||||
color: theme.palette.primary.main,
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
}
|
||||
},
|
||||
InputKeyboardArrowDownIconBlank: {
|
||||
fontSize: '2.5em',
|
||||
color: "#ffffff",
|
||||
textAlign: "right"
|
||||
},
|
||||
InputKeyboardArrowDownIcon: {
|
||||
fontSize: '2.5em',
|
||||
color: "#1689FB",
|
||||
textAlign: "right"
|
||||
},
|
||||
buttons :{
|
||||
display: "inline-table",
|
||||
}
|
||||
});
|
||||
const Recorder = dynamic(() => import ('../organisms/Recorder'), {ssr: false})
|
||||
class Etape2 extends React.Component {
|
||||
state = {
|
||||
loading: true,
|
||||
activeStep: 0,
|
||||
data: {},
|
||||
openSnack: false,
|
||||
errors: {},
|
||||
success : {}
|
||||
};
|
||||
|
||||
|
||||
componentDidMount() {
|
||||
localStorage.setItem('loginRedirect', window.location.pathname)
|
||||
|
||||
if (!!!localStorage.getItem('ttJWT')) {
|
||||
Router.push("/Login")
|
||||
} else
|
||||
this.setState({loading: false, firstname: this.props.user.firstname, videoPres: this.props.user.videoPres, video: this.props.user.presentation_video_id})
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
|
||||
this.setState({
|
||||
loading: nextProps.loading,
|
||||
openSnack: !!!_.isEmpty(nextProps.errors),
|
||||
errors: !!!nextProps.errors
|
||||
? {
|
||||
errors: {
|
||||
message: ""
|
||||
}
|
||||
}
|
||||
: nextProps.errors,
|
||||
videoPres: nextProps.videoPres,
|
||||
video: nextProps.video
|
||||
})
|
||||
//window.location.reload(false);
|
||||
if (nextProps.media.status === 'success') {
|
||||
const success = {};
|
||||
success.message ="Vidéo mise à jour";
|
||||
this.setState({ success });
|
||||
this.setActiveStep(1);
|
||||
}
|
||||
}
|
||||
|
||||
setActiveStep = (step) => {
|
||||
this.setState({activeStep: step})
|
||||
}
|
||||
|
||||
inputFilesystemChange = (e) => {
|
||||
this.uploadMediaPres(e)
|
||||
}
|
||||
|
||||
inputCamRecorderChange = (e) => {
|
||||
this.uploadMediaPres(e)
|
||||
}
|
||||
|
||||
uploadMediaPres = (e) => {
|
||||
var file = e.target.files[0]
|
||||
|
||||
const data = new FormData()
|
||||
data.append('upload', file)
|
||||
//this.setState({ videoPres: videoPres })
|
||||
|
||||
this
|
||||
.props
|
||||
.uploadMediaPres(data)
|
||||
}
|
||||
|
||||
AfficherSuccess() {
|
||||
if (!this.state.success || !this.state.success.message) {
|
||||
|
||||
} else if (this.state.success.length != 0 && this.state.success.message != "") {
|
||||
return (
|
||||
<Snackbar open={open} autoHideDuration={1000} onClose={() => this.setState({open: false})}>
|
||||
<Alert onClose={() => this.setState({open: false})} severity="success">
|
||||
{ReactHtmlParser(this.state.success.message)}
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
handleClose = (event, reason) => {
|
||||
this.setState({openSnack: false});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {classes, company} = this.props;
|
||||
const {loading, activeStep} = this.state;
|
||||
let video;
|
||||
if (this.state.videoPres) {
|
||||
video = <VideoVimeo videoId={Ar.last(_.split(this.state.videoPres, '/'))} autoplay='1' classesOverride="videoPresentation"/>;
|
||||
} else {
|
||||
video = "";
|
||||
}
|
||||
return (
|
||||
<section className={classes.container}>
|
||||
<Fragment>
|
||||
{this.AfficherSuccess()}
|
||||
{ loading ? <LoaderVideo textePrincipal="Votre vidéo est en cours d’envoi..." texteSecondaire="Veuillez rester sur la page pendant le chargement qui peut durer plusieurs minutes."/> : <div></div> }
|
||||
|
||||
<div className={classes.root}>
|
||||
<Hidden xsUp>
|
||||
|
||||
</Hidden>
|
||||
<Container maxWidth="md">
|
||||
|
||||
<Grid container
|
||||
justify="center"
|
||||
alignItems="center"
|
||||
spacing={2}
|
||||
className={classes.buttons}>
|
||||
<Grid item xs={12} sm={12} md={12} lg={6} lg={6}>
|
||||
|
||||
|
||||
|
||||
{ /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ?
|
||||
(
|
||||
<Fragment >
|
||||
<input
|
||||
type="file" accept="video/*" capture="camcorder"
|
||||
className={classes.input}
|
||||
style={{ display: 'none' }}
|
||||
id="record-button-file"
|
||||
multiple
|
||||
onChange={this.inputCamRecorderChange}
|
||||
/>
|
||||
<label htmlFor="record-button-file">
|
||||
<Button component="span" className={classes.captureButton} classes={{ root: classes.rootButton }}>
|
||||
<img alt="talents-tube" src='/static/images/capture.svg' className={classes.iconButton} />
|
||||
<Typography align="left" className={classes.textButton}>
|
||||
Je <span className={classes.underlined}>réalise</span> ma vidéo de présentation
|
||||
</Typography>
|
||||
<KeyboardArrowRightIcon className={ classes.InputKeyboardArrowRightIcon }/>
|
||||
</Button>
|
||||
</label>
|
||||
</Fragment>
|
||||
):
|
||||
(
|
||||
|
||||
|
||||
<div className={classes.recorderContainer}>
|
||||
<Recorder uploader={this.props.uploadMediaPres} titreBouton="Remplacer ma vidéo"/>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12} lg={6} xl={6}>
|
||||
<div>
|
||||
<label htmlFor="import-conseil">
|
||||
<Button
|
||||
component="span"
|
||||
className={classes.conseilButton}
|
||||
classes={{
|
||||
root: classes.rootButton}}
|
||||
onClick={() => Router.push(`/Conseils`)}>
|
||||
<img
|
||||
alt="talents-tube"
|
||||
src='/statique/images/conseils-talentstube.svg'
|
||||
className={classes.iconButton}/>
|
||||
<Typography align="left" className={classes.textButton}>
|
||||
<span className={classes.underlined}>Comment</span> créer ma vidéo
|
||||
</Typography>
|
||||
<KeyboardArrowDownIcon className={classes.InputKeyboardArrowDownIconBlank}/>
|
||||
</Button>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="file"
|
||||
accept="video/*"
|
||||
className={classes.input + ' cypButtonImportVid'}
|
||||
style={{display: 'none'}}
|
||||
id="import-button-file"
|
||||
onChange={this.inputFilesystemChange}/>
|
||||
<label htmlFor="import-button-file">
|
||||
<Button
|
||||
component="span"
|
||||
className={classes.importButton}
|
||||
classes={{
|
||||
root: classes.rootButton}}>
|
||||
<img
|
||||
alt="talents-tube"
|
||||
src='/statique/images/Import.svg'
|
||||
className={classes.iconButton}/>
|
||||
<Typography align="left" className={classes.textButton}>
|
||||
J'<span className={classes.underlined}>importe</span> ma vidéo de présentation
|
||||
|
||||
</Typography>
|
||||
<KeyboardArrowDownIcon className={classes.InputKeyboardArrowDownIcon}/>
|
||||
</Button>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</Grid>
|
||||
<Hidden xsUp>
|
||||
|
||||
</Hidden>
|
||||
|
||||
<Grid item xs={12} sm={12} md={12} lg={12} xl={12}>
|
||||
<div className={classes.videoPresentation}>
|
||||
{video}
|
||||
</div>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</Container>
|
||||
</div>
|
||||
{/* <div className={classes.textContainer}>
|
||||
|
||||
</div> */}
|
||||
|
||||
</Fragment>
|
||||
</section>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Etape2.getInitialProps = function (context) {
|
||||
|
||||
const {companyId} = context.query
|
||||
const {res} = context
|
||||
//TODO :really needed ?
|
||||
context
|
||||
.store
|
||||
.dispatch(fetchCurrentUserRequest())
|
||||
|
||||
if (!!companyId)
|
||||
context.store.dispatch(fetchCompanyRequest(companyId))
|
||||
|
||||
return {}; //leave this please
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
|
||||
return {
|
||||
loading: !!state.media.loading,
|
||||
media: state.media,
|
||||
offre: state.ad,
|
||||
//errors: errorMessageSelector(state),
|
||||
user: state.user,
|
||||
company: state.company
|
||||
};
|
||||
}
|
||||
|
||||
export default withStyles(styles)(connect(mapStateToProps, {fetchCurrentUserRequest, fetchCompanyRequest, uploadMediaPres})(Etape2));
|
||||
@@ -0,0 +1,257 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { connect } from "react-redux";
|
||||
import { fetchCurrentUserRequest } from '../../actions/user'
|
||||
import { fetchCompanyRequest } from '../../actions/companies'
|
||||
import { uploadMediaCv } from '../../actions/mediaCv'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { Button, Typography, Divider, Hidden } from '@material-ui/core';
|
||||
import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight';
|
||||
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
|
||||
import LoaderVideo from '../../components/templates/loaderVideo'
|
||||
import Snack from '../../components/atoms/snack';
|
||||
import Snackbar from '@material-ui/core/Snackbar';
|
||||
import { Alert, AlertTitle } from '@material-ui/lab';
|
||||
import ReactHtmlParser from 'react-html-parser';
|
||||
import getConfig from 'next/config'
|
||||
import Card from '@material-ui/core/Card';
|
||||
import CardActions from '@material-ui/core/CardActions';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
|
||||
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
margin: theme.spacing(1),
|
||||
},
|
||||
rootButton: {
|
||||
textTransform: 'inherit',
|
||||
},
|
||||
underlined: {
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
textButton: {
|
||||
fontWeight: '700',
|
||||
fontSize: '1.15em',
|
||||
paddingLeft: theme.spacing(2),
|
||||
},
|
||||
InputKeyboardArrowDownIcon: {
|
||||
fontSize: '2.5em',
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
importButton: {
|
||||
color: theme.palette.primary.main,
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
padding: theme.spacing(3, 2),
|
||||
margin: theme.spacing(1),
|
||||
width: "370px",
|
||||
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1' +
|
||||
'px rgba(0, 0, 0, 0.14)',
|
||||
'&:hover': {
|
||||
color: theme.palette.primary.main,
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
const { publicRuntimeConfig } = getConfig();
|
||||
class Etape3 extends React.Component {
|
||||
state = {
|
||||
loading: true,
|
||||
openSnack: false,
|
||||
cv:false,
|
||||
errors: {},
|
||||
success : {}
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
localStorage.setItem('loginRedirect', window.location.pathname)
|
||||
|
||||
if(!!!localStorage.getItem('ttJWT'))
|
||||
{
|
||||
Router.push("/Login")
|
||||
}
|
||||
else
|
||||
this.setState({
|
||||
loading: false,
|
||||
cvLink: this.props.user.cv
|
||||
})
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
|
||||
this.setState({
|
||||
cvLink: nextProps.cvLink,
|
||||
loading: nextProps.loading,
|
||||
openSnack: !!!_.isEmpty(nextProps.errors),
|
||||
errors: !!!nextProps.errors ? { errors: { message: "" } } : nextProps.errors,
|
||||
})
|
||||
this.state.cvLink = nextProps.cvLink;
|
||||
if (nextProps.loading) {
|
||||
const success = {};
|
||||
success.message ="CV mis à jour";
|
||||
console.log("CV mis à jour!!!")
|
||||
if(this.state.cvLink) console.log(this.state.cvLink)
|
||||
this.setState({ success });
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
inputFilesystemChange = (e) => {
|
||||
this.uploadMediaCv(e)
|
||||
}
|
||||
|
||||
uploadMediaCv = (e) => {
|
||||
var file = e.target.files[0]
|
||||
|
||||
const data = new FormData()
|
||||
data.append('upload', file)
|
||||
|
||||
this.props.uploadMediaCv(data)
|
||||
}
|
||||
|
||||
AfficherSuccess() {
|
||||
if (!this.state.success || !this.state.success.message) {
|
||||
console.log("Erreur Upload CV");
|
||||
return "";
|
||||
} else if (this.state.success.length != 0 && this.state.success.message != "") {
|
||||
return (
|
||||
<Snackbar open={open} autoHideDuration={1000} onClose={() => this.setState({open: false})}>
|
||||
<Alert onClose={() => this.setState({open: false})} severity="success">
|
||||
{ReactHtmlParser(this.state.success.message)}
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
AfficherLienCv() {
|
||||
console.log("afficher lien");
|
||||
if (this.state.cvLink !="") {
|
||||
|
||||
return (
|
||||
|
||||
<Fragment>
|
||||
<Hidden> </Hidden>
|
||||
<Hidden> </Hidden>
|
||||
|
||||
<Hidden> </Hidden>
|
||||
<Hidden> </Hidden>
|
||||
<Card variant="" style={{
|
||||
width:370+"px",
|
||||
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1' +
|
||||
'px rgba(0, 0, 0, 0.14)',
|
||||
marginLeft : '10px',
|
||||
marginTop:'10px'
|
||||
|
||||
}}>
|
||||
<Hidden> </Hidden>
|
||||
<CardActions>
|
||||
<Button size="small">MON CV</Button>
|
||||
</CardActions>
|
||||
<CardContent>
|
||||
<Typography >
|
||||
<a href={publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.postedContentCv + this.state.cvLink}
|
||||
target="_blank"
|
||||
style={{
|
||||
color:'#1689FB',
|
||||
'&:hover': {
|
||||
color: '#1689FB',
|
||||
},
|
||||
fontWeight: '700',
|
||||
fontSize: '1em',
|
||||
}}
|
||||
>
|
||||
Visualiser mon CV
|
||||
</a>
|
||||
<br />
|
||||
{/* <a href="https://www.permatheque.fr/PDF/mansobufukuoka-larevolutiondunseulbrindepaille.pdf" target="_blank">lien</a> */}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
|
||||
</Card>
|
||||
</Fragment>
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes, company } = this.props;
|
||||
const { loading } = this.state;
|
||||
return (
|
||||
<Fragment>
|
||||
{ loading ?
|
||||
<LoaderVideo textePrincipal="Votre candidature vidéo est en cours d’envoi..." texteSecondaire="Veuillez rester sur la page pendant le chargement qui peut durer plusieurs minutes."/> :
|
||||
<Fragment>
|
||||
{this.AfficherSuccess()}
|
||||
|
||||
<input
|
||||
type="file"
|
||||
accept=".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document, .pdf, .odt"
|
||||
className={classes.input+' cypButtonImportVid'}
|
||||
style={{ display: 'none' }}
|
||||
id="import-button-file"
|
||||
onChange={this.inputFilesystemChange}
|
||||
/>
|
||||
<label htmlFor="import-button-file">
|
||||
<Button component="span" className={classes.importButton} classes={{ root: classes.rootButton }}>
|
||||
<img alt="talents-tube" src='/statique/images/Import-cv-candidat.svg' className={classes.iconButton} />
|
||||
<Typography className={classes.textButton}>
|
||||
J'<span className={classes.underlined}>importe</span> mon CV
|
||||
</Typography>
|
||||
<KeyboardArrowDownIcon className={ classes. InputKeyboardArrowDownIcon }/>
|
||||
</Button>
|
||||
|
||||
</label>
|
||||
<Hidden> </Hidden>
|
||||
{this.AfficherLienCv()}
|
||||
|
||||
</Fragment>
|
||||
}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Etape3.getInitialProps = function (context) {
|
||||
|
||||
const { adId, companyId } = context.query
|
||||
const {res} = context
|
||||
//TODO :really needed ?
|
||||
context.store.dispatch(fetchCurrentUserRequest())
|
||||
|
||||
if(!!adId)
|
||||
context.store.dispatch(fetchJobRequest(adId))
|
||||
else if(!!companyId)
|
||||
context.store.dispatch(fetchCompanyRequest(companyId))
|
||||
|
||||
return {};//leave this please
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
// console.log("mapStateToProps")
|
||||
// console.log(state.loading)
|
||||
// console.log(state.user)
|
||||
// console.log(state.media.message)
|
||||
return {
|
||||
user: state.user ,
|
||||
cvLink : state.mediaCv.message,
|
||||
loading: !!state.media.loading,
|
||||
cv : true,
|
||||
//errors: errorMessageSelector(state),
|
||||
user: state.user,
|
||||
company: state.company
|
||||
};
|
||||
}
|
||||
export default withStyles(styles)(connect(mapStateToProps, { fetchCurrentUserRequest, fetchCompanyRequest, uploadMediaCv })(Etape3));
|
||||
@@ -0,0 +1,485 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import clsx from 'clsx';
|
||||
// import AccountStep from "../../components/organisms/AccountStep";
|
||||
import AccountEtape1 from '../organisms/AccountEtape1';
|
||||
import AccountEtape2 from '../organisms/AccountEtape2';
|
||||
import AccountEtape3 from '../organisms/AccountEtape3';
|
||||
import {withStyles} from '@material-ui/core/styles';
|
||||
// import Switch from '@material-ui/core/Switch';
|
||||
import PhoneIcon from '@material-ui/icons/Phone';
|
||||
import MailIcon from '@material-ui/icons/Mail';
|
||||
import PublicIcon from '@material-ui/icons/Public';
|
||||
import DuoIcon from '@material-ui/icons/Duo';
|
||||
import LinkedInIcon from '@material-ui/icons/LinkedIn';
|
||||
import Facebook from '@material-ui/icons/Facebook';
|
||||
// import FormGroup from '@material-ui/core/FormGroup'; import FormControlLabel
|
||||
// from '@material-ui/core/FormControlLabel'; import FormControl from
|
||||
// '@material-ui/core/FormControl';
|
||||
import {updateUserRequest, updateUserPictureRequest} from '../../actions/user'
|
||||
import {makeStyles} from '@material-ui/styles';
|
||||
import {connect} from 'react-redux'
|
||||
import getConfig from 'next/config'
|
||||
import BottomNavigation from '@material-ui/core/BottomNavigation';
|
||||
// import BottomNavigationAction from
|
||||
// '@material-ui/core/BottomNavigationAction';
|
||||
import RefreshIcon from '@material-ui/icons/Refresh';
|
||||
// import FavoriteIcon from '@material-ui/icons/Favorite'; import LocationOnIcon
|
||||
// from '@material-ui/icons/LocationOn';
|
||||
|
||||
import Box from '@material-ui/core/Box';
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardActions,
|
||||
CardContent,
|
||||
Avatar,
|
||||
Typography,
|
||||
Divider,
|
||||
Button,
|
||||
LinearProgress,
|
||||
Stepper,
|
||||
Step,
|
||||
StepLabel,
|
||||
StepContent,
|
||||
StepButton,
|
||||
Paper,
|
||||
Grid
|
||||
} from '@material-ui/core';
|
||||
|
||||
const styles = theme => ({
|
||||
container: {
|
||||
width: '100%'
|
||||
},
|
||||
button: {
|
||||
textTransform: 'inherit',
|
||||
marginLeft: theme.spacing(8),
|
||||
marginRight: theme.spacing(8),
|
||||
padding: theme.spacing(1.2, 2),
|
||||
color: theme.palette.secondary.main,
|
||||
backgroundColor: theme.palette.primary.important
|
||||
},
|
||||
stickToBottom: {
|
||||
width: '100%',
|
||||
position: 'fixed',
|
||||
bottom: 0
|
||||
}
|
||||
});
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
root: {},
|
||||
details: {
|
||||
display: 'flex'
|
||||
},
|
||||
avatar: {
|
||||
marginLeft: 'auto',
|
||||
height: 110,
|
||||
width: 100,
|
||||
flexShrink: 0,
|
||||
flexGrow: 0
|
||||
},
|
||||
progress: {
|
||||
marginTop: theme.spacing(2)
|
||||
},
|
||||
information: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
[
|
||||
theme
|
||||
.breakpoints
|
||||
.up('md')
|
||||
]: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
justifyContent: 'space-around',
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
padding: theme.spacing(7, 7)
|
||||
},
|
||||
'& a': {
|
||||
textDecoration: 'none'
|
||||
}
|
||||
},
|
||||
texteBlanc: {
|
||||
color: "#fff"
|
||||
},
|
||||
uploadButton: {
|
||||
marginRight: theme.spacing(2)
|
||||
},
|
||||
button: {
|
||||
marginTop: theme.spacing(1),
|
||||
marginRight: theme.spacing(1)
|
||||
},
|
||||
actionsContainer: {
|
||||
marginBottom: theme.spacing(2)
|
||||
},
|
||||
resetContainer: {
|
||||
padding: theme.spacing(3)
|
||||
}
|
||||
}));
|
||||
|
||||
function getSteps() {
|
||||
return ['Informations personnelles', 'Vidéo de présentation', 'Expériences professionnelles'];
|
||||
}
|
||||
|
||||
function getStepContent(step) {
|
||||
switch (step) {
|
||||
case 0:
|
||||
return <AccountEtape1 ></AccountEtape1>;
|
||||
case 1:
|
||||
return <AccountEtape2></AccountEtape2>;
|
||||
case 2:
|
||||
return <AccountEtape3></AccountEtape3>;
|
||||
default:
|
||||
return 'Unknown step';
|
||||
}
|
||||
}
|
||||
|
||||
const AccountProfile = props => {
|
||||
const {
|
||||
className,
|
||||
user,
|
||||
...rest
|
||||
} = props;
|
||||
const logoUrl = user.picture;
|
||||
const classes = useStyles();
|
||||
|
||||
// const user = { name: 'Laurent Laniau', city: 'Questembert', country:
|
||||
// 'France', timezone: '', avatar: '/images/avatars/avatar_11.png' };
|
||||
const {publicRuntimeConfig} = getConfig()
|
||||
const [activeStep,
|
||||
setActiveStep] = React.useState(0);
|
||||
const [completed,
|
||||
setCompleted] = React.useState(new Set());
|
||||
const [skipped,
|
||||
setSkipped] = React.useState(new Set());
|
||||
const [state,
|
||||
setState] = React.useState({checkedA: true, checkedB: true});
|
||||
const steps = getSteps();
|
||||
|
||||
const totalSteps = () => {
|
||||
return getSteps().length;
|
||||
};
|
||||
|
||||
const isStepOptional = (step) => {
|
||||
return step === 4;
|
||||
};
|
||||
|
||||
const handleSkip = () => {
|
||||
if (!isStepOptional(activeStep)) {
|
||||
// You probably want to guard against something like this it should never occur
|
||||
// unless someone's actively trying to break something.
|
||||
throw new Error("You can't skip a step that isn't optional.");
|
||||
}
|
||||
|
||||
setActiveStep((prevActiveStep) => prevActiveStep + 1);
|
||||
setSkipped((prevSkipped) => {
|
||||
const newSkipped = new Set(prevSkipped.values());
|
||||
newSkipped.add(activeStep);
|
||||
return newSkipped;
|
||||
});
|
||||
};
|
||||
|
||||
const skippedSteps = () => {
|
||||
return skipped.size;
|
||||
};
|
||||
|
||||
const completedSteps = () => {
|
||||
return completed.size;
|
||||
};
|
||||
|
||||
const allStepsCompleted = () => {
|
||||
return completedSteps() === totalSteps() - skippedSteps();
|
||||
};
|
||||
|
||||
const isLastStep = () => {
|
||||
return activeStep === totalSteps() - 1;
|
||||
};
|
||||
|
||||
const handleNext = () => {
|
||||
const newActiveStep = isLastStep() && !allStepsCompleted()
|
||||
? // It's the last step, but not all steps have been completed
|
||||
// find the first step that has been completed
|
||||
steps.findIndex((step, i) => !completed.has(i))
|
||||
: activeStep + 1;
|
||||
|
||||
setActiveStep(newActiveStep);
|
||||
};
|
||||
|
||||
const handleBack = () => {
|
||||
setActiveStep((prevActiveStep) => prevActiveStep - 1);
|
||||
};
|
||||
|
||||
const handleStep = (step) => () => {
|
||||
console.log("step");
|
||||
console.log(step);
|
||||
setActiveStep(step);
|
||||
};
|
||||
|
||||
const handleComplete = () => {
|
||||
const newCompleted = new Set(completed);
|
||||
newCompleted.add(activeStep);
|
||||
setCompleted(newCompleted);
|
||||
|
||||
/**
|
||||
* Sigh... it would be much nicer to replace the following if conditional with
|
||||
* `if (!this.allStepsComplete())` however state is not set when we do this,
|
||||
* thus we have to resort to not being very DRY.
|
||||
*/
|
||||
if (completed.size !== totalSteps() - skippedSteps()) {
|
||||
handleNext();
|
||||
}
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
setActiveStep(0);
|
||||
setCompleted(new Set());
|
||||
setSkipped(new Set());
|
||||
};
|
||||
|
||||
const isStepSkipped = (step) => {
|
||||
return skipped.has(step);
|
||||
};
|
||||
|
||||
const handleChange = (event) => {
|
||||
setState({
|
||||
...state,
|
||||
[event.target.name]: event.target.checked
|
||||
});
|
||||
};
|
||||
|
||||
function isStepComplete(step) {
|
||||
return completed.has(step);
|
||||
}
|
||||
function refresh() {
|
||||
document
|
||||
.location
|
||||
.reload(true);
|
||||
console.log("refresh")
|
||||
}
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
spacing={4}
|
||||
direction="row"
|
||||
justify="space-between"
|
||||
alignItems="flex-start">
|
||||
<Grid item lg={3} md={6} xl={4} xs={12}>
|
||||
<Card {...rest} className={clsx(classes.root, className)}>
|
||||
<CardContent>
|
||||
<div id="fb-root"></div>
|
||||
<script
|
||||
async
|
||||
defer
|
||||
crossorigin="anonymous"
|
||||
src="https://connect.facebook.net/fr_FR/sdk.js#xfbml=1&version=v8.0&appId=2332071840142634&autoLogAppEvents=1"
|
||||
nonce="O28M4TTm"></script>
|
||||
<div className={classes.details}>
|
||||
<div>
|
||||
<Typography gutterBottom variant="h5">
|
||||
{user.lastname}
|
||||
{user.firstname}
|
||||
<a href="#" onClick={refresh}><RefreshIcon className={classes.menuButton}/></a>
|
||||
</Typography>
|
||||
<Typography
|
||||
className={classes.locationText}
|
||||
color="textSecondary"
|
||||
variant="body1">
|
||||
<MailIcon className={classes.menuButton}/>
|
||||
: {user.email}<br/>
|
||||
<PhoneIcon className={classes.menuButton}/>
|
||||
: {user.phone}<br/>
|
||||
<LinkedInIcon className={classes.menuButton}/>
|
||||
: {(user.linkedin && user.linkedin != '' && user.linkedin != 'null')
|
||||
? <a href={user.linkedin} target="_blank">Lien sur mon linkedIn</a>
|
||||
: 'Non renseigné'}<br/>
|
||||
<PublicIcon className={classes.menuButton}/>
|
||||
: {(user.website && user.website != '' && user.website != 'null')
|
||||
? <a href={user.website} target="_blank">Lien sur mon site</a>
|
||||
: 'Non renseigné'}<br/>
|
||||
|
||||
|
||||
|
||||
</Typography>
|
||||
|
||||
</div>
|
||||
{/* <Avatar
|
||||
className={classes.avatar}
|
||||
src={publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.postedContentUrl + logoUrl}/> */}
|
||||
</div>
|
||||
<div>
|
||||
<Box m={3}/>
|
||||
<Divider/>
|
||||
<Box m={3}/>
|
||||
<Typography
|
||||
className={classes.locationText}
|
||||
color="textSecondary"
|
||||
variant="body1">
|
||||
|
||||
<DuoIcon className={classes.menuButton}/>
|
||||
: {(user.alias && user.alias != '' && user.alias != 'null')
|
||||
? <a
|
||||
href={publicRuntimeConfig.cvThequeUrl + "/talent/" + user.alias}
|
||||
target="_blank">Voir mon profil TalentsTube
|
||||
</a>
|
||||
: 'Non renseigné'}<br/>
|
||||
<div
|
||||
class="fb-share-button"
|
||||
data-href={publicRuntimeConfig.cvThequeUrl + "/talent/" + user.alias}
|
||||
data-layout="button_count"
|
||||
data-size="small">
|
||||
|
||||
<Facebook className={classes.menuButton}/>
|
||||
:
|
||||
<a
|
||||
target="_blank"
|
||||
href={"https://www.facebook.com/sharer/sharer.php?u=" + publicRuntimeConfig.cvThequeUrl + "/talent/" + user.alias + "%2F&src=sdkpreparse"}
|
||||
class="fb-xfbml-parse-ignore"> Partager mon profil
|
||||
</a>
|
||||
</div>
|
||||
</Typography>
|
||||
</div>
|
||||
{/* <div className={classes.progress}>
|
||||
<Typography variant="body1">Etat du Profil: 70%</Typography>
|
||||
<LinearProgress value={70} variant="determinate"/>
|
||||
</div> */}
|
||||
|
||||
</CardContent>
|
||||
<Box m={2}/>
|
||||
<Divider/>
|
||||
<Box m={2}/>
|
||||
<div className={classes.information}>
|
||||
<Typography className={classes.texteBlanc} align="left"></Typography>
|
||||
</div>
|
||||
{/* <CardActions>
|
||||
<Button className={classes.uploadButton} color="primary" variant="text">
|
||||
Remplacer une photo de profil
|
||||
</Button>
|
||||
<Button variant="text">Supprimer photo de profil</Button>
|
||||
</CardActions> */}
|
||||
<Box m={1}/>
|
||||
<Divider/>
|
||||
{/* <CardContent>
|
||||
<Typography variant="body1"></Typography>
|
||||
<FormControlLabel
|
||||
value="end"
|
||||
control={< Switch checked = {
|
||||
state.checkedA
|
||||
}
|
||||
onChange = {
|
||||
handleChange
|
||||
}
|
||||
name = "checkedA" color = "primary" />}
|
||||
label="Je souhaite afficher mon profil sur la CV Vidéothèque Talents Tube"
|
||||
labelPlacement="start"/>
|
||||
|
||||
</CardContent> */}
|
||||
|
||||
|
||||
|
||||
<CardActions>
|
||||
|
||||
<Stepper nonLinear activeStep={activeStep} orientation="vertical">
|
||||
{steps.map((label, index) => {
|
||||
const stepProps = {};
|
||||
const buttonProps = {};
|
||||
if (isStepOptional(index)) {
|
||||
buttonProps.optional = <Typography variant="caption">Optional</Typography>;
|
||||
}
|
||||
if (isStepSkipped(index)) {
|
||||
stepProps.completed = false;
|
||||
}
|
||||
return (
|
||||
<Step key={label} className={classes.actionsContainer} {...stepProps}>
|
||||
<StepButton
|
||||
onClick={handleStep(index)}
|
||||
completed={isStepComplete(index)}
|
||||
{...buttonProps}>
|
||||
{label}
|
||||
</StepButton>
|
||||
|
||||
</Step>
|
||||
);
|
||||
})}
|
||||
</Stepper>
|
||||
</CardActions>
|
||||
<Divider/>
|
||||
|
||||
<div>
|
||||
|
||||
<div>
|
||||
|
||||
<div>
|
||||
|
||||
{/* {isStepOptional(activeStep) && !completed.has(activeStep) && (
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleSkip}
|
||||
className={classes.button}
|
||||
>
|
||||
Skip
|
||||
</Button>
|
||||
)} */}
|
||||
|
||||
{/* {activeStep !== steps.length &&
|
||||
(completed.has(activeStep) ? (
|
||||
<Typography variant="caption" className={classes.completed}>
|
||||
Step {activeStep + 1} already completed
|
||||
</Typography>
|
||||
) : (
|
||||
<Button variant="contained" color="primary" onClick={handleComplete}>
|
||||
{completedSteps() === totalSteps() - 1 ? 'Finish' : 'Complete Step'}
|
||||
</Button>
|
||||
))} */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<Box m={2}/>
|
||||
<CardContent>
|
||||
<BottomNavigation className={classes.stickToBottom}>
|
||||
<Button
|
||||
disabled={activeStep === 0}
|
||||
onClick={handleBack}
|
||||
className={classes.button}>
|
||||
Etape précédente
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleNext}
|
||||
className={classes.button}>
|
||||
Etape suivante
|
||||
</Button>
|
||||
{/* <BottomNavigationAction label="Recents" icon={< RestoreIcon />}/>
|
||||
<BottomNavigationAction label="Favorites" icon={< FavoriteIcon />}/>
|
||||
<BottomNavigationAction label="Nearby" icon={< LocationOnIcon />}/> */}
|
||||
</BottomNavigation>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
</Grid>
|
||||
<Grid item lg={9} md={6} xl={8} xs={12}>
|
||||
{getStepContent(activeStep)}
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
AccountProfile.propTypes = {
|
||||
className: PropTypes.string
|
||||
};
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
user: state.user,
|
||||
loading: !!state.user.loading,
|
||||
errors: state.user.errors || ownProps.errors
|
||||
};
|
||||
}
|
||||
|
||||
export default withStyles(styles)(connect(mapStateToProps, {updateUserRequest})(AccountProfile))
|
||||
@@ -0,0 +1,306 @@
|
||||
import React, {Fragment} from 'react';
|
||||
import {Hidden} from '@material-ui/core';
|
||||
import PropTypes from 'prop-types';
|
||||
import clsx from 'clsx';
|
||||
// import AccountStep from "../../components/organisms/AccountStep";
|
||||
import AccountEtape1 from './AccountEtape1';
|
||||
import AccountEtape2 from './AccountEtape2';
|
||||
import AccountEtape3 from './AccountEtape3';
|
||||
import {withStyles} from '@material-ui/core/styles';
|
||||
// import Switch from '@material-ui/core/Switch';
|
||||
import PhoneIcon from '@material-ui/icons/Phone';
|
||||
import MailIcon from '@material-ui/icons/Mail';
|
||||
import PublicIcon from '@material-ui/icons/Public';
|
||||
import DuoIcon from '@material-ui/icons/Duo';
|
||||
import LinkedInIcon from '@material-ui/icons/LinkedIn';
|
||||
import Facebook from '@material-ui/icons/Facebook';
|
||||
// import FormGroup from '@material-ui/core/FormGroup'; import FormControlLabel
|
||||
// from '@material-ui/core/FormControlLabel'; import FormControl from
|
||||
// '@material-ui/core/FormControl';
|
||||
import {updateUserRequest, updateUserPictureRequest} from '../../actions/user'
|
||||
import {makeStyles} from '@material-ui/styles';
|
||||
import {connect} from 'react-redux'
|
||||
import getConfig from 'next/config'
|
||||
import Router from 'next/router'
|
||||
|
||||
import BottomNavigation from '@material-ui/core/BottomNavigation';
|
||||
// import BottomNavigationAction from
|
||||
// '@material-ui/core/BottomNavigationAction';
|
||||
import RefreshIcon from '@material-ui/icons/Refresh';
|
||||
// import FavoriteIcon from '@material-ui/icons/Favorite'; import LocationOnIcon
|
||||
// from '@material-ui/icons/LocationOn';
|
||||
|
||||
import Box from '@material-ui/core/Box';
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardActions,
|
||||
CardContent,
|
||||
Avatar,
|
||||
Typography,
|
||||
Divider,
|
||||
Button,
|
||||
LinearProgress,
|
||||
Stepper,
|
||||
Step,
|
||||
StepLabel,
|
||||
StepContent,
|
||||
StepButton,
|
||||
Paper,
|
||||
Grid
|
||||
} from '@material-ui/core';
|
||||
|
||||
const styles = theme => ({
|
||||
container: {
|
||||
width: '100%'
|
||||
},
|
||||
button: {
|
||||
textTransform: 'inherit',
|
||||
marginLeft: theme.spacing(8),
|
||||
marginRight: theme.spacing(8),
|
||||
padding: theme.spacing(1.2, 2),
|
||||
color: theme.palette.secondary.main,
|
||||
backgroundColor: theme.palette.primary.important
|
||||
},
|
||||
stickToBottom: {
|
||||
width: '100%',
|
||||
position: 'fixed',
|
||||
bottom: 0
|
||||
}
|
||||
});
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
root: {},
|
||||
details: {
|
||||
display: 'flex'
|
||||
},
|
||||
avatar: {
|
||||
marginLeft: 'auto',
|
||||
height: 110,
|
||||
width: 100,
|
||||
flexShrink: 0,
|
||||
flexGrow: 0
|
||||
},
|
||||
progress: {
|
||||
marginTop: theme.spacing(2)
|
||||
},
|
||||
information: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
[
|
||||
theme
|
||||
.breakpoints
|
||||
.up('md')
|
||||
]: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
justifyContent: 'space-around',
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
padding: theme.spacing(7, 7)
|
||||
},
|
||||
'& a': {
|
||||
textDecoration: 'none'
|
||||
}
|
||||
},
|
||||
texteBlanc: {
|
||||
color: "#fff"
|
||||
},
|
||||
uploadButton: {
|
||||
marginRight: theme.spacing(2)
|
||||
},
|
||||
button: {
|
||||
marginTop: theme.spacing(1),
|
||||
marginRight: theme.spacing(1)
|
||||
},
|
||||
actionsContainer: {
|
||||
marginBottom: theme.spacing(2)
|
||||
},
|
||||
resetContainer: {
|
||||
padding: theme.spacing(3)
|
||||
},
|
||||
iconButton:{
|
||||
marginTop: "50px",
|
||||
|
||||
[theme.breakpoints.down('md')]: {
|
||||
marginTop: "50px",
|
||||
|
||||
},
|
||||
},
|
||||
button: {
|
||||
textTransform: 'inherit',
|
||||
marginTop: theme.spacing(4),
|
||||
marginBottom: theme.spacing(2),
|
||||
padding: theme.spacing(1.2, 1),
|
||||
borderRadius: '3px',
|
||||
color: theme.palette.secondary.main,
|
||||
backgroundColor: theme.palette.primary.important,
|
||||
},
|
||||
title:{
|
||||
fontFamily: 'Roboto',
|
||||
fontSize: '1.625em',
|
||||
fontWeight: '600',
|
||||
padding: theme.spacing(3, 0),
|
||||
},
|
||||
texteEtape:{
|
||||
fontSize: '1em',
|
||||
fontWeight: '300',
|
||||
|
||||
},
|
||||
conteneur:{
|
||||
width:'400px',
|
||||
},
|
||||
tabContainer:{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems:'center',
|
||||
textAlign:'center',
|
||||
align:'center',
|
||||
alignSelf:'center',
|
||||
},
|
||||
|
||||
}));
|
||||
|
||||
const AccountProfile = props => {
|
||||
const {
|
||||
className,
|
||||
user,
|
||||
...rest
|
||||
} = props;
|
||||
const logoUrl = user.picture;
|
||||
const classes = useStyles();
|
||||
|
||||
// const user = { name: 'Laurent Laniau', city: 'Questembert', country:
|
||||
// 'France', timezone: '', avatar: '/images/avatars/avatar_11.png' };
|
||||
const {publicRuntimeConfig} = getConfig()
|
||||
|
||||
return (
|
||||
<Fragment >
|
||||
<div className={classes.tabContainer}>
|
||||
<div className={classes.conteneur}>
|
||||
<Typography gutterBottom align="center" >
|
||||
<span className={classes.title}>
|
||||
<img
|
||||
alt="talents-tube"
|
||||
src='/statique/images/inscription/candidature-video-envoyee.svg'
|
||||
className={classes.iconButton}/>
|
||||
</span>
|
||||
</Typography>
|
||||
<Typography gutterBottom align="center" >
|
||||
<span className={classes.title}>Bravo !<br></br>
|
||||
Votre candidature a été envoyée
|
||||
</span>
|
||||
</Typography>
|
||||
<Typography gutterBottom align="center" className={classes.conteneur}>
|
||||
<div className={classes.texteEtape}>
|
||||
Pour suivre l’état d’avancement de vos candidatures, rendez-vous sur votre espace <b>Mon compte</b>.
|
||||
</div>
|
||||
</Typography>
|
||||
|
||||
|
||||
<Typography gutterBottom align="center" className={classes.text}>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
className={classes.button}
|
||||
classes={{ root: classes.rootButton }}
|
||||
onClick={() => Router.push('/Candidatures')}
|
||||
>
|
||||
Accéder à Mon compte
|
||||
</Button>
|
||||
|
||||
</Typography>
|
||||
{/* <section className={classes.bottomContainer}>
|
||||
<Button
|
||||
variant="contained"
|
||||
className={classes.button}
|
||||
classes={{ root: classes.rootButton }}
|
||||
onClick={() => Router.push('/Login')}
|
||||
>
|
||||
Connexion
|
||||
</Button>
|
||||
</section> */}
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
// <Grid
|
||||
// container
|
||||
// spacing={4}
|
||||
// direction="row"
|
||||
// justify="space-between"
|
||||
// alignItems="flex-start">
|
||||
|
||||
// <Grid item lg={9} md={6} xl={8} xs={12}>
|
||||
// <Fragment>
|
||||
// <Hidden> </Hidden>
|
||||
// <Hidden> </Hidden>
|
||||
|
||||
// <Card
|
||||
// variant="outlined"
|
||||
// style={{
|
||||
// width: 420 + "px",
|
||||
// textAlign:"center"
|
||||
// }}>
|
||||
// <CardActions></CardActions>
|
||||
// <CardContent>
|
||||
// <Typography>
|
||||
// Tu n'as pas tout dit dans ta vidéo?<br/>
|
||||
// Pour mettre toutes les chances de ton côté,
|
||||
// <b> dépose ton CV old school (format pdf, word)!</b>
|
||||
// </Typography>
|
||||
// </CardContent>
|
||||
|
||||
// </Card>
|
||||
// <Hidden> </Hidden>
|
||||
// <Card
|
||||
// variant="outlined"
|
||||
// style={{
|
||||
// width: 420 + "px",
|
||||
// textAlign:"center"
|
||||
// }}>
|
||||
// <CardContent>
|
||||
// <AccountEtape3></AccountEtape3>
|
||||
// </CardContent>
|
||||
// </Card>
|
||||
// <Hidden> </Hidden>
|
||||
// <Hidden> </Hidden>
|
||||
// <Card
|
||||
// variant="outlined"
|
||||
// style={{
|
||||
// width: 420 + "px",
|
||||
// textAlign:"center"
|
||||
// }}>
|
||||
// <CardContent>
|
||||
|
||||
// <Button
|
||||
// variant="contained"
|
||||
// color="primary"
|
||||
// onClick={() => Router.push(`/Candidatures`)}
|
||||
// className={classes.button}>
|
||||
// Voir mes candidatures
|
||||
// </Button>
|
||||
// </CardContent>
|
||||
// </Card>
|
||||
// </Fragment>
|
||||
|
||||
// </Grid>
|
||||
// <Grid item lg={3} md={6} xl={4} xs={12}></Grid>
|
||||
|
||||
// </Grid>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
AccountProfile.propTypes = {
|
||||
className: PropTypes.string
|
||||
};
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
user: state.user,
|
||||
loading: !!state.user.loading,
|
||||
errors: state.user.errors || ownProps.errors
|
||||
};
|
||||
}
|
||||
|
||||
export default withStyles(styles)(connect(mapStateToProps, {updateUserRequest})(AccountProfile))
|
||||
@@ -0,0 +1,147 @@
|
||||
import React from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Stepper from '@material-ui/core/Stepper';
|
||||
import Step from '@material-ui/core/Step';
|
||||
import StepButton from '@material-ui/core/StepButton';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import AccountEtape1 from '../organisms/AccountEtape1';
|
||||
import AccountEtape2 from '../organisms/AccountEtape2';
|
||||
import AccountEtape3 from '../organisms/AccountEtape3';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
width: '100%',
|
||||
},
|
||||
button: {
|
||||
marginRight: theme.spacing(1),
|
||||
},
|
||||
completed: {
|
||||
display: 'inline-block',
|
||||
},
|
||||
instructions: {
|
||||
marginTop: theme.spacing(1),
|
||||
marginBottom: theme.spacing(1),
|
||||
},
|
||||
}));
|
||||
|
||||
function getSteps() {
|
||||
return ['Informations personnelles', 'Vidéo de présentation', 'Expériences professionnelles'];
|
||||
}
|
||||
|
||||
function getStepContent(step) {
|
||||
switch (step) {
|
||||
case 0:
|
||||
return <AccountEtape1 ></AccountEtape1>;
|
||||
case 1:
|
||||
return <AccountEtape2></AccountEtape2>;
|
||||
case 2:
|
||||
return <AccountEtape3></AccountEtape3>;
|
||||
default:
|
||||
return 'Unknown step';
|
||||
}
|
||||
}
|
||||
|
||||
export default function HorizontalNonLinearStepper() {
|
||||
const classes = useStyles();
|
||||
const [activeStep, setActiveStep] = React.useState(0);
|
||||
const [completed, setCompleted] = React.useState({});
|
||||
const steps = getSteps();
|
||||
|
||||
const totalSteps = () => {
|
||||
return steps.length;
|
||||
};
|
||||
|
||||
const completedSteps = () => {
|
||||
return Object.keys(completed).length;
|
||||
};
|
||||
|
||||
const isLastStep = () => {
|
||||
return activeStep === totalSteps() - 1;
|
||||
};
|
||||
|
||||
const allStepsCompleted = () => {
|
||||
return completedSteps() === totalSteps();
|
||||
};
|
||||
|
||||
const handleNext = () => {
|
||||
const newActiveStep =
|
||||
isLastStep() && !allStepsCompleted()
|
||||
? // It's the last step, but not all steps have been completed,
|
||||
// find the first step that has been completed
|
||||
steps.findIndex((step, i) => !(i in completed))
|
||||
: activeStep + 1;
|
||||
setActiveStep(newActiveStep);
|
||||
};
|
||||
|
||||
const handleBack = () => {
|
||||
setActiveStep((prevActiveStep) => prevActiveStep - 1);
|
||||
};
|
||||
|
||||
const handleStep = (step) => () => {
|
||||
setActiveStep(step);
|
||||
};
|
||||
|
||||
const handleComplete = () => {
|
||||
const newCompleted = completed;
|
||||
newCompleted[activeStep] = true;
|
||||
setCompleted(newCompleted);
|
||||
handleNext();
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
setActiveStep(0);
|
||||
setCompleted({});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Stepper alternativeLabel nonLinear activeStep={activeStep}>
|
||||
{steps.map((label, index) => (
|
||||
<Step key={label}>
|
||||
<StepButton onClick={handleStep(index)} completed={completed[index]}>
|
||||
{label}
|
||||
</StepButton>
|
||||
</Step>
|
||||
))}
|
||||
</Stepper>
|
||||
<div>
|
||||
{allStepsCompleted() ? (
|
||||
<div>
|
||||
{/* <Typography className={classes.instructions}>
|
||||
Toutes les étapes sont terminées -
|
||||
</Typography>
|
||||
<Button onClick={handleReset}>Annuler</Button> */}
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<Typography className={classes.instructions}>{getStepContent(activeStep)}</Typography>
|
||||
<div>
|
||||
{/* <Button disabled={activeStep === 0} onClick={handleBack} className={classes.button}>
|
||||
Précédent
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleNext}
|
||||
className={classes.button}
|
||||
>
|
||||
Suivant
|
||||
</Button> */}
|
||||
{/* {activeStep !== steps.length &&
|
||||
(completed[activeStep] ? (
|
||||
<Typography variant="caption" className={classes.completed}>
|
||||
Step {activeStep + 1} already completed
|
||||
</Typography>
|
||||
) : (
|
||||
<Button variant="contained" color="primary" onClick={handleComplete}>
|
||||
{completedSteps() === totalSteps() - 1 ? 'Etape valide' : 'Processus terminé'}
|
||||
</Button>
|
||||
))} */}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import React, { useState } from 'react';
|
||||
import clsx from 'clsx';
|
||||
import PropTypes from 'prop-types';
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import Link from 'next/link';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardContent,
|
||||
CardActions,
|
||||
Divider,
|
||||
Grid,
|
||||
Button,
|
||||
TextField
|
||||
} from '@material-ui/core';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
root: {}
|
||||
}));
|
||||
|
||||
const AccountVideoPres = props => {
|
||||
const { className, ...rest } = props;
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<Card
|
||||
{...rest}
|
||||
className={clsx(classes.root, className)}
|
||||
>
|
||||
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
AccountVideoPres.propTypes = {
|
||||
className: PropTypes.string
|
||||
};
|
||||
|
||||
export default AccountVideoPres;
|
||||
@@ -0,0 +1,849 @@
|
||||
import React, { Component, Fragment, useState } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { Button, Typography, Divider, Hidden } from '@material-ui/core';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Input from '@material-ui/core/Input';
|
||||
import { connect } from 'react-redux'
|
||||
import { postAdAnswerRequest } from '../../actions/answer'
|
||||
import { updateUserRequest, updateUserPictureRequest } from '../../actions/user'
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight';
|
||||
import Loader from './../templates/loader'
|
||||
import getConfig from 'next/config'
|
||||
import 'video-react/dist/video-react.css';
|
||||
import { Player } from 'video-react';
|
||||
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
|
||||
import GooglePlaceAutocomplete from 'mui-places-autocomplete'
|
||||
import { geocodeByAddress } from 'react-places-autocomplete'
|
||||
import FormControl from '@material-ui/core/FormControl'
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
import DialogContentText from '@material-ui/core/DialogContentText';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import { uploadMediaCv } from '../../actions/mediaCv'
|
||||
import GetApp from '@material-ui/icons/GetApp';
|
||||
// import PlacesAutocomplete from 'react-places-autocomplete';
|
||||
// import {
|
||||
// geocodeByAddress,
|
||||
// geocodeByPlaceId,
|
||||
// getLatLng,
|
||||
// } from 'react-places-autocomplete';
|
||||
// import GoogleAutoComplete from 'react-google-autocomplete-address-fields';
|
||||
|
||||
|
||||
|
||||
const styles = theme => ({
|
||||
container: {
|
||||
width: '100%',
|
||||
},
|
||||
form: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: '24px',
|
||||
paddingBottom: theme.spacing(8),
|
||||
marginBottom: theme.spacing(8),
|
||||
'&>div': {
|
||||
marginTop: theme.spacing(1.5),
|
||||
marginBottom: theme.spacing(1.5),
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
padding: '0 calc(25vw + 24px)',
|
||||
},
|
||||
|
||||
},
|
||||
importContainer: {
|
||||
alignSelf: 'flex-start',
|
||||
},
|
||||
textField: {
|
||||
width: '100%',
|
||||
'&:disabled': {
|
||||
color: theme.palette.secondary.dark,
|
||||
},
|
||||
'& label': {
|
||||
color: theme.palette.primary.dark,
|
||||
},
|
||||
'& fieldset:hover': {
|
||||
borderColor: theme.palette.primary.main + ' !important',
|
||||
},
|
||||
},
|
||||
foot: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
zIndex: '10',
|
||||
width: '100%',
|
||||
position: 'fixed',
|
||||
bottom: 0,
|
||||
padding: theme.spacing(1.2, 0),
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
boxShadow: '0px 0px 10px rgba(30, 35, 39, 0.10)',
|
||||
},
|
||||
rootButton: {
|
||||
textTransform: 'inherit',
|
||||
|
||||
},
|
||||
button: {
|
||||
textTransform: 'inherit',
|
||||
marginLeft: theme.spacing(8),
|
||||
marginRight: theme.spacing(8),
|
||||
padding: theme.spacing(1.2, 2),
|
||||
color: theme.palette.secondary.main,
|
||||
backgroundColor: theme.palette.primary.important,
|
||||
},
|
||||
containerImport:{
|
||||
width:"100%",
|
||||
textAlign:"left",
|
||||
align:"left",
|
||||
alignItems:"flex-start",
|
||||
border: 0,
|
||||
margin: 0,
|
||||
display: "inline-flex",
|
||||
padding: 0,
|
||||
position: "relative",
|
||||
flexDirection: "column",
|
||||
verticalAlign: "top",
|
||||
marginBottom:"20px !important"
|
||||
},
|
||||
importButton: {
|
||||
padding: '4px 8px',
|
||||
textTransform: 'inherit',
|
||||
border: '2px solid #1E2327',
|
||||
color: '#1E2327',
|
||||
},
|
||||
remplacerButton: {
|
||||
color: '#1E2327',
|
||||
borderColor: '#1E2327',
|
||||
border: '2px solid',
|
||||
padding: '9.6px 8px',
|
||||
margin:'15px 0px 25px 0px',
|
||||
textTransform: 'inherit',
|
||||
},
|
||||
popup: {
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
fontWeight: '400',
|
||||
color: '#8E9092'
|
||||
},
|
||||
player:{
|
||||
width:"100px"
|
||||
},
|
||||
labelGeoloc:{
|
||||
paddingLeft:"14px",
|
||||
fontSize: "0.8rem",
|
||||
color:"#1E2327",
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
|
||||
fontWeight: "400",
|
||||
lineHeight: "1",
|
||||
letterSpacing: "0.00938em", }
|
||||
,conteneurGoogle:{
|
||||
border:"1px solid rgb(200, 200, 200)",
|
||||
borderRadius :"5px",
|
||||
padding:"5px 0px",
|
||||
|
||||
|
||||
},
|
||||
conteneurGoogleComposant:{
|
||||
paddingLeft:"14px"
|
||||
}
|
||||
|
||||
});
|
||||
export const getCountryFromAddress = (address) => {
|
||||
if (!address) {
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
const country = address.address_components.filter(component => component.types.includes('country')).map(c => c.long_name)[0];
|
||||
console.log('using country for filter ' + country);
|
||||
return country;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
const { publicRuntimeConfig } = getConfig()
|
||||
|
||||
//https://xd.adobe.com/view/ba98331a-9145-4d67-7e27-25a36e519ef4-cca9/screen/a96779d7-bdb3-410a-8f19-e6987acb98ee/Candidature-Step-3
|
||||
class Answer extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
|
||||
const viewValue = this.props.value;
|
||||
|
||||
this.onSuggestionSelected = this.onSuggestionSelected.bind(this);
|
||||
this.onChange = this.onChange.bind(this);
|
||||
|
||||
}
|
||||
|
||||
state = {
|
||||
file: null,
|
||||
firstname: '',
|
||||
lastname: '',
|
||||
phone: '',
|
||||
currentJob: '',
|
||||
geoloc: '',
|
||||
value:'',
|
||||
route: '',
|
||||
street_number: '',
|
||||
locality: '',
|
||||
administrative_area_level_2: '',
|
||||
administrative_area_level_1: '',
|
||||
country: '',
|
||||
postal_code: '',
|
||||
formatted_address:"",
|
||||
lat:"",
|
||||
lng:"",
|
||||
linkedin: '',
|
||||
twitter: '',
|
||||
website: '',
|
||||
mediaId: null,
|
||||
mediaUrl: null,
|
||||
thumbnails:null,
|
||||
heure: null,
|
||||
companyId: null,
|
||||
address:'',
|
||||
errorMessage:'',
|
||||
open: false,
|
||||
loading: true,
|
||||
openSnack: false,
|
||||
cv:false,
|
||||
};
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
this.setState({
|
||||
firstname: this.state.firstname,
|
||||
lastname: this.state.lastname,
|
||||
phone: this.state.phone,
|
||||
currentJob: this.state.currentJob,
|
||||
geoloc: this.state.geoloc,
|
||||
value: this.state.value,
|
||||
route: this.state.route,
|
||||
street_number: this.state.street_number,
|
||||
locality: this.state.locality,
|
||||
administrative_area_level_2: this.state.administrative_area_level_2,
|
||||
administrative_area_level_1: this.state.administrative_area_level_1,
|
||||
country: this.state.country,
|
||||
postal_code: this.state.postal_code,
|
||||
formatted_address : this.state.formatted_address,
|
||||
lat:this.state.lat,
|
||||
lng: this.state.lng,
|
||||
linkedin: this.state.linkedin,
|
||||
twitter: this.state.twitter,
|
||||
website: this.state.website,
|
||||
mediaId: nextProps.mediaId,
|
||||
mediaUrl: nextProps.mediaUrl,
|
||||
thumbnails: nextProps.thumbnails,
|
||||
heure: nextProps.heure,
|
||||
companyId: nextProps.companyId,
|
||||
cvLink: nextProps.cvLink,
|
||||
loading: nextProps.loading,
|
||||
openSnack: !!!_.isEmpty(nextProps.errors),
|
||||
})
|
||||
if (nextProps.loading) {
|
||||
const success = {};
|
||||
success.message ="CV mis à jour";
|
||||
console.log("CV mis à jour!!!")
|
||||
this.setState({ success });
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
console.log("ANSWER ! ");
|
||||
console.log(this.props);
|
||||
this.setState({
|
||||
firstname: this.props.user.firstname,
|
||||
lastname: this.props.user.lastname,
|
||||
phone: this.props.user.phone,
|
||||
currentJob: this.props.user.currentJob,
|
||||
value: this.props.user.geoloc && this.props.user.geoloc[0].formatted_address ? this.props.user.geoloc[0].formatted_address :"",
|
||||
geoloc: this.props.user.geoloc && this.props.user.geoloc[0].formatted_address ? this.props.user.geoloc[0].formatted_address :"",
|
||||
route: "",
|
||||
street_number: "",
|
||||
locality: "",
|
||||
administrative_area_level_2: "",
|
||||
administrative_area_level_1: "",
|
||||
country: "",
|
||||
postal_code: "",
|
||||
formatted_address:"",
|
||||
lat:"",
|
||||
lng:"",
|
||||
linkedin: this.props.user.linkedin,
|
||||
twitter: this.props.user.twitter,
|
||||
website: this.props.user.website,
|
||||
video: this.props.answer,
|
||||
mediaUrl : this.props.mediaUrl,
|
||||
thumbnails : this.props.thumbnails,
|
||||
heure : this.props.heure,
|
||||
loading: false,
|
||||
cvLink: this.props.user.cv
|
||||
|
||||
})
|
||||
console.log(this.state);
|
||||
}
|
||||
|
||||
inputFilesystemChange = (e) => {
|
||||
this.uploadMediaCv(e)
|
||||
}
|
||||
|
||||
uploadMediaCv = (e) => {
|
||||
var file = e.target.files[0]
|
||||
|
||||
const data = new FormData()
|
||||
data.append('upload', file)
|
||||
this.props.uploadMediaCv(data)
|
||||
}
|
||||
|
||||
AfficherSuccess() {
|
||||
if (!this.state.success || !this.state.success.message) {
|
||||
console.log("Erreur Upload CV");
|
||||
return "";
|
||||
} else if (this.state.success.length != 0 && this.state.success.message != "") {
|
||||
return (
|
||||
<Snackbar open={open} autoHideDuration={1000} onClose={() => this.setState({open: false})}>
|
||||
<Alert onClose={() => this.setState({open: false})} severity="success">
|
||||
{ReactHtmlParser(this.state.success.message)}
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
AfficherLienCv() {
|
||||
console.log("afficher lien");
|
||||
if (this.state.cvLink !="") {
|
||||
|
||||
return (
|
||||
|
||||
<Fragment>
|
||||
|
||||
<Typography >
|
||||
<a href={publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.postedContentCv + this.state.cvLink}
|
||||
target="_blank"
|
||||
style={{
|
||||
color:'#1E2327',
|
||||
'&:hover': {
|
||||
color: '#1E2327',
|
||||
},
|
||||
backgroundColor: '#F3F3F4',
|
||||
width:'100%',
|
||||
fontWeight: '500',
|
||||
fontSize: '1em',
|
||||
padding:'15px',
|
||||
margin:'20px 0',
|
||||
|
||||
}}
|
||||
>
|
||||
Visualiser mon CV
|
||||
</a>
|
||||
<br />
|
||||
|
||||
</Typography>
|
||||
|
||||
</Fragment>
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
openDialog() {
|
||||
this.setState({ open: true });
|
||||
}
|
||||
|
||||
closeDialog() {
|
||||
this.setState({ open: false });
|
||||
}
|
||||
|
||||
refreshDialog() {
|
||||
this.setState({ open: false });
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
onChange = (e) => {
|
||||
|
||||
this.setState({
|
||||
value: e.target.value
|
||||
});
|
||||
|
||||
if (e.target.value === '') {
|
||||
console.log('cleared');
|
||||
//this.props.onSelectionChanged('');
|
||||
}
|
||||
}
|
||||
|
||||
remplirLocation = (typeDonnee, donnee) =>{
|
||||
console.log("DEBUT remplirLocation");
|
||||
console.log(typeDonnee);
|
||||
console.log(donnee);
|
||||
if(typeDonnee=='"street_number"') {
|
||||
this.setState({ street_number: donnee.replace('"', '') })
|
||||
}else if(typeDonnee=='"route"') {
|
||||
this.setState({ route: donnee.replace('"', '') })
|
||||
}else if(typeDonnee=='"locality"') {
|
||||
this.setState({ locality: donnee.replace('"', '') })
|
||||
}else if(typeDonnee=='"administrative_area_level_2"') {
|
||||
this.setState({ administrative_area_level_2: donnee.replace('"', '') })
|
||||
}else if(typeDonnee=='"administrative_area_level_1"') {
|
||||
this.setState({ administrative_area_level_1: donnee.replace('"', '') })
|
||||
}else if(typeDonnee=='"country"') {
|
||||
this.setState({ country: donnee.replace('"', '') })
|
||||
}else if(typeDonnee=='"postal_code"') {
|
||||
this.setState({ postal_code: donnee.replace('"', '') })
|
||||
}
|
||||
console.log("FIN remplirLocation");
|
||||
|
||||
}
|
||||
|
||||
onSuggestionSelected = (suggestion) => {
|
||||
|
||||
console.log('Selected suggestion:', suggestion)
|
||||
let address = suggestion.description;
|
||||
var words = address.split(',');
|
||||
if(words.length<3){
|
||||
address = "mairie de "+address;
|
||||
}
|
||||
this.setState({ geoloc: address})
|
||||
this.setState({
|
||||
value: address
|
||||
});
|
||||
|
||||
geocodeByAddress(address)
|
||||
.then(address => {
|
||||
console.log("ADRESSE");
|
||||
console.log(address);
|
||||
if(address[0].address_components[0]){
|
||||
this.remplirLocation(JSON.stringify(address[0].address_components[0].types[0]), JSON.stringify(address[0].address_components[0].long_name))
|
||||
}
|
||||
if(address[0].address_components[1]){
|
||||
this.remplirLocation(JSON.stringify(address[0].address_components[1].types[0]), JSON.stringify(address[0].address_components[1].long_name))
|
||||
}
|
||||
if(address[0].address_components[2]){
|
||||
this.remplirLocation(JSON.stringify(address[0].address_components[2].types[0]), JSON.stringify(address[0].address_components[2].long_name))
|
||||
}
|
||||
if(address[0].address_components[3]){
|
||||
this.remplirLocation(JSON.stringify(address[0].address_components[3].types[0]), JSON.stringify(address[0].address_components[3].long_name))
|
||||
}
|
||||
if(address[0].address_components[4]){
|
||||
this.remplirLocation(JSON.stringify(address[0].address_components[4].types[0]), JSON.stringify(address[0].address_components[4].long_name))
|
||||
}
|
||||
if(address[0].address_components[5]){
|
||||
this.remplirLocation(JSON.stringify(address[0].address_components[5].types[0]), JSON.stringify(address[0].address_components[5].long_name))
|
||||
}
|
||||
if(address[0].address_components[6]){
|
||||
this.remplirLocation(JSON.stringify(address[0].address_components[6].types[0]), JSON.stringify(address[0].address_components[6].long_name))
|
||||
}
|
||||
if(address[0].geometry){
|
||||
|
||||
console.log(address[0].geometry.location_type);
|
||||
let gps =JSON.stringify(address[0].geometry.location);
|
||||
const obj = JSON.parse(gps);
|
||||
this.setState({ formatted_address: JSON.stringify(address[0].formatted_address) })
|
||||
this.setState({ lat: obj.lat.toString()})
|
||||
this.setState({ lng: obj.lng.toString()})
|
||||
}
|
||||
|
||||
|
||||
// console.log("GEOLOC ON geocodeByAddress")
|
||||
// console.log(this.state.geoloc)
|
||||
// document.getElementById("geoloc").value =JSON.stringify(address[0]);
|
||||
// this.props.onSelectionChanged(address[0]);
|
||||
})
|
||||
.catch(error => console.error('Error', error))
|
||||
}
|
||||
|
||||
onSuggestionSelected(suggestion) {
|
||||
|
||||
// Add your business logic here. In this case we just log...
|
||||
console.log('Selected suggestion:', suggestion)
|
||||
}
|
||||
|
||||
renderFunc = ({ getInputProps, getSuggestionItemProps, suggestions, loading }) => (
|
||||
<div>
|
||||
<input className={styles.inputSearchBar} {...getInputProps()} />
|
||||
<div >
|
||||
{loading && <div>Loading...</div>}
|
||||
{suggestions.map(suggestion => {
|
||||
const className = suggestion.active ? 'suggestion-item--active' : 'suggestion-item';
|
||||
const style = suggestion.active
|
||||
? { backgroundColor: 'red', cursor: 'pointer',border: '1px solid' }
|
||||
: { backgroundColor: '#123456', cursor: 'pointer',border: '1px solid' };
|
||||
return (<div {...getSuggestionItemProps(suggestion,{className,style})}>
|
||||
<span >{suggestion.description}</span>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
callbackFunc = ( autoCompleteData ) => {
|
||||
//You can use the address data, passed by autocomplete as you want.
|
||||
}
|
||||
|
||||
|
||||
|
||||
handleChange = (e) => {
|
||||
this.setState({ [e.target.name]: e.target.value })
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
onSubmit = (e) => {
|
||||
e.preventDefault()
|
||||
//TODO : Vérifier si le nom et prénom sont renseignés
|
||||
console.log("firstname")
|
||||
console.log(this.state.firstname)
|
||||
const data = new FormData()
|
||||
|
||||
data.append('firstname', this.state.firstname)
|
||||
data.append('lastname', this.state.lastname)
|
||||
data.append('phone', this.state.phone)
|
||||
data.append('currentJob', this.state.currentJob)
|
||||
console.log("GEOLOC ON SUBMIT")
|
||||
console.log(this.state)
|
||||
data.append('geoloc', this.state.geoloc)
|
||||
|
||||
data.append('street_number', this.state.street_number.replace('"', ''))
|
||||
data.append('route', this.state.route.replace('"', ''))
|
||||
data.append('locality', this.state.locality.replace('"', ''))
|
||||
data.append('administrative_area_level_2', this.state.administrative_area_level_2.replace('"', ''))
|
||||
data.append('administrative_area_level_1', this.state.administrative_area_level_1.replace('"', ''))
|
||||
data.append('country', this.state.country.replace('"', ''))
|
||||
data.append('postal_code', this.state.postal_code.replace('"', ''))
|
||||
data.append('formatted_address', this.state.formatted_address.replace('"', ''))
|
||||
data.append('lat', this.state.lat)
|
||||
data.append('lng', this.state.lng)
|
||||
//
|
||||
data.append('linkedin', this.state.linkedin)
|
||||
data.append('twitter', this.state.twitter)
|
||||
data.append('website', this.state.website)
|
||||
|
||||
//TODO:maybe add this two in a single transactionnal saga
|
||||
this.props.updateUserRequest(data)
|
||||
//TODO: faire appel à une méthode qui va encoyer le mail a l'entreprise
|
||||
|
||||
// this.props.companyMails.map((user) =>
|
||||
// //TODO Envoyer un mail a chaque user
|
||||
// console.log(user.email)
|
||||
// )
|
||||
// US 471 : TODO envoyer le lien du cv pour le mettre dans la candidature (this.state.cvLink)
|
||||
|
||||
console.log(this.state.cvLink, "lien CV")
|
||||
this.props.postAdAnswerRequest(
|
||||
{
|
||||
adId: this.props.adId,
|
||||
companyId: this.props.companyId,
|
||||
mediaId: this.props.mediaId,
|
||||
mediaUrl: this.props.mediaUrl,
|
||||
thumbnails : this.props.thumbnails,
|
||||
heure: this.props.heure
|
||||
})
|
||||
}
|
||||
|
||||
// inputFilesystemChange = (e) => {
|
||||
|
||||
// console.log("inputFilesystemChange");
|
||||
// var file = e.target.files[0]
|
||||
// this.setState({ picture: file })
|
||||
|
||||
// const data = new FormData()
|
||||
// data.append('file', file)
|
||||
// this.props.updateUserPictureRequest(data)
|
||||
// }
|
||||
recupererAdresse =()=>{
|
||||
geocodeByAddress('1 rue de la laine, Questembert')
|
||||
.then(results => getLatLng(results[0]))
|
||||
.then(({ lat, lng }) =>
|
||||
console.log('Successfully got latitude and longitude', { lat, lng })
|
||||
)
|
||||
geocodeByAddress('1 rue de la laine, Questembert')
|
||||
.then(results => console.log(results))
|
||||
.catch(error => console.error(error));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
const { classes, user } = this.props
|
||||
const logoUrl = user.picture;
|
||||
const { loading } = this.state;
|
||||
const inputProps = {
|
||||
value: this.state.address,
|
||||
onChange: this.onChange,
|
||||
}
|
||||
const searchOptions = {
|
||||
componentRestrictions: { country: ['fr'] },
|
||||
}
|
||||
|
||||
return (
|
||||
<section className={classes.container}>
|
||||
|
||||
<form className={classes.form}
|
||||
autoComplete="off">
|
||||
{!!logoUrl && <Avatar className={classes.logo}
|
||||
classes={{ img: classes.MuiAvatarImg }}
|
||||
src={publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.postedContentUrl + logoUrl} alt="candidatLogo" />}
|
||||
|
||||
{/* {!!user.pictureLoading && <Loader />} */}
|
||||
{/* {!!!user.pictureLoading && !!!logoUrl &&
|
||||
(<Fragment><input
|
||||
type="file" accept="image/*" capture="filesystem"
|
||||
className={classes.input}
|
||||
style={{ display: 'none' }}
|
||||
id="raised-button-file"
|
||||
multiple
|
||||
type="file"
|
||||
onChange={this.inputFilesystemChange}
|
||||
/>
|
||||
<label htmlFor="raised-button-file">
|
||||
<Button component="span" className={classes.importButton} classes={{ root: classes.rootButton }}>
|
||||
<img alt="talents-tube" src='/static/images/default/account-avatar-default.svg'
|
||||
className={classes.iconButton} />
|
||||
<Typography align="left" className={classes.textButton}>
|
||||
J'<span className={classes.underlined}>importe</span> ma photo de profil
|
||||
</Typography>
|
||||
<KeyboardArrowRightIcon className={classes.InputKeyboardArrowRightIcon} />
|
||||
</Button>
|
||||
</label></Fragment>)
|
||||
} */}
|
||||
<Player fluid={false} width={"75%"} height={350}
|
||||
playsInline className={classes.player}
|
||||
src={publicRuntimeConfig.symphonyUrl + "uploads/videos/"+this.state.mediaUrl}
|
||||
//src={this.state.mediaUrl}
|
||||
// src="https://media.w3.org/2010/05/sintel/trailer_hd.mp4"
|
||||
/>
|
||||
|
||||
|
||||
<Button className={classes.remplacerButton} onClick={this.openDialog.bind(this)}>
|
||||
Remplacer ma vidéo
|
||||
</Button>
|
||||
<Dialog open={this.state.open}>
|
||||
<DialogTitle> Souhaitez-vous remplacer votre vidéo de réponse ?</DialogTitle>
|
||||
<DialogContent className={classes.popup}> Cette vidéo et tous les éléments de votre candidature seront définitivement supprimés. Vous pourrez importer ou réaliser une nouvelle vidéo de réponse. </DialogContent>
|
||||
<DialogActions>
|
||||
|
||||
<Button onClick={this.closeDialog.bind(this)} autoFocus>
|
||||
Annuler
|
||||
</Button>
|
||||
<Button onClick={this.refreshDialog.bind(this)} >
|
||||
Remplacer
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
|
||||
|
||||
|
||||
<TextField
|
||||
name="firstname"
|
||||
required
|
||||
id="outlined-required"
|
||||
label="Prénom"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
value={this.state.firstname}
|
||||
onChange={this.handleChange}
|
||||
error={!!_.isEmpty(this.state.firstname)}
|
||||
helperText={!!_.isEmpty(this.state.firstname) && "Veuillez saisir votre prénom"}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
name="lastname"
|
||||
required
|
||||
id="outlined-required"
|
||||
label="Nom"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
value={this.state.lastname}
|
||||
onChange={this.handleChange}
|
||||
error={!!_.isEmpty(this.state.lastname)}
|
||||
helperText={!!_.isEmpty(this.state.lastname) && "Veuillez saisir votre nom"}
|
||||
required
|
||||
/>
|
||||
|
||||
<div
|
||||
className={classes.conteneurGoogle}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
style={{ position: 'relative', zIndex:2, width: '100%' }}>
|
||||
<label htmlFor="outlined-required"
|
||||
className={classes.labelGeoloc}>
|
||||
Adresse
|
||||
</label>
|
||||
<div className={classes.conteneurGoogleComposant}>
|
||||
<GooglePlaceAutocomplete
|
||||
style={{ paddingLeft:'14px !important', left: 0, right: 0, zIndex: '2 !important', width: '100%' }}
|
||||
name="location"
|
||||
label="Location"
|
||||
id="outlined-required"
|
||||
variant="outlined"
|
||||
textFieldProps={{ id: "outlined-required" }}
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
options={this.searchOptions}
|
||||
onSuggestionSelected={this.onSuggestionSelected}
|
||||
textFieldProps={{ onChange: (e) => this.onChange(e), value: this.state.value, placeholder: 'Ex : Rue de Rivoli, Paris, France', fullWidth: true, size:"small"}}
|
||||
types={['(regions)']}
|
||||
componentRestrictions={{country: 'fr'}}
|
||||
renderTarget={() => (
|
||||
<div
|
||||
style={{
|
||||
|
||||
width: '100%',
|
||||
zIndex:9
|
||||
}}
|
||||
>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* <Input
|
||||
name="geoloc"
|
||||
id="geoloc"
|
||||
label="geoloc"
|
||||
ref="geoloc"
|
||||
onChange={this.handleChange}
|
||||
value={this.state.geoloc =='null' || this.state.geoloc =='' ? '' :this.state.geoloc}
|
||||
/> */}
|
||||
</div>
|
||||
|
||||
<TextField
|
||||
name="phone"
|
||||
id="outlined"
|
||||
label="Téléphone"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
value={this.state.phone}
|
||||
onChange={this.handleChange}
|
||||
type="tel"
|
||||
helperText="Renseignez votre numéro de téléphone pour permettre au recruteur de vous contacter"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
disabled
|
||||
id="outlined-required"
|
||||
label="E-mail"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
value={user.email}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
name="currentJob"
|
||||
id="outlined"
|
||||
label="Poste actuel"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
value={this.state.currentJob =='null' || this.state.currentJob =='' ? '' :this.state.currentJob}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
|
||||
{this.AfficherSuccess()}
|
||||
<div className={classes.containerImport}>
|
||||
<input
|
||||
type="file"
|
||||
accept=".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document, .pdf, .odt"
|
||||
className={classes.input+' cypButtonImportVid'}
|
||||
style={{ display: 'none' }}
|
||||
id="import-button-file"
|
||||
onChange={this.inputFilesystemChange}
|
||||
/>
|
||||
<label htmlFor="import-button-file">
|
||||
<Button component="span" className={classes.importButton} classes={{ root: classes.rootButton }}>
|
||||
|
||||
|
||||
<GetApp className={classes.icon} /> Importer mon CV
|
||||
|
||||
|
||||
</Button>
|
||||
|
||||
</label>
|
||||
<Hidden> </Hidden>
|
||||
{this.AfficherLienCv()}
|
||||
</div>
|
||||
<TextField
|
||||
name="linkedin"
|
||||
id="outlined"
|
||||
label="Linkedin"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
placeholder="http://www.linkedin.com/in/"
|
||||
value={this.state.linkedin =='null' || this.state.linkedin =='' ? '' :this.state.linkedin}
|
||||
onChange={this.handleChange}
|
||||
|
||||
/>
|
||||
|
||||
<TextField
|
||||
name="twitter"
|
||||
id="outlined"
|
||||
label="Twitter"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
placeholder="http://twitter.com/.."
|
||||
value={this.state.twitter =='null' || this.state.twitter =='' ? '' :this.state.twitter}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
name="website"
|
||||
id="outlined"
|
||||
label="Site internet"
|
||||
className={classes.textField}
|
||||
classes={{ root: classes.rootTextfield }}
|
||||
variant="outlined"
|
||||
placeholder="http://monsite.fr"
|
||||
value={this.state.website =='null' || this.state.website =='' ? '' :this.state.website}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
|
||||
</form>
|
||||
<div id="F" className={classes.foot}>
|
||||
<Button variant="contained" className={classes.button + ' cypButtonSendApplication'} onClick={this.onSubmit}>Envoyer ma candidature</Button>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
// console.log(state.media.message.heure);
|
||||
return {
|
||||
user: state.user ,
|
||||
cvLink : state.mediaCv.message,
|
||||
loading: !!state.media.loading,
|
||||
cv : true,
|
||||
// user: state.user,
|
||||
// loading: !!state.user.loading,
|
||||
pictureLoading: !!state.user.pictureLoading,
|
||||
errors: state.user.errors || ownProps.errors,
|
||||
mediaId: state.media.message && state.media.message.mediaId,
|
||||
mediaUrl: state.media.message && state.media.message.originalUrl,
|
||||
thumbnails: state.media.message && state.media.message.thumbnails,
|
||||
mediaUrlVimeo: state.media.message && state.media.message.uriVimeo,
|
||||
mediaFileName: state.media.message && state.media.message.filename,
|
||||
heure: state.media.message && state.media.message.heure,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export default withStyles(styles)(connect(mapStateToProps, { postAdAnswerRequest, updateUserRequest, updateUserPictureRequest, uploadMediaCv })(Answer))
|
||||
@@ -0,0 +1,263 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import Router from 'next/router'
|
||||
import getConfig from 'next/config'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
import CardMedia from '@material-ui/core/CardMedia';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import IconText from './../atoms/IconText';
|
||||
import KeyboardArrowleftIcon from '@material-ui/icons/PlayArrowRounded';
|
||||
import ArrowForwardIcon from '@material-ui/icons/ArrowForward';
|
||||
import Link from 'next/link';
|
||||
|
||||
const styles = theme => ({
|
||||
card: {
|
||||
display: 'flex',
|
||||
minHeight: '21vh',
|
||||
maxHeight: '25vh',
|
||||
width: '100%',
|
||||
margin: theme.spacing(1,0),
|
||||
borderRadius: '5px',
|
||||
cursor: 'pointer',
|
||||
'& > div': {
|
||||
padding: '0 !important',
|
||||
},
|
||||
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: '30%',
|
||||
},
|
||||
[theme.breakpoints.down('md')]: {
|
||||
width: '40%',
|
||||
},
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
width: '100%',
|
||||
},
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
margin: '1vh 0 1vh 0',
|
||||
},
|
||||
},
|
||||
detailsContainer: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
padding: theme.spacing(3, 2),
|
||||
width: '75%',
|
||||
},
|
||||
jobTitle: {
|
||||
fontSize: '1em',
|
||||
fontWeight: 'bold',
|
||||
color: theme.palette.offerlistitem.title,
|
||||
},
|
||||
companyTitle: {
|
||||
fontSize: '0.8em',
|
||||
fontWeight: '300',
|
||||
color: theme.palette.offerlistitem.title,
|
||||
},
|
||||
content: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
padding: 0,
|
||||
},
|
||||
cover: {
|
||||
position: 'relative',
|
||||
width: '125px',
|
||||
height: '100%',
|
||||
backgroundPosition: 'center',
|
||||
backgroundSize: 'cover',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
},
|
||||
iconPlay: {
|
||||
fontSize: '2em',
|
||||
color: theme.palette.background.grey,
|
||||
position: 'absolute',
|
||||
top: 'calc(50% - 0.5em)',
|
||||
left: 'calc(50% - 0.5em)',
|
||||
},
|
||||
iconText: {
|
||||
marginLeft: 0,
|
||||
justifyContent: 'flex-start',
|
||||
},
|
||||
iconTextIcon: {
|
||||
color: theme.palette.offerlistitem.icon,
|
||||
fontSize: '0.8em',
|
||||
},
|
||||
iconTextText: {
|
||||
color: theme.palette.offerlistitem.text,
|
||||
fontSize: '0.6em',
|
||||
paddingLeft: theme.spacing(1),
|
||||
},
|
||||
bottomCard: {
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
width: '90%',
|
||||
},
|
||||
chip: {
|
||||
color: theme.palette.secondary.main,
|
||||
backgroundColor: theme.palette.primary.important,
|
||||
},
|
||||
icon: {
|
||||
color: theme.palette.secondary.dark,
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
|
||||
const { publicRuntimeConfig } = getConfig()
|
||||
|
||||
//TODO:shouldn't be here
|
||||
//must go in API
|
||||
const status = new Map([
|
||||
|
||||
["DRAFT"
|
||||
, "Brouillon"]
|
||||
,
|
||||
["TO_PUBLISH"
|
||||
, "En cours de validation"]
|
||||
,
|
||||
["VALIDATED"
|
||||
, "Validée"]
|
||||
,
|
||||
["PUBLISHED"
|
||||
, "Publiée"]
|
||||
,
|
||||
["CLOSED"
|
||||
, "Cloturée"]
|
||||
,
|
||||
["EXPIRED"
|
||||
, "Expirée"]
|
||||
,
|
||||
["SENDED"
|
||||
, "Envoyée"]
|
||||
,
|
||||
["DECLINED"
|
||||
, "Refusée"]
|
||||
,
|
||||
["NEW"
|
||||
, "Nouveau"]
|
||||
,
|
||||
["VIEWED"
|
||||
, "Visionnée"]
|
||||
,
|
||||
["NEGATIVE"
|
||||
, "Négatif"]
|
||||
,
|
||||
["POSITIVE"
|
||||
, "Positif"]
|
||||
,
|
||||
["INFOS"
|
||||
, "Demande d’informations"]
|
||||
,
|
||||
["CONTACTED"
|
||||
, "Demande d’informations"]
|
||||
,
|
||||
["CONTACTED.RDV"
|
||||
, "Convocation entretien"]
|
||||
|
||||
])
|
||||
class AnswerRowComponent extends React.Component {
|
||||
|
||||
render() {
|
||||
|
||||
const { classes, rowData, company } = this.props;
|
||||
// company not used ?
|
||||
let companyR = company
|
||||
if (!!!company)
|
||||
companyR = rowData.ad.company;
|
||||
else
|
||||
companyR = company;
|
||||
|
||||
const imgUrl = (rowData.ad && rowData.ad.video && rowData.ad.video.thumbnails[0] && rowData.ad.video.thumbnails[0].sizes[4])
|
||||
? rowData.ad.video.thumbnails[0].sizes[4].link
|
||||
: publicRuntimeConfig.adListDefaultUrl
|
||||
const logoUrl = publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.cachedMediaUrl + companyR.logo
|
||||
|
||||
return (
|
||||
<Link href={`/Candidature/${rowData.id}`} >
|
||||
<Card className={classes.card} >
|
||||
{rowData.ad ? (
|
||||
<CardContent className={classes.content}>
|
||||
<CardMedia
|
||||
className={classes.cover}
|
||||
image={imgUrl}
|
||||
title={rowData.ad.title}
|
||||
>
|
||||
<KeyboardArrowleftIcon className={classes.iconPlay} />
|
||||
</CardMedia>
|
||||
|
||||
<div className={classes.detailsContainer}>
|
||||
<Typography
|
||||
gutterBottom
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h3"
|
||||
className={classes.jobTitle}>
|
||||
{rowData.ad.title&&rowData.ad.title}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h4"
|
||||
className={classes.companyTitle}>
|
||||
{rowData.ad.company.brand_name&&rowData.ad.company.brand_name}
|
||||
</Typography>
|
||||
<div className={ classes.bottomCard }>
|
||||
<Chip size="small" label={status.get(rowData.status)} className={classes.chip} />
|
||||
<ArrowForwardIcon className={classes.icon} />
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
):(
|
||||
<CardContent className={classes.content}>
|
||||
<CardMedia
|
||||
className={classes.cover}
|
||||
image={publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.cachedMediaUrl + rowData.company.logo}
|
||||
title={rowData.company.brand_name}
|
||||
>
|
||||
<KeyboardArrowleftIcon className={classes.iconPlay} />
|
||||
</CardMedia>
|
||||
|
||||
<div className={classes.detailsContainer}>
|
||||
<Typography
|
||||
gutterBottom
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h3"
|
||||
className={classes.jobTitle}>
|
||||
Candidature spontanée
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h4"
|
||||
className={classes.companyTitle}>
|
||||
{rowData.company.brand_name&&rowData.company.brand_name}
|
||||
</Typography>
|
||||
<div className={ classes.bottomCard }>
|
||||
<Chip size="small" label={status.get(rowData.status)} className={classes.chip} />
|
||||
<ArrowForwardIcon className={classes.icon} />
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
)}
|
||||
</Card>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AnswerRowComponent.defaultProps = {
|
||||
company: {}
|
||||
}
|
||||
|
||||
AnswerRowComponent.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
rowData: PropTypes.object.isRequired,
|
||||
company: PropTypes.object
|
||||
};
|
||||
|
||||
export default withStyles(styles, { withTheme: true })(AnswerRowComponent);
|
||||
@@ -0,0 +1,39 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import _ from "lodash"
|
||||
import Ar from "lodash/array"
|
||||
import VideoVimeo from '../atoms/VideoVimeo'
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
card: {
|
||||
width: '100%',
|
||||
},
|
||||
title: {
|
||||
fontSize: '1em',
|
||||
fontWeight: '500',
|
||||
},
|
||||
titleBorder: {
|
||||
'&:after': {
|
||||
content: '""',
|
||||
width: '15px',
|
||||
borderBottom: 'solid 2px',
|
||||
borderColor: theme.palette.primary.main + '!important',
|
||||
display: 'flex',
|
||||
},
|
||||
},
|
||||
video: {
|
||||
[theme.breakpoints.up('md')]: {
|
||||
paddingBottom: '35%', /* 16:9 */
|
||||
},
|
||||
}
|
||||
}));
|
||||
|
||||
export default function CandidatureDetail(props) {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<VideoVimeo classes={{ video: classes.video }} videoId={Ar.last(_.split(props.video.cdn_url, '/'))} />
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
import React, { Fragment, useState, useCallback } from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
|
||||
import _ from "lodash"
|
||||
import ChatCard from '../atoms/ChatCard'
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import { Button } from '@material-ui/core';
|
||||
import IconAdd from '@material-ui/icons/Add';
|
||||
import ArrowUpwardIcon from '@material-ui/icons/ArrowUpward';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useSelector } from 'react-redux'
|
||||
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
card: {
|
||||
width: '100%',
|
||||
},
|
||||
wrapper: {
|
||||
minHeight: '100%',
|
||||
},
|
||||
contain: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
padding: '2vh 18vw',
|
||||
},
|
||||
},
|
||||
push: {
|
||||
height: '50px'
|
||||
},
|
||||
foot: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
padding: '2vh 18vw',
|
||||
},
|
||||
},
|
||||
chat: {
|
||||
|
||||
},
|
||||
filterForm: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
backgroundColor: theme.palette.input.main,
|
||||
padding: theme.spacing(1),
|
||||
width: '100%',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
padding: theme.spacing(3),
|
||||
},
|
||||
},
|
||||
button: {
|
||||
backgroundColor: 'inherit',
|
||||
borderRadius: '0',
|
||||
'& svg': {
|
||||
fontSize: '1.5rem',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
fontSize: '2rem',
|
||||
},
|
||||
}
|
||||
},
|
||||
icon: {
|
||||
color: theme.palette.secondary.main,
|
||||
background: theme.palette.primary.important,
|
||||
padding: theme.spacing(1),
|
||||
borderRadius: '50%',
|
||||
},
|
||||
video: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '11vh',
|
||||
},
|
||||
title: {
|
||||
fontSize: '1em',
|
||||
fontWeight: '500',
|
||||
},
|
||||
titleBorder: {
|
||||
'&:after': {
|
||||
content: '""',
|
||||
width: '15px',
|
||||
borderBottom: 'solid 2px',
|
||||
borderColor: theme.palette.primary.main + '!important',
|
||||
display: 'flex',
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
|
||||
function Chat(props) {
|
||||
const classes = useStyles();
|
||||
const [text, setText] = useState("");
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const messages = useSelector(state => state.answer.messages);
|
||||
const loadingMessage = useSelector(state => state.answer.loadingMessage);
|
||||
|
||||
const sendMessage = useCallback(
|
||||
(message) => dispatch({ type: 'POST_MESSAGE_ANSWER_REQUEST', payload: { answerId: props.answerId, message: message } }),
|
||||
[dispatch]
|
||||
)
|
||||
|
||||
const postMessage = () => {
|
||||
sendMessage(text);
|
||||
setText('');
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={classes.wrapper}>
|
||||
<div className={classes.contain}>
|
||||
{
|
||||
_.orderBy(messages, ['c_time'], ['asc']).map((message, index) => {
|
||||
return <ChatCard message={message} key={index}></ChatCard>
|
||||
})
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="F" className={classes.foot}>
|
||||
<div className={classes.filterForm}>
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
rows={isWidthUp('md', props.width) ? 8 : 1}
|
||||
id="standard-search"
|
||||
name="chattext"
|
||||
value={text}
|
||||
onChange={(e) => setText(e.target.value)}
|
||||
placeholder={"Message"}
|
||||
className={classes.textField}
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
/>
|
||||
<Button onClick={()=>postMessage()}
|
||||
disabled={loadingMessage}
|
||||
variant="contained"
|
||||
className={classes.button}>
|
||||
<ArrowUpwardIcon className={classes.icon}/>
|
||||
</Button >
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default withWidth()(Chat)
|
||||
@@ -6,10 +6,12 @@ import { withStyles } from '@material-ui/core/styles';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
import CardHeader from '@material-ui/core/CardHeader';
|
||||
import CardMedia from '@material-ui/core/CardMedia';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import IconText from './../atoms/IconText';
|
||||
import KeyboardArrowleftIcon from '@material-ui/icons/PlayArrowRounded';
|
||||
import Link from 'next/link';
|
||||
|
||||
const { publicRuntimeConfig } = getConfig()
|
||||
|
||||
@@ -17,40 +19,57 @@ const styles = theme => ({
|
||||
card: {
|
||||
display: 'flex',
|
||||
position: 'relative',
|
||||
height: '50vh',
|
||||
height: '67vh',
|
||||
width: '100%',
|
||||
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width : '30%',
|
||||
},
|
||||
[theme.breakpoints.down('md')]: {
|
||||
width : '40%',
|
||||
},
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
width : '100%',
|
||||
cursor: 'pointer',
|
||||
transform: 'translateY(-0px)',
|
||||
transition: 'transform 0.25s',
|
||||
'&:hover': {
|
||||
transform: 'translateY(-15px)',
|
||||
transition: 'transform 0.5s, box-shadow 1.2s',
|
||||
'& .cardHover': {
|
||||
backgroundColor: 'rgba(0,0,0,0)',
|
||||
},
|
||||
},
|
||||
|
||||
margin: '1vh 2vh 1vh 2vh',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
margin: '1vh 0 1vh 0',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: '30%',
|
||||
height: '53vh',
|
||||
},
|
||||
borderRadius: 0
|
||||
[theme.breakpoints.down('md')]: {
|
||||
width: '40%',
|
||||
height: '67vh',
|
||||
},
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
width: '100%',
|
||||
},
|
||||
|
||||
margin: theme.spacing(1.5),
|
||||
marginBottom: theme.spacing(3),
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
margin: theme.spacing(2, 0),
|
||||
},
|
||||
borderRadius: '4px',
|
||||
},
|
||||
details_container: {
|
||||
detailsContainer: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
padding: '8vh 0 0 0',
|
||||
width: '100%',
|
||||
paddingTop: theme.spacing(6),
|
||||
},
|
||||
company_title: {
|
||||
companyTitle: {
|
||||
textAlign: 'center',
|
||||
fontSize: '1em',
|
||||
fontWeight: 'normal',
|
||||
textTransform: 'uppercase',
|
||||
fontWeight: '500',
|
||||
minHeight: '5vh',
|
||||
padding: theme.spacing(0,1.5),
|
||||
},
|
||||
content: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
flexWrap: 'wrap',
|
||||
width: '100%',
|
||||
padding: 0,
|
||||
@@ -60,102 +79,108 @@ const styles = theme => ({
|
||||
height: '50%',
|
||||
backgroundSize: 'cover',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
position: 'relative',
|
||||
backgroundBlendMode: 'darken',
|
||||
backgroundColor: 'rgba(30,35,39,0.25)',
|
||||
transition: 'background-color 1s',
|
||||
},
|
||||
logo_container: {
|
||||
logoContainer: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: 100,
|
||||
height: 100,
|
||||
width: 85,
|
||||
height: 85,
|
||||
position: 'absolute',
|
||||
left: '50%',
|
||||
top: '50%',
|
||||
transform: 'translate(-50%, -66%)',
|
||||
border: 'solid 5px white',
|
||||
backgroundColor: 'white',
|
||||
boxShadow: '0 8px 6px -6px grey',
|
||||
boxShadow: '0px 6px 15px rgba(30, 35, 39, 0.10)',
|
||||
borderRadius: '6px',
|
||||
},
|
||||
iconTextContainer: {
|
||||
width: '100%',
|
||||
},
|
||||
iconText: {
|
||||
marginLeft: 0,
|
||||
padding: theme.spacing(2, 3),
|
||||
justifyContent: 'flex-start',
|
||||
},
|
||||
iconTextIcon: {
|
||||
color: theme.palette.offerlistitem.icon,
|
||||
fontSize: '1em',
|
||||
},
|
||||
iconTextText: {
|
||||
color: theme.palette.offerlistitem.text,
|
||||
fontSize: '0.8em',
|
||||
textTransform: 'capitalize',
|
||||
paddingLeft: theme.spacing(1),
|
||||
},
|
||||
iconPlay: {
|
||||
fontSize: '3em',
|
||||
color: theme.palette.background.grey,
|
||||
position: 'absolute',
|
||||
top: 'calc(50% - 0.5em)',
|
||||
left: 'calc(50% - 0.5em)',
|
||||
},
|
||||
logo: {
|
||||
width: '100%',
|
||||
height: 'auto',
|
||||
objectfit: 'contain',
|
||||
borderRadius: 0,
|
||||
objectFit: 'contain',
|
||||
borderRadius: '0px',
|
||||
},
|
||||
chip: {
|
||||
margin: '0 1vh 0 1vh',
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
class CompanyRowComponent extends React.Component {
|
||||
|
||||
render() {
|
||||
const { classes, theme, rowData } = this.props;
|
||||
|
||||
const imgDefaultUrl = "https://www.talentstube.com/img/default_picture_company.svg"
|
||||
const imgDefaultUrl = "https://blog.talentstube.com/wp-content/uploads/2021/01/default_picture_company.jpg"
|
||||
|
||||
const imgUrl = (rowData.presentation_video && rowData.presentation_video.thumbnails[0] && rowData.presentation_video.thumbnails[0].sizes[4]) ? rowData.presentation_video.thumbnails[0].sizes[4].link : imgDefaultUrl
|
||||
const logoUrl = publicRuntimeConfig.logoRootUrl + rowData.logo
|
||||
const logoUrl = publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.cachedMediaUrl + rowData.logo
|
||||
let location = "non renseigné"
|
||||
if (rowData.addresses && rowData.addresses.billing && rowData.addresses.billing.city && rowData.addresses.billing.postcode)
|
||||
location = (rowData.addresses.billing.city.toLowerCase() + ', ' + rowData.addresses.billing.postcode);
|
||||
|
||||
const offre = (rowData.count_ads == 1) ? rowData.count_ads + ' offre' : rowData.count_ads + ' offres';
|
||||
const nbOffre = (rowData.count_ads > 0) ? offre : 'Candidature spontanée';
|
||||
|
||||
return (
|
||||
<Card onClick={() => Router.push(`/Company?id=${rowData.id}`)}>
|
||||
<CardContent className={classes.content}>
|
||||
<CardMedia
|
||||
className={classes.cover}
|
||||
image={imgUrl}
|
||||
title={rowData.title}
|
||||
/>
|
||||
<Link href={`/Entreprise/${rowData.id}-${_.kebabCase(rowData.brand_name)}`} >
|
||||
<Card className={classes.card + ' cypCardCompany'}>
|
||||
<CardContent className={classes.content}>
|
||||
<CardMedia
|
||||
className={classes.cover + ' cardHover'}
|
||||
image={imgUrl}
|
||||
title={rowData.brand_name}
|
||||
>
|
||||
<KeyboardArrowleftIcon className={classes.iconPlay} />
|
||||
</CardMedia>
|
||||
<div className={classes.logoContainer}>
|
||||
<Avatar className={classes.logo} src={logoUrl} alt="companylogo" />
|
||||
</div>
|
||||
|
||||
<div className={classes.logo_container}>
|
||||
<Avatar className={classes.logo} src={logoUrl} />
|
||||
</div>
|
||||
|
||||
<div className={classes.details_container}>
|
||||
<Typography
|
||||
gutterBottom
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h4"
|
||||
align="center"
|
||||
className={classes.company_title}>
|
||||
{rowData.business_name}
|
||||
</Typography>
|
||||
{/* <Typography
|
||||
gutterBottom
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h3"
|
||||
align="center"
|
||||
className={classes.job_title}>
|
||||
{rowData.title}
|
||||
</Typography> */}
|
||||
</div>
|
||||
<div>
|
||||
{/* <Chip label={rowData.extra.contract_type} className={classes.chip} />
|
||||
<Chip label={rowData.location.gmap_address.address_components[0].long_name} className={classes.chip} /> */}
|
||||
</div>
|
||||
</CardContent>
|
||||
{/* <CardHeader />
|
||||
<CardContent>
|
||||
<CardMedia
|
||||
className={classes.cover}
|
||||
image={imgUrl}
|
||||
title={rowData.presentation_video&&rowData.presentation_video.title}
|
||||
/>
|
||||
<Typography gutterBottom component="h3"
|
||||
className={classes.details}>
|
||||
{rowData.brand_name}
|
||||
</Typography>
|
||||
<Typography gutterBottom component="h4"
|
||||
className={classes.details}>
|
||||
{rowData.website}
|
||||
</Typography>
|
||||
<Typography gutterBottom component="h5"
|
||||
className={classes.details}>
|
||||
{rowData.description}
|
||||
</Typography>
|
||||
</CardContent> */}
|
||||
</Card>
|
||||
<div className={classes.detailsContainer}>
|
||||
<Typography
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h3"
|
||||
className={classes.companyTitle}>
|
||||
{rowData.brand_name}
|
||||
</Typography>
|
||||
<div className={classes.iconTextContainer}>
|
||||
<IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="location_on" text={location} />
|
||||
</div>
|
||||
</div>
|
||||
<Chip color="primary" label={nbOffre} className={classes.chip} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,299 @@
|
||||
import Link from 'next/link'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import { Fragment, Children } from 'react';
|
||||
import { Button } from '@material-ui/core';
|
||||
import { Typography } from '@material-ui/core';
|
||||
import { Fragment } from 'react';
|
||||
import NewsLetterRegistration from './NewsLetterRegistration'
|
||||
import dynamic from 'next/dynamic'
|
||||
import Button from '@material-ui/core/Button'
|
||||
import getConfig from 'next/config'
|
||||
const PWAInstallSnack = dynamic(() => import('./PWAInstallSnack'), {
|
||||
ssr: false
|
||||
});
|
||||
const { publicRuntimeConfig } = getConfig();
|
||||
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
position: 'relative',
|
||||
height: '10vh'
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
[theme.breakpoints.up('md')]: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
justifyContent: 'space-around',
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
padding: theme.spacing(10, 18),
|
||||
},
|
||||
'& a': {
|
||||
textDecoration: 'none',
|
||||
},
|
||||
},
|
||||
container: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
padding: theme.spacing(0, 5),
|
||||
paddingBottom: theme.spacing(3.5),
|
||||
'&:first-child': {
|
||||
paddingTop: theme.spacing(4),
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
padding: 0,
|
||||
'&:first-child': {
|
||||
paddingTop: 0,
|
||||
},
|
||||
},
|
||||
|
||||
},
|
||||
containerRegion: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
padding: theme.spacing(3),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
padding: theme.spacing(8, 0),
|
||||
},
|
||||
|
||||
},
|
||||
titleContainer: {
|
||||
color: theme.palette.primary.darkMain,
|
||||
fontSize: '1.5em',
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
fontWeight: '600',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
fontSize: '1.2em',
|
||||
paddingBottom: theme.spacing(2),
|
||||
},
|
||||
},
|
||||
textContainer: {
|
||||
fontWeight: '300',
|
||||
fontSize: '0.9em',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
fontWeight: '300',
|
||||
fontSize: '0.8em',
|
||||
},
|
||||
},
|
||||
textContainerRegion: {
|
||||
fontWeight: '300',
|
||||
fontSize: '0.9em',
|
||||
color: theme.palette.primary.dark,
|
||||
},
|
||||
footerLogo: {
|
||||
width: '15vw',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: '4vw',
|
||||
},
|
||||
},
|
||||
footerLogoTT: {
|
||||
width: '70%',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
paddingBottom: theme.spacing(1),
|
||||
width: '100%'
|
||||
},
|
||||
},
|
||||
containerReactApp: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
height: 'auto',
|
||||
paddingTop: theme.spacing(4),
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
height: '100vh',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-around',
|
||||
height: '35vh',
|
||||
padding: theme.spacing(6, 1),
|
||||
position: 'relative',
|
||||
},
|
||||
},
|
||||
titleReactApp: {
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
fontSize: '1.5em',
|
||||
fontWeight: '600',
|
||||
paddingTop: theme.spacing(4),
|
||||
paddingLeft: theme.spacing(4),
|
||||
paddingRight: theme.spacing(4),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
order: 1,
|
||||
width: '20%',
|
||||
textAlign: 'left',
|
||||
},
|
||||
},
|
||||
buttonReactApp: {
|
||||
textTransform: 'inherit',
|
||||
margin: theme.spacing(0, 8),
|
||||
padding: theme.spacing(1.2, 2),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
order: 3,
|
||||
margin: 'inherit',
|
||||
marginRight: '5vw',
|
||||
},
|
||||
},
|
||||
imageReactApp: {
|
||||
width: '100%',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
width: 'auto',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: '25%',
|
||||
order: 2,
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
},
|
||||
},
|
||||
containerNewsletter: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: theme.spacing(6, 4),
|
||||
},
|
||||
version:{
|
||||
marginTop: '15px',
|
||||
fontSize: '0.7em',
|
||||
fontWeight: '300',
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function Footer(props) {
|
||||
const { classes } = props;
|
||||
return (
|
||||
<Fragment>
|
||||
{props.children}
|
||||
</Fragment>
|
||||
<div>
|
||||
<PWAInstallSnack >
|
||||
{({ initInstall }) =>
|
||||
<section
|
||||
className={classes.containerReactApp}
|
||||
>
|
||||
<Typography
|
||||
gutterBottom
|
||||
color="secondary"
|
||||
align="center"
|
||||
component="h3"
|
||||
className={classes.titleReactApp}
|
||||
>
|
||||
Installez l'application Talents Tube pour suivre vos candidatures
|
||||
</Typography>
|
||||
<Button
|
||||
aria-label='install'
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
onClick={initInstall}
|
||||
className={classes.buttonReactApp}
|
||||
>
|
||||
Installer l'application
|
||||
</Button>
|
||||
<img alt="télécharger-pwa" src='/static/images/newsletter/application.png' className={classes.imageReactApp} />
|
||||
</section>
|
||||
}
|
||||
</PWAInstallSnack>
|
||||
|
||||
<section className={classes.containerNewsletter}>
|
||||
<NewsLetterRegistration />
|
||||
</section>
|
||||
|
||||
<div className={classes.root}>
|
||||
<section className={classes.container}>
|
||||
<img alt="talents-tube" src='/static/images/logos/TalentsTube_logo-blanc.svg' className={classes.footerLogoTT} />
|
||||
<Link href="/Offres" >
|
||||
<a>
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
Offre d'emploi
|
||||
</Typography>
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="/Entreprises" >
|
||||
<a>
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
Entreprises
|
||||
</Typography>
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="/Help" >
|
||||
<a>
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
Comment ça marche ?
|
||||
</Typography>
|
||||
</a>
|
||||
</Link>
|
||||
<a href="https://blog.talentstube.com" target="_blank">
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}
|
||||
>
|
||||
Blog
|
||||
</Typography>
|
||||
</a>
|
||||
</section>
|
||||
<section className={classes.container}>
|
||||
<Typography color="secondary" component="p" className={classes.titleContainer}>
|
||||
Informations
|
||||
</Typography>
|
||||
|
||||
<Link href="/Cgu" >
|
||||
<a>
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
CGU
|
||||
</Typography>
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<Link href="/MentionsLegales" >
|
||||
<a>
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
Mentions légales
|
||||
</Typography>
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="/Confidentialite" >
|
||||
<a>
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
Politique de confidentialité et Protection <br />des données
|
||||
</Typography>
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="" >
|
||||
<a href="https://blog.talentstube.com/contact" target="_blank">
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
Contact
|
||||
</Typography>
|
||||
</a>
|
||||
</Link>
|
||||
</section>
|
||||
<section className={classes.container}>
|
||||
<Typography color="secondary" component="p" className={classes.titleContainer}>
|
||||
Rencontrons-nous
|
||||
</Typography>
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
3, rue Louis de Broglie
|
||||
</Typography>
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
56 000 Vannes
|
||||
</Typography>
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
<a href="tel:+33230050631" >02.30.05.06.31 </a>
|
||||
</Typography>
|
||||
{/* <Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
contact@talentstube.com
|
||||
</Typography> */}
|
||||
</section>
|
||||
|
||||
</div>
|
||||
<section className={classes.containerRegion}>
|
||||
<Typography gutterBottom component="p" className={classes.textContainerRegion} align="center" >
|
||||
Entreprise soutenue par
|
||||
</Typography>
|
||||
<a href="https://www.bretagne.bzh/" target="_blank" className={classes.darkMenuItem} rel="noopener">
|
||||
<img alt="Région Bretagne" src='/static/images/logos/Logo-region.svg' className={classes.footerLogo} />
|
||||
</a>
|
||||
<Typography className={classes.version} align="center" >
|
||||
{publicRuntimeConfig.version}
|
||||
</Typography>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
import Link from 'next/link'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import { Typography } from '@material-ui/core';
|
||||
import { Fragment } from 'react';
|
||||
import NewsLetterRegistration from './NewsLetterRegistration'
|
||||
import dynamic from 'next/dynamic'
|
||||
import Button from '@material-ui/core/Button'
|
||||
import getConfig from 'next/config'
|
||||
const { publicRuntimeConfig } = getConfig();
|
||||
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
backgroundColor: "#1E2327",
|
||||
[theme.breakpoints.up('md')]: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
justifyContent: 'space-around',
|
||||
backgroundColor: "#1E2327",
|
||||
padding: theme.spacing(10, 18),
|
||||
},
|
||||
'& a': {
|
||||
textDecoration: 'none',
|
||||
color:"#fff"
|
||||
},
|
||||
},
|
||||
container: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
padding: theme.spacing(0, 5),
|
||||
paddingBottom: theme.spacing(3.5),
|
||||
'&:first-child': {
|
||||
paddingTop: theme.spacing(4),
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
padding: 0,
|
||||
'&:first-child': {
|
||||
paddingTop: 0,
|
||||
},
|
||||
},
|
||||
|
||||
},
|
||||
containerRegion: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
padding: theme.spacing(3),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
padding: theme.spacing(8, 0),
|
||||
},
|
||||
|
||||
},
|
||||
titleContainer: {
|
||||
color: "#fff",
|
||||
fontSize: '1.5em',
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
fontWeight: '600',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
fontSize: '1.2em',
|
||||
paddingBottom: theme.spacing(2),
|
||||
},
|
||||
},
|
||||
textContainer: {
|
||||
fontWeight: '300',
|
||||
fontSize: '0.9em',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
fontWeight: '300',
|
||||
fontSize: '0.8em',
|
||||
},
|
||||
},
|
||||
textContainerRegion: {
|
||||
fontWeight: '300',
|
||||
fontSize: '0.9em',
|
||||
color: theme.palette.primary.dark,
|
||||
},
|
||||
footerLogo: {
|
||||
width: '15vw',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: '4vw',
|
||||
},
|
||||
},
|
||||
footerLogoTT: {
|
||||
width: '70%',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
paddingBottom: theme.spacing(1),
|
||||
width: '100%'
|
||||
},
|
||||
},
|
||||
containerReactApp: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
height: 'auto',
|
||||
paddingTop: theme.spacing(4),
|
||||
backgroundColor: "#000",
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
height: '100vh',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-around',
|
||||
height: '35vh',
|
||||
padding: theme.spacing(6, 1),
|
||||
position: 'relative',
|
||||
},
|
||||
},
|
||||
titleReactApp: {
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
fontSize: '1.5em',
|
||||
fontWeight: '600',
|
||||
paddingTop: theme.spacing(4),
|
||||
paddingLeft: theme.spacing(4),
|
||||
paddingRight: theme.spacing(4),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
order: 1,
|
||||
width: '20%',
|
||||
textAlign: 'left',
|
||||
},
|
||||
},
|
||||
buttonReactApp: {
|
||||
textTransform: 'inherit',
|
||||
margin: theme.spacing(0, 8),
|
||||
padding: theme.spacing(1.2, 2),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
order: 3,
|
||||
margin: 'inherit',
|
||||
marginRight: '5vw',
|
||||
},
|
||||
},
|
||||
imageReactApp: {
|
||||
width: '100%',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
width: 'auto',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: '25%',
|
||||
order: 2,
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
},
|
||||
},
|
||||
containerNewsletter: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: theme.spacing(6, 4),
|
||||
},
|
||||
version:{
|
||||
marginTop: '15px',
|
||||
fontSize: '0.7em',
|
||||
fontWeight: '300',
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function Footer(props) {
|
||||
const { classes } = props;
|
||||
return (
|
||||
<div>
|
||||
|
||||
|
||||
<section className={classes.containerNewsletter}>
|
||||
<NewsLetterRegistration />
|
||||
</section>
|
||||
|
||||
<div className={classes.root}>
|
||||
<section className={classes.container}>
|
||||
<img alt="talents-tube" src='/static/images/logos/TalentsTube_logo-blanc.svg' className={classes.footerLogoTT} />
|
||||
|
||||
</section>
|
||||
<section className={classes.container}>
|
||||
<Typography color="secondary" component="p" className={classes.titleContainer}>
|
||||
Informations
|
||||
</Typography>
|
||||
|
||||
<Link href="/Cgu" >
|
||||
<a>
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
CGU
|
||||
</Typography>
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<Link href="/MentionsLegales" >
|
||||
<a>
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
Mentions légales
|
||||
</Typography>
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="/Confidentialite" >
|
||||
<a>
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
Politique de confidentialité et Protection <br />des données
|
||||
</Typography>
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="" >
|
||||
<a href="https://blog.talentstube.com/contact" target="_blank">
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
Contact
|
||||
</Typography>
|
||||
</a>
|
||||
</Link>
|
||||
</section>
|
||||
<section className={classes.container}>
|
||||
<Typography color="secondary" component="p" className={classes.titleContainer}>
|
||||
Rencontrons-nous
|
||||
</Typography>
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
3, rue Louis de Broglie
|
||||
</Typography>
|
||||
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
56 000 Vannes
|
||||
</Typography>
|
||||
<Typography gutterBottom component="p" className={classes.textContainer}>
|
||||
<a href="tel:+33230050631" >02.30.05.06.31 </a>
|
||||
</Typography>
|
||||
{/* <Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
|
||||
contact@talentstube.com
|
||||
</Typography> */}
|
||||
</section>
|
||||
|
||||
</div>
|
||||
<section className={classes.containerRegion}>
|
||||
<Typography gutterBottom component="p" className={classes.textContainerRegion} align="center" >
|
||||
Entreprise soutenue par
|
||||
</Typography>
|
||||
<a href="https://www.bretagne.bzh/" target="_blank" className={classes.darkMenuItem} rel="noopener">
|
||||
<img alt="Région Bretagne" src='/static/images/logos/Logo-region.svg' className={classes.footerLogo} />
|
||||
</a>
|
||||
<Typography className={classes.version} align="center" >
|
||||
{publicRuntimeConfig.version}
|
||||
</Typography>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default withStyles(styles)(Footer)
|
||||
@@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
const NextButton = ({ hasNext, onClick, style, className, text }) => hasNext ? (
|
||||
// <button type="button" onClick={onClick} style={style} className={className}>Suivant</button>
|
||||
<div></div>
|
||||
) :
|
||||
null;
|
||||
|
||||
export default NextButton;
|
||||
@@ -0,0 +1,35 @@
|
||||
// import React, { useState } from 'react';
|
||||
// import Pagination from '@material-ui/lab/Pagination';
|
||||
// import PaginationItem from '@material-ui/lab/PaginationItem';
|
||||
// export default function GriddleCustomPageDropdown(props) {
|
||||
// let [page] = React.useState(1);
|
||||
// let PageDropDown = null;
|
||||
// const setPage = (event, newPage) => {
|
||||
// console.log('test');
|
||||
// setPage(newPage);
|
||||
|
||||
// };
|
||||
// return (
|
||||
// <Pagination count={props.maxPages} defaultPage={props.currentPage} onChange={props.setPage}/>
|
||||
// );
|
||||
// }
|
||||
|
||||
// const [page, setPage] = useState(1);
|
||||
// const handleChangePage = (event, newPage) => {
|
||||
|
||||
// setPage(newPage);
|
||||
// };
|
||||
// const PageDropDown = ({ maxPages, currentPage, setPage }) => <Pagination count={maxPages} defaultPage={currentPage} onChangePage={handleChangePage}/> ;
|
||||
|
||||
// export default PageDropDown;
|
||||
|
||||
|
||||
import React from 'react';
|
||||
import Pagination from '@material-ui/lab/Pagination';
|
||||
|
||||
const NextButton = ({ maxPages, currentPage, setPage, className, text }) => maxPages ? (
|
||||
<Pagination count={maxPages} defaultPage={currentPage} onChange={setPage} shape="rounded"/>
|
||||
) :
|
||||
null;
|
||||
|
||||
export default NextButton;
|
||||
@@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
const PreviousButton = ({ hasPrevious, onClick, style, className, text }) => hasPrevious ? (
|
||||
// <button type="button" onClick={onClick} style={style} className={className}>Précédent</button>
|
||||
<div></div>
|
||||
) :
|
||||
null;
|
||||
|
||||
export default PreviousButton;
|
||||
@@ -1,43 +1,62 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Fragment, Children } from 'react';
|
||||
import AppBar from '@material-ui/core/AppBar';
|
||||
import Toolbar from '@material-ui/core/Toolbar';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { withStyles, getMuiTheme } from '@material-ui/core/styles';
|
||||
import MenuIcon from '@material-ui/icons/Menu';
|
||||
import Link from 'next/link'
|
||||
import Drawer from '@material-ui/core/Drawer';
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import SendIcon from '@material-ui/icons/Send';
|
||||
import CodeIcon from '@material-ui/icons/Code';
|
||||
import HomeIcon from '@material-ui/icons/Home';
|
||||
import FingerprintIcon from '@material-ui/icons/Fingerprint';
|
||||
import LocalBarIcon from '@material-ui/icons/LocalBar';
|
||||
import AccountCircle from '@material-ui/icons/AccountCircle';
|
||||
import HomeIcon from '@material-ui/icons/HomeOutlined';
|
||||
import OfferIcon from '@material-ui/icons/LocalOfferOutlined';
|
||||
import CompanyIcon from '@material-ui/icons/DomainOutlined';
|
||||
import HelpIcon from '@material-ui/icons/HelpOutline';
|
||||
import VideoIcon from '@material-ui/icons/OndemandVideoOutlined';
|
||||
import NotesIcon from '@material-ui/icons/NotesOutlined';
|
||||
import SupervisorAccountIcon from '@material-ui/icons/SupervisorAccount';
|
||||
import PersonIcon from '@material-ui/icons/Person';
|
||||
import PersonAddIcon from '@material-ui/icons/PersonAdd';
|
||||
import WorkOutlineIcon from '@material-ui/icons/WorkOutline';
|
||||
import AccountCircleOutlinedIcon from '@material-ui/icons/AccountCircleOutlined';
|
||||
import FolderSharedIcon from '@material-ui/icons/FolderShared';
|
||||
import AccountCircleIcon from '@material-ui/icons/AccountCircle';
|
||||
import PermContactCalendar from '@material-ui/icons/PermContactCalendar';
|
||||
import VideoCam from '@material-ui/icons/Videocam';
|
||||
import SettingsIcon from '@material-ui/icons/Settings';
|
||||
import PowerSettingsNewIcon from '@material-ui/icons/PowerSettingsNew';
|
||||
import ArrowForward from '@material-ui/icons/ArrowForward';
|
||||
import List from '@material-ui/core/List';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import { ListItemText } from '@material-ui/core';
|
||||
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||
import Loader from './../templates/loader'
|
||||
import { connect } from 'react-redux'
|
||||
import { fetchCurrentUserRequest } from "../../actions/user";
|
||||
import { requestLogout } from "../../actions/auth";
|
||||
import Button from '@material-ui/core/Button';
|
||||
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { withRouter } from "next/router";
|
||||
import ActiveLink from "./../atoms/Activelink";
|
||||
import axios from 'axios';
|
||||
import setAuthorizationHeader from "../../data/setAuthorizationHeader";
|
||||
import getConfig from 'next/config'
|
||||
import Router from 'next/router'
|
||||
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
zIndex: '999',
|
||||
'& a': {
|
||||
textDecoration: 'none'
|
||||
}
|
||||
},
|
||||
|
||||
toolbar: {
|
||||
height: '64px',
|
||||
},
|
||||
grow: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
bar: {
|
||||
},
|
||||
menuButton: {
|
||||
marginLeft: -12,
|
||||
marginRight: 20,
|
||||
@@ -46,40 +65,240 @@ const styles = theme => ({
|
||||
menuLogo: {
|
||||
cursor: 'pointer',
|
||||
[theme.breakpoints.down('md')]: {
|
||||
width:'200px'
|
||||
width: '200px'
|
||||
},
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
width:'100px'
|
||||
width: '130px'
|
||||
},
|
||||
},
|
||||
title: {
|
||||
display: 'none',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
display: 'block',
|
||||
},
|
||||
[theme.breakpoints.down('md')]: {
|
||||
display: 'none',
|
||||
},
|
||||
marginRight: 15,
|
||||
cursor: 'pointer'
|
||||
menuAvatar: {
|
||||
width: '2.5em',
|
||||
borderRadius: '50%',
|
||||
marginTop: theme.spacing(2),
|
||||
marginLeft: theme.spacing(2),
|
||||
},
|
||||
sectionDesktop: {
|
||||
display: 'none',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
display: 'flex',
|
||||
},
|
||||
menuUserName: {
|
||||
color: theme.palette.menu.emailText,
|
||||
fontSize: '1.3rem',
|
||||
fontWeight: '500',
|
||||
},
|
||||
sectionMobile: {
|
||||
menuUserEmail: {
|
||||
color: theme.palette.menu.emailText,
|
||||
fontSize: '0.9rem',
|
||||
fontWeight: '200',
|
||||
},
|
||||
darkDivider: {
|
||||
background: 'whitesmoke',
|
||||
opacity: '0.1',
|
||||
},
|
||||
List: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
height: '100%',
|
||||
paddingTop: 0,
|
||||
paddingBottom: 0,
|
||||
'&>a:first-child': {
|
||||
minHeight: '64px',
|
||||
height: '64px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
display: 'none',
|
||||
'&>a:first-child': {
|
||||
height: '64px',
|
||||
},
|
||||
'&>a:first-child li': {
|
||||
height: '64px',
|
||||
alignItems: 'center',
|
||||
},
|
||||
},
|
||||
},
|
||||
fullList: {
|
||||
width: 'auto',
|
||||
cursor: 'pointer'
|
||||
cursor: 'pointer',
|
||||
paddingBottom: 0
|
||||
},
|
||||
lightFullList: {
|
||||
height: '100vh',
|
||||
backgroundColor: theme.palette.background.default,
|
||||
},
|
||||
darkFullList: {
|
||||
backgroundColor: theme.palette.background.dark,
|
||||
},
|
||||
lightMenuItem: {
|
||||
color: theme.palette.menu.lightText,
|
||||
textDecoration: 'none',
|
||||
},
|
||||
darkMenuItem: {
|
||||
color: theme.palette.menu.darkText,
|
||||
textDecoration: 'none',
|
||||
},
|
||||
darkMenuItemSpecific: {
|
||||
'&:hover,&:active': {
|
||||
color: theme.palette.primary.main,
|
||||
}
|
||||
},
|
||||
links: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
height: '100%',
|
||||
},
|
||||
linkGroup: {
|
||||
padding: theme.spacing(1.2, 0),
|
||||
paddingLeft: 0,
|
||||
},
|
||||
videothequeLinkGroup: {
|
||||
backgroundColor: theme.palette.background.videotheque,
|
||||
},
|
||||
blogLinkGroup: {
|
||||
backgroundColor: theme.palette.background.blog,
|
||||
},
|
||||
recruteurLinkGroup: {
|
||||
backgroundColor: theme.palette.background.recruteur,
|
||||
},
|
||||
rootListItem: {
|
||||
padding: theme.spacing(1, 2),
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
},
|
||||
rootListItemIcon: {
|
||||
padding: theme.spacing(1, 2),
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
ListItemUserConnected: {
|
||||
flexDirection: 'column',
|
||||
},
|
||||
ListItemText: {
|
||||
fontSize: '1em',
|
||||
},
|
||||
icon: {
|
||||
paddingRight: theme.spacing(2.5),
|
||||
},
|
||||
iconAccount: {
|
||||
color: theme.palette.primary.dark,
|
||||
},
|
||||
title: {
|
||||
color: theme.palette.secondary.main,
|
||||
fontSize: '1.5em'
|
||||
},
|
||||
email: {
|
||||
color: theme.palette.menu.emailText,
|
||||
fontSize: '0.9em'
|
||||
},
|
||||
button: {
|
||||
padding: theme.spacing(0.5, 1),
|
||||
textTransform: 'inherit',
|
||||
'& svg': {
|
||||
width: '0.7em',
|
||||
height: '0.7em',
|
||||
},
|
||||
},
|
||||
|
||||
active: {
|
||||
'& span, & svg': {
|
||||
color: theme.palette.primary.main + ' !important',
|
||||
},
|
||||
},
|
||||
|
||||
//DESKTOP PART
|
||||
|
||||
desktopMenuItem: {
|
||||
[theme.breakpoints.down('md')]: {
|
||||
padding: theme.spacing(0.4),
|
||||
},
|
||||
'& span.MuiTypography-root': {
|
||||
fontSize: '0.8rem',
|
||||
fontWeight: '500',
|
||||
},
|
||||
},
|
||||
desktopMenuList: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
padding: 0,
|
||||
},
|
||||
appBar:{
|
||||
position:'fixed'
|
||||
},
|
||||
appBarDesktopSection: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
appBarDesktopSection1: {
|
||||
padding: theme.spacing(0, 2),
|
||||
height: '100%',
|
||||
borderRight: 'solid 1px whitesmoke',
|
||||
},
|
||||
appBarDesktopSection2: {
|
||||
width: '100%',
|
||||
justifyContent: 'space-between',
|
||||
padding: theme.spacing(0, 2),
|
||||
'& ul': {
|
||||
width: '95%',
|
||||
},
|
||||
'& ul>div': {
|
||||
display: 'flex',
|
||||
},
|
||||
'& ul > div:nth-child(1) a span': {
|
||||
color: theme.palette.primary.dark,
|
||||
'&:hover, &:active': {
|
||||
color: theme.palette.primary.main,
|
||||
}
|
||||
},
|
||||
'& .MuiListItemText-root': {
|
||||
padding: theme.spacing(0, 1),
|
||||
[theme.breakpoints.down('md')]: {
|
||||
padding: theme.spacing(0),
|
||||
},
|
||||
},
|
||||
'& a:last-child .MuiButtonBase-root span': {
|
||||
color: theme.palette.secondary.main,
|
||||
},
|
||||
},
|
||||
appBarDesktopSection3: {
|
||||
padding: theme.spacing(0, 2),
|
||||
height: '100%',
|
||||
backgroundColor: theme.palette.primary.dark,
|
||||
'& a': {
|
||||
display: 'flex',
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
'& span, & svg': {
|
||||
color: theme.palette.secondary.main,
|
||||
},
|
||||
},
|
||||
toolbarDesktop: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
height: '64px',
|
||||
},
|
||||
desktopMenuButtonLogin: {
|
||||
background: theme.palette.primary.main,
|
||||
borderColor: theme.palette.primary.main,
|
||||
},
|
||||
rootListItemDesktop: {
|
||||
[theme.breakpoints.up('md')]: {
|
||||
padding: theme.spacing(1),
|
||||
},
|
||||
},
|
||||
iconDesktop: {
|
||||
paddingRight: theme.spacing(2.5),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
paddingRight: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
let urlEnv;
|
||||
|
||||
class Header extends React.Component {
|
||||
state = {
|
||||
@@ -87,23 +306,51 @@ class Header extends React.Component {
|
||||
left: false,
|
||||
bottom: false,
|
||||
right: false,
|
||||
toggle: true
|
||||
toggle: true,
|
||||
|
||||
};
|
||||
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
toggleDrawer = (side, open) => () => {
|
||||
this.setState({
|
||||
[side]: open,
|
||||
});
|
||||
};
|
||||
|
||||
toggle = () => this.setState(state => ({ toggle: !state.toggle }))
|
||||
onRedirectAccount = e => {
|
||||
urlEnv = (process.env.NODE_ENV !== 'production') ? '//localhost/app_dev.php' : process.env.SERVER_URL;
|
||||
e.preventDefault();
|
||||
var redirectAccountUrl = urlEnv + "/api/talent?bearer=" + localStorage.getItem("ttJWT");
|
||||
window.open(redirectAccountUrl);
|
||||
}
|
||||
|
||||
toggle = () => this.setState(state => ({ toggle: !state.toggle }))
|
||||
chargerPage =(type)=> {
|
||||
console.log(type);
|
||||
//Router.replace(page);
|
||||
sessionStorage.setItem(type+'_currentPage',1);
|
||||
|
||||
}
|
||||
|
||||
redirectionrecruteur=(props) => {
|
||||
console.log("redirection recruteur")
|
||||
localStorage.removeItem("ttJWT");
|
||||
//this.openDialog()
|
||||
props.requestLogout();
|
||||
window.location.href = "https://recruteur.talentstube.com/";
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
const { publicRuntimeConfig } = getConfig();
|
||||
console.log("user",this.props.user)
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Drawer anchor="left" open={this.state.left} onClose={this.toggleDrawer('left', false)}>
|
||||
@@ -113,75 +360,82 @@ class Header extends React.Component {
|
||||
onClick={this.toggleDrawer('left', false)}
|
||||
onKeyDown={this.toggleDrawer('left', false)}
|
||||
>
|
||||
<div className={classes.fullList}>
|
||||
<List>
|
||||
<Link href="/" prefetch >
|
||||
<a><ListItem>
|
||||
<img alt="talents-tube" src='/static/images/logos/Logo-header.svg' className={classes.menuLogo} />
|
||||
<div className={classes.fullList + ' ' + classes.lightFullList}>
|
||||
<List className={classes.List}>
|
||||
|
||||
<Link href="/" >
|
||||
<a className={classes.darkMenuItem}><ListItem classes={{ root: classes.rootListItem }}>
|
||||
<img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-color.svg' className={classes.menuLogo} />
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
|
||||
|
||||
<Divider />
|
||||
<Link href="/" prefetch >
|
||||
<a><ListItem>
|
||||
<div className={classes.links}>
|
||||
{/* Menu Accueil /Offres Entreprises */}
|
||||
<div className={classes.linkGroup}>
|
||||
<ActiveLink activeClassName={classes.active} href="/" >
|
||||
<a className={classes.darkMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
<HomeIcon className={classes.icon} />
|
||||
<ListItemText classes={{ primary: classes.ListItemText }} primary='Accueil'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</ActiveLink>
|
||||
<ActiveLink activeClassName={classes.active} href="/Offres" >
|
||||
<a className={classes.darkMenuItem + ' ' + classes.darkMenuItemSpecific}><ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
<OfferIcon className={classes.icon} />
|
||||
<ListItemText classes={{ primary: classes.ListItemText }} primary={`Offres d'emploi`}>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</ActiveLink>
|
||||
<ActiveLink activeClassName={classes.active} href="/Entreprises" >
|
||||
<a className={classes.darkMenuItem + ' ' + classes.darkMenuItemSpecific}><ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
<CompanyIcon className={classes.icon} />
|
||||
<ListItemText classes={{ primary: classes.ListItemText }} primary='Nos entreprises'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</ActiveLink>
|
||||
<ActiveLink activeClassName={classes.active} href="/Help" >
|
||||
<a className={classes.darkMenuItem + ' ' + classes.darkMenuItemSpecific}><ListItem classes={{ root: classes.rootListItem }}>
|
||||
<HelpIcon className={classes.icon} />
|
||||
<ListItemText classes={{ primary: classes.ListItemText }} primary='Comment ça marche ?'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</ActiveLink>
|
||||
|
||||
<a className={classes.darkMenuItem + ' ' + classes.darkMenuItemSpecific} href="https://blog.talentstube.com/" target="_blank">
|
||||
<ListItem classes={{ root: classes.rootListItem }}>
|
||||
<NotesIcon className={classes.icon} />
|
||||
<ListItemText classes={{ primary: classes.ListItemText }} primary='Blog'>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
{/* FIN Menu Accueil /Offres Entreprises */}
|
||||
{/* Menu recruteur */}
|
||||
<div>
|
||||
{/* <div className={classes.blogLinkGroup}>
|
||||
<a href={publicRuntimeConfig.blogUrl} className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
<NotesIcon className={classes.icon} />
|
||||
<ListItemText classes={{ primary: classes.ListItemText }} primary='Blog'>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
</a>
|
||||
</div> */}
|
||||
<div className={classes.recruteurLinkGroup}>
|
||||
<a href={publicRuntimeConfig.symphonyUrl } className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
<SupervisorAccountIcon className={classes.icon} />
|
||||
<ListItemText classes={{ primary: classes.ListItemText }} primary='Recruteurs'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</div>
|
||||
</div>
|
||||
{/* FIN Menu recruteur*/}
|
||||
|
||||
<ListItemText primary='Accueil'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
<Link href="/Offres" prefetch >
|
||||
<a><ListItem>
|
||||
|
||||
<ListItemText primary="Offres d'emploi">
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
<Link href="/Companies" prefetch >
|
||||
<a><ListItem>
|
||||
|
||||
<ListItemText primary='Entreprises'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
<Link href="/help" prefetch >
|
||||
<a><ListItem>
|
||||
|
||||
<ListItemText primary='Comment ça marche ?'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
<Divider />
|
||||
|
||||
<Link href="/" prefetch >
|
||||
<a><ListItem>
|
||||
|
||||
<ListItemText primary='CV vidéothèque'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
<Link href="https://blog.talentstube.com" prefetch >
|
||||
<a><ListItem>
|
||||
|
||||
<ListItemText primary='Blog'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
<Link href="/contact" prefetch >
|
||||
<a><ListItem>
|
||||
|
||||
<ListItemText primary='Contact'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
<Divider />
|
||||
|
||||
<Link href="https://www.talentstube.com/faire-offre-emploi-video" prefetch >
|
||||
<a><ListItem>
|
||||
|
||||
<ListItemText primary='Recruteurs'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
</div>
|
||||
</List>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</Drawer>
|
||||
@@ -192,118 +446,268 @@ class Header extends React.Component {
|
||||
role="button"
|
||||
onClick={this.toggleDrawer('right', false)}
|
||||
onKeyDown={this.toggleDrawer('right', false)}
|
||||
>{!!this.props.loading &&
|
||||
(<div className="alert alert-info"><CircularProgress color="secondary" />Chargement...</div>
|
||||
)}
|
||||
>
|
||||
{!!this.props.loading &&
|
||||
(<Loader />
|
||||
)
|
||||
}
|
||||
{!!!this.props.loading && !!!this.props.fetched
|
||||
&&
|
||||
<div className={classes.fullList}>
|
||||
<div className={classes.fullList + ' ' + classes.darkFullList}>
|
||||
<List>
|
||||
<ListItem>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
<Link href="/login" prefetch >
|
||||
<a><ListItem>
|
||||
|
||||
<ListItemText primary='Connexion'>
|
||||
</ListItemText>
|
||||
<Link href="/" >
|
||||
<a className={classes.darkMenuItem + ' cypFrontPage'}><ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
<img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-blanc.svg' className={classes.menuLogo} />
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
{/* TODO */}
|
||||
<Link href="/login" prefetch >
|
||||
<a><ListItem>
|
||||
|
||||
<ListItemText primary='Inscription'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
<Divider />
|
||||
<Link href="https://www.talentstube.com/faire-offre-emploi-video" >
|
||||
<a><ListItem>
|
||||
|
||||
<ListItemText primary='Espace recruteurs'>
|
||||
<Divider light={true} />
|
||||
|
||||
<div className={classes.linkGroup}>
|
||||
<Link href="/Login" >
|
||||
<a className={classes.lightMenuItem + ' cypConnexion'}><ListItem classes={{ root: classes.rootListItemIcon }} >
|
||||
<PersonIcon className={classes.icon} />
|
||||
<ListItemText classes={{ primary: classes.ListItemText }} primary='Connexion'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
{/* TODO */}
|
||||
<Link href="/Inscription" >
|
||||
<a className={classes.lightMenuItem + ' cypRegister'}><ListItem classes={{ primary: classes.ListItemText }} classes={{ root: classes.rootListItem }}>
|
||||
<PersonAddIcon className={classes.icon} />
|
||||
<ListItemText primary='Inscription'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<Divider light={true} />
|
||||
|
||||
<div className={classes.linkGroup}>
|
||||
<a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.lightMenuItem}><ListItem classes={{ primary: classes.ListItemText }} classes={{ root: classes.rootListItemIcon }}>
|
||||
<WorkOutlineIcon className={classes.icon} />
|
||||
<ListItemText primary='Connexion recruteurs'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
</ListItem>
|
||||
</a>
|
||||
</div>
|
||||
</List>
|
||||
</div>}
|
||||
{!!!this.props.loading && !!this.props.fetched &&
|
||||
</div>
|
||||
}
|
||||
{!!!this.props.loading && !!this.props.fetched &&
|
||||
<Fragment>
|
||||
<ListItem>
|
||||
{this.props.user.firstname}
|
||||
{this.props.user.lastname}
|
||||
{this.props.user.email}
|
||||
</ListItem>
|
||||
<Divider />
|
||||
{/* TODO:real links */}
|
||||
<Link href="/Candidatures" prefetch >
|
||||
<a><ListItem>
|
||||
<ListItemText primary='Mes candidatures'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
<Link href="/help" prefetch >
|
||||
<a><ListItem>
|
||||
<ListItemText primary='Mon compte'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
<Link href="/help" prefetch >
|
||||
<a><ListItem>
|
||||
<ListItemText primary='Paramètres'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
{this.props.user.picture ?
|
||||
<img alt="talents-tube" src={publicRuntimeConfig.symphonyUrl +publicRuntimeConfig.postedContentUrl+ this.props.user.picture} className={classes.menuAvatar} />
|
||||
:
|
||||
<img alt="talents-tube" src='/static/images/default/account-avatar-default.svg' className={classes.menuAvatar} />
|
||||
}
|
||||
|
||||
<ListItem classes={{ root: classes.rootListItem }} className={classes.ListItemUserConnected}>
|
||||
<Typography gutterBottom component="h1" className={classes.menuUserName}>
|
||||
{this.props.user.firstname + " " + this.props.user.lastname}
|
||||
</Typography>
|
||||
|
||||
<ListItem>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={classes.button}
|
||||
onClick={() => this.props.requestLogout()}>Déconnexion</Button>
|
||||
<Typography gutterBottom component="h3" className={classes.menuUserEmail} >
|
||||
{this.props.user.email}
|
||||
</Typography>
|
||||
</ListItem>
|
||||
|
||||
<Divider className={classes.darkDivider} />
|
||||
|
||||
{this.props.user.type=="TALENT"
|
||||
?
|
||||
<div>
|
||||
<Link href="/Candidatures" >
|
||||
<a className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
<FolderSharedIcon className={classes.icon} />
|
||||
<ListItemText primary='Mes candidatures'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
<Link href="/profileStep" >
|
||||
<a className={classes.lightMenuItem}>
|
||||
<ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
<AccountCircleIcon className={classes.icon} />
|
||||
<ListItemText primary='Mon compte'>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<Link href="/Parametres" >
|
||||
<a className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
<SettingsIcon className={classes.icon} />
|
||||
<ListItemText primary='Paramètres de notification'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
</div>
|
||||
:
|
||||
this.redirectionrecruteur(this.props)
|
||||
|
||||
// <div>
|
||||
|
||||
// <a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.lightMenuItem}>
|
||||
// <ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
// <SettingsIcon className={classes.icon} />
|
||||
// <ListItemText primary='Espace recruteur'>
|
||||
// </ListItemText>
|
||||
// </ListItem></a>
|
||||
|
||||
// </div>
|
||||
|
||||
}
|
||||
|
||||
|
||||
<Link href="/" >
|
||||
<a onClick={() => {
|
||||
localStorage.removeItem("ttJWT");
|
||||
return this.props.requestLogout();
|
||||
}} className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
<PowerSettingsNewIcon className={classes.icon} />
|
||||
<ListItemText primary='Déconnexion'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
</Fragment>
|
||||
}
|
||||
</div>
|
||||
</Drawer>
|
||||
<AppBar position="static" className={classes.appBar}>
|
||||
<Toolbar>
|
||||
<IconButton className={classes.menuButton} onClick={this.toggleDrawer('left', true)}
|
||||
color="inherit" aria-label="Open drawer">
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
<div className={classes.grow} />
|
||||
|
||||
<img alt="talents-tube" src='/static/images/logos/Logo-header.svg' className={classes.menuLogo} />
|
||||
{isWidthUp('md', this.props.width) ?
|
||||
(<AppBar position="static" className={classes.appBar}>
|
||||
<Toolbar disableGutters={true} className={classes.toolbarDesktop}>
|
||||
<section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection1}>
|
||||
<Link href="/" >
|
||||
<a className={classes.darkMenuItem}>
|
||||
<ListItem classes={{ root: classes.rootListItemDesktop }}>
|
||||
<img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-color.svg' className={classes.desktopMenuLogo} />
|
||||
</ListItem>
|
||||
</a>
|
||||
</Link>
|
||||
</section>
|
||||
<section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection2}>
|
||||
<IconButton className={classes.menuButton} onClick={this.toggleDrawer('left', true)}
|
||||
color="inherit" aria-label="Open drawer">
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
|
||||
<div className={classes.grow} />
|
||||
<IconButton
|
||||
edge="end"
|
||||
aria-label="Profile"
|
||||
aria-controls={'primary-search-account-menu'}
|
||||
aria-haspopup="true"
|
||||
onClick={this.toggleDrawer('right', true)}
|
||||
color="inherit"
|
||||
>
|
||||
<AccountCircle />
|
||||
</IconButton>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
<List className={classes.desktopMenuList}>
|
||||
<div>
|
||||
<ActiveLink activeClassName={classes.active} href="/Offres" >
|
||||
<a className={classes.desktopMenuItem} >
|
||||
<ListItemText primary="Offres d'emploi">
|
||||
</ListItemText>
|
||||
</a>
|
||||
</ActiveLink>
|
||||
<ActiveLink activeClassName={classes.active} href="/Entreprises" >
|
||||
<a className={classes.desktopMenuItem}>
|
||||
<ListItemText primary='Nos entreprises'>
|
||||
</ListItemText>
|
||||
</a>
|
||||
</ActiveLink>
|
||||
<ActiveLink activeClassName={classes.active} href="/Help" >
|
||||
<a className={classes.desktopMenuItem}>
|
||||
<ListItemText primary='Comment ça marche ?'>
|
||||
</ListItemText>
|
||||
</a>
|
||||
</ActiveLink>
|
||||
|
||||
<a className={classes.desktopMenuItem} target="_blank" href="https://blog.talentstube.com/">
|
||||
<ListItemText primary='Blog'>
|
||||
</ListItemText>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{!!!this.props.loading && !!!this.props.fetched &&
|
||||
<Fragment>
|
||||
<Link href="/Inscription" >
|
||||
<a className={classes.desktopMenuItem}>
|
||||
<ListItem classes={{ root: classes.rootListItemDesktop }}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
className={classes.button + ' ' + classes.desktopMenuButtonRegister}>
|
||||
<PersonAddIcon className={classes.iconDesktop} />
|
||||
<ListItemText classes={{ primary: classes.ListItemText }} primary='Inscription'></ListItemText>
|
||||
</Button >
|
||||
</ListItem>
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<Link href="/Login" >
|
||||
<a className={classes.desktopMenuItem}>
|
||||
<ListItem classes={{ root: classes.rootListItemDesktop }}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
className={classes.button + ' ' + classes.desktopMenuButtonLogin}>
|
||||
<PersonIcon className={classes.iconDesktop} />
|
||||
<ListItemText classes={{ primary: classes.ListItemText }} primary='Connexion'></ListItemText>
|
||||
</Button >
|
||||
</ListItem>
|
||||
</a>
|
||||
</Link>
|
||||
</Fragment>
|
||||
}
|
||||
{!!!this.props.loading && !!this.props.fetched &&
|
||||
<IconButton
|
||||
edge="end"
|
||||
aria-label="Profile"
|
||||
aria-controls={'primary-search-account-menu'}
|
||||
aria-haspopup="true"
|
||||
onClick={this.toggleDrawer('right', true)}
|
||||
className={classes.iconAccount + ' cypConnexionMenu'}
|
||||
>
|
||||
<AccountCircleOutlinedIcon />
|
||||
</IconButton>
|
||||
}
|
||||
</div>
|
||||
</List>
|
||||
</section>
|
||||
{/* <section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection3}>
|
||||
|
||||
<a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.desktopMenuItem}>
|
||||
<ListItemText primary='Espace recruteurs'>
|
||||
</ListItemText>
|
||||
<ArrowForward className={classes.icon} />
|
||||
</a>
|
||||
</section> */}
|
||||
</Toolbar>
|
||||
</AppBar>)
|
||||
:
|
||||
(
|
||||
<AppBar position="static" className={classes.appBar}>
|
||||
<Toolbar className={classes.toolbar}>
|
||||
<IconButton className={classes.menuButton} onClick={this.toggleDrawer('left', true)}
|
||||
color="inherit" role="button">
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
<div className={classes.grow} />
|
||||
<Link href="/" >
|
||||
<a><img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-color.svg' className={classes.menuLogo} /></a>
|
||||
</Link>
|
||||
<div className={classes.grow} />
|
||||
<IconButton
|
||||
edge="end"
|
||||
aria-label="Profile"
|
||||
aria-controls={'primary-search-account-menu'}
|
||||
aria-haspopup="true"
|
||||
onClick={this.toggleDrawer('right', true)}
|
||||
className={classes.iconAccount + ' cypConnexionMenu'}
|
||||
|
||||
>
|
||||
<AccountCircleOutlinedIcon />
|
||||
</IconButton>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
)}
|
||||
</div >
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Header.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
user: state.user,
|
||||
@@ -311,5 +715,4 @@ function mapStateToProps(state) {
|
||||
loading: !!state.user.loading
|
||||
};
|
||||
}
|
||||
export default withStyles(styles)(connect(mapStateToProps, { fetchCurrentUserRequest, requestLogout })(Header));
|
||||
|
||||
export default (connect(mapStateToProps, { fetchCurrentUserRequest, requestLogout })(withStyles(styles)(withWidth()(Header))));
|
||||
@@ -0,0 +1,634 @@
|
||||
import React, { Fragment, Children } from 'react';
|
||||
import AppBar from '@material-ui/core/AppBar';
|
||||
import Toolbar from '@material-ui/core/Toolbar';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import { withStyles, getMuiTheme } from '@material-ui/core/styles';
|
||||
import MenuIcon from '@material-ui/icons/Menu';
|
||||
import Link from 'next/link'
|
||||
import Drawer from '@material-ui/core/Drawer';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import HomeIcon from '@material-ui/icons/HomeOutlined';
|
||||
import OfferIcon from '@material-ui/icons/LocalOfferOutlined';
|
||||
import CompanyIcon from '@material-ui/icons/DomainOutlined';
|
||||
import HelpIcon from '@material-ui/icons/HelpOutline';
|
||||
import VideoIcon from '@material-ui/icons/OndemandVideoOutlined';
|
||||
import NotesIcon from '@material-ui/icons/NotesOutlined';
|
||||
import SupervisorAccountIcon from '@material-ui/icons/SupervisorAccount';
|
||||
import PersonIcon from '@material-ui/icons/Person';
|
||||
import PersonAddIcon from '@material-ui/icons/PersonAdd';
|
||||
import WorkOutlineIcon from '@material-ui/icons/WorkOutline';
|
||||
import AccountCircleOutlinedIcon from '@material-ui/icons/AccountCircleOutlined';
|
||||
import FolderSharedIcon from '@material-ui/icons/FolderShared';
|
||||
import AccountCircleIcon from '@material-ui/icons/AccountCircle';
|
||||
import PermContactCalendar from '@material-ui/icons/PermContactCalendar';
|
||||
import VideoCam from '@material-ui/icons/Videocam';
|
||||
import SettingsIcon from '@material-ui/icons/Settings';
|
||||
import PowerSettingsNewIcon from '@material-ui/icons/PowerSettingsNew';
|
||||
import ArrowForward from '@material-ui/icons/ArrowForward';
|
||||
import List from '@material-ui/core/List';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import { ListItemText } from '@material-ui/core';
|
||||
import Loader from '../templates/loader'
|
||||
import { connect } from 'react-redux'
|
||||
import { fetchCurrentUserRequest } from "../../actions/user";
|
||||
import { requestLogout } from "../../actions/auth";
|
||||
import Button from '@material-ui/core/Button';
|
||||
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { withRouter } from "next/router";
|
||||
import ActiveLink from "../atoms/Activelink";
|
||||
import axios from 'axios';
|
||||
import setAuthorizationHeader from "../../data/setAuthorizationHeader";
|
||||
import getConfig from 'next/config'
|
||||
import Router from 'next/router'
|
||||
import ButtonBase from "@material-ui/core/ButtonBase";
|
||||
import ArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
|
||||
import LoadingBar from 'react-redux-loading-bar'
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
zIndex: '999',
|
||||
'& a': {
|
||||
textDecoration: 'none'
|
||||
}
|
||||
},
|
||||
toolbar: {
|
||||
height: '64px',
|
||||
},
|
||||
grow: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
menuButton: {
|
||||
marginLeft: -12,
|
||||
marginRight: 20,
|
||||
display: 'block'
|
||||
},
|
||||
menuLogo: {
|
||||
cursor: 'pointer',
|
||||
[theme.breakpoints.down('md')]: {
|
||||
width: '200px'
|
||||
},
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
width: '130px'
|
||||
},
|
||||
},
|
||||
menuAvatar: {
|
||||
width: '2.5em',
|
||||
borderRadius: '50%',
|
||||
marginTop: theme.spacing(2),
|
||||
marginLeft: theme.spacing(2),
|
||||
},
|
||||
menuUserName: {
|
||||
color: theme.palette.menu.emailText,
|
||||
fontSize: '1.3rem',
|
||||
fontWeight: '500',
|
||||
},
|
||||
menuUserEmail: {
|
||||
color: theme.palette.menu.emailText,
|
||||
fontSize: '0.9rem',
|
||||
fontWeight: '200',
|
||||
},
|
||||
darkDivider: {
|
||||
background: 'whitesmoke',
|
||||
opacity: '0.1',
|
||||
},
|
||||
List: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
height: '100%',
|
||||
paddingTop: 0,
|
||||
paddingBottom: 0,
|
||||
'&>a:first-child': {
|
||||
minHeight: '64px',
|
||||
height: '64px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
'&>a:first-child': {
|
||||
height: '64px',
|
||||
},
|
||||
'&>a:first-child li': {
|
||||
height: '64px',
|
||||
alignItems: 'center',
|
||||
},
|
||||
},
|
||||
},
|
||||
fullList: {
|
||||
width: 'auto',
|
||||
cursor: 'pointer',
|
||||
paddingBottom: 0
|
||||
},
|
||||
lightFullList: {
|
||||
height: '100vh',
|
||||
backgroundColor: theme.palette.background.default,
|
||||
},
|
||||
darkFullList: {
|
||||
backgroundColor: theme.palette.background.dark,
|
||||
},
|
||||
lightMenuItem: {
|
||||
color: theme.palette.menu.lightText,
|
||||
textDecoration: 'none',
|
||||
},
|
||||
darkMenuItem: {
|
||||
color: theme.palette.menu.darkText,
|
||||
textDecoration: 'none',
|
||||
},
|
||||
darkMenuItemSpecific: {
|
||||
'&:hover,&:active': {
|
||||
color: theme.palette.primary.main,
|
||||
}
|
||||
},
|
||||
links: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
height: '100%',
|
||||
},
|
||||
linkGroup: {
|
||||
padding: theme.spacing(1.2, 0),
|
||||
paddingLeft: 0,
|
||||
},
|
||||
videothequeLinkGroup: {
|
||||
backgroundColor: theme.palette.background.videotheque,
|
||||
},
|
||||
blogLinkGroup: {
|
||||
backgroundColor: theme.palette.background.blog,
|
||||
},
|
||||
recruteurLinkGroup: {
|
||||
backgroundColor: theme.palette.background.recruteur,
|
||||
},
|
||||
rootListItem: {
|
||||
padding: theme.spacing(1, 2),
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
},
|
||||
rootListItemIcon: {
|
||||
padding: theme.spacing(1, 2),
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
ListItemUserConnected: {
|
||||
flexDirection: 'column',
|
||||
},
|
||||
ListItemText: {
|
||||
fontSize: '1em',
|
||||
},
|
||||
icon: {
|
||||
paddingRight: theme.spacing(2.5),
|
||||
},
|
||||
iconAccount: {
|
||||
color: theme.palette.primary.dark,
|
||||
},
|
||||
title: {
|
||||
color: theme.palette.secondary.main,
|
||||
fontSize: '1.5em'
|
||||
},
|
||||
email: {
|
||||
color: theme.palette.menu.emailText,
|
||||
fontSize: '0.9em'
|
||||
},
|
||||
button: {
|
||||
padding: theme.spacing(0.5, 1),
|
||||
textTransform: 'inherit',
|
||||
'& svg': {
|
||||
width: '0.7em',
|
||||
height: '0.7em',
|
||||
},
|
||||
},
|
||||
|
||||
active: {
|
||||
'& span, & svg': {
|
||||
color: theme.palette.primary.main + ' !important',
|
||||
},
|
||||
},
|
||||
|
||||
//DESKTOP PART
|
||||
|
||||
desktopMenuItem: {
|
||||
[theme.breakpoints.down('md')]: {
|
||||
padding: theme.spacing(0.4),
|
||||
},
|
||||
'& span.MuiTypography-root': {
|
||||
fontSize: '0.8rem',
|
||||
fontWeight: '500',
|
||||
},
|
||||
},
|
||||
desktopMenuList: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
padding: 0,
|
||||
},
|
||||
appBar:{
|
||||
position:'fixed'
|
||||
},
|
||||
appBarDesktopSection: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
appBarDesktopSection1: {
|
||||
padding: theme.spacing(0, 2),
|
||||
height: '100%',
|
||||
borderRight: 'solid 1px whitesmoke',
|
||||
},
|
||||
appBarDesktopSection2: {
|
||||
width: '100%',
|
||||
justifyContent: 'space-between',
|
||||
padding: theme.spacing(0, 2),
|
||||
'& ul': {
|
||||
width: '95%',
|
||||
},
|
||||
'& ul>div': {
|
||||
display: 'flex',
|
||||
},
|
||||
'& ul > div:nth-child(1) a span': {
|
||||
color: theme.palette.primary.dark,
|
||||
'&:hover, &:active': {
|
||||
color: theme.palette.primary.main,
|
||||
}
|
||||
},
|
||||
'& .MuiListItemText-root': {
|
||||
padding: theme.spacing(0, 1),
|
||||
[theme.breakpoints.down('md')]: {
|
||||
padding: theme.spacing(0),
|
||||
},
|
||||
},
|
||||
'& a:last-child .MuiButtonBase-root span': {
|
||||
color: theme.palette.secondary.main,
|
||||
},
|
||||
},
|
||||
appBarDesktopSection3: {
|
||||
padding: theme.spacing(0, 2),
|
||||
height: '100%',
|
||||
backgroundColor: theme.palette.primary.dark,
|
||||
'& a': {
|
||||
display: 'flex',
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
'& span, & svg': {
|
||||
color: theme.palette.secondary.main,
|
||||
},
|
||||
},
|
||||
toolbarDesktop: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
height: '64px',
|
||||
},
|
||||
desktopMenuButtonLogin: {
|
||||
background: theme.palette.primary.main,
|
||||
borderColor: theme.palette.primary.main,
|
||||
},
|
||||
rootListItemDesktop: {
|
||||
[theme.breakpoints.up('md')]: {
|
||||
padding: theme.spacing(1),
|
||||
},
|
||||
},
|
||||
iconDesktop: {
|
||||
paddingRight: theme.spacing(2.5),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
paddingRight: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
let urlEnv;
|
||||
|
||||
class HeaderPersonnalise extends React.Component {
|
||||
state = {
|
||||
top: false,
|
||||
left: false,
|
||||
bottom: false,
|
||||
right: false,
|
||||
toggle: true
|
||||
};
|
||||
|
||||
redirectionrecruteur=(props) => {
|
||||
console.log("redirection recruteur")
|
||||
localStorage.removeItem("ttJWT");
|
||||
//this.openDialog()
|
||||
props.requestLogout();
|
||||
window.location.href = "https://recruteur.talentstube.com/";
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
toggleDrawer = (side, open) => () => {
|
||||
this.setState({
|
||||
[side]: open,
|
||||
});
|
||||
};
|
||||
|
||||
onRedirectAccount = e => {
|
||||
urlEnv = (process.env.NODE_ENV !== 'production') ? '//localhost/app_dev.php' : process.env.SERVER_URL;
|
||||
e.preventDefault();
|
||||
var redirectAccountUrl = urlEnv + "/api/talent?bearer=" + localStorage.getItem("ttJWT");
|
||||
window.open(redirectAccountUrl);
|
||||
}
|
||||
|
||||
toggle = () => this.setState(state => ({ toggle: !state.toggle }))
|
||||
chargerPage =(type)=> {
|
||||
console.log(type);
|
||||
//Router.replace(page);
|
||||
sessionStorage.setItem(type+'_currentPage',1);
|
||||
|
||||
}
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
const { publicRuntimeConfig } = getConfig();
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
|
||||
|
||||
<Drawer anchor="right" open={this.state.right} onClose={this.toggleDrawer('right', false)}>
|
||||
<div
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
onClick={this.toggleDrawer('right', false)}
|
||||
onKeyDown={this.toggleDrawer('right', false)}
|
||||
>{!!this.props.loading &&
|
||||
(<Loader />
|
||||
)}
|
||||
{!!!this.props.loading && !!!this.props.fetched
|
||||
&&
|
||||
<div className={classes.fullList + ' ' + classes.darkFullList}>
|
||||
<List>
|
||||
<Link href="/" >
|
||||
<a className={classes.darkMenuItem + ' cypFrontPage'}><ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
<img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-blanc.svg' className={classes.menuLogo} />
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
|
||||
|
||||
<Divider light={true} />
|
||||
|
||||
<div className={classes.linkGroup}>
|
||||
<Link href="/Login" >
|
||||
<a className={classes.lightMenuItem + ' cypConnexion'}><ListItem classes={{ root: classes.rootListItemIcon }} >
|
||||
<PersonIcon className={classes.icon} />
|
||||
<ListItemText classes={{ primary: classes.ListItemText }} primary='Connexion'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
{/* TODO */}
|
||||
<Link href="/Inscription" >
|
||||
<a className={classes.lightMenuItem + ' cypRegister'}><ListItem classes={{ primary: classes.ListItemText }} classes={{ root: classes.rootListItem }}>
|
||||
<PersonAddIcon className={classes.icon} />
|
||||
<ListItemText primary='Inscription'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<Divider light={true} />
|
||||
|
||||
<div className={classes.linkGroup}>
|
||||
<a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.lightMenuItem}><ListItem classes={{ primary: classes.ListItemText }} classes={{ root: classes.rootListItemIcon }}>
|
||||
<WorkOutlineIcon className={classes.icon} />
|
||||
<ListItemText primary='Connexion recruteurs'>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
</a>
|
||||
</div>
|
||||
</List>
|
||||
</div>}
|
||||
{!!!this.props.loading && !!this.props.fetched &&
|
||||
<Fragment>
|
||||
{this.props.user.picture ?
|
||||
<img alt="talents-tube" src={publicRuntimeConfig.symphonyUrl +publicRuntimeConfig.postedContentUrl+ this.props.user.picture} className={classes.menuAvatar} />
|
||||
:
|
||||
<img alt="talents-tube" src='/static/images/default/account-avatar-default.svg' className={classes.menuAvatar} />
|
||||
}
|
||||
<ListItem classes={{ root: classes.rootListItem }} className={classes.ListItemUserConnected}>
|
||||
<Typography gutterBottom component="h1" className={classes.menuUserName}>
|
||||
{this.props.user.firstname + " " + this.props.user.lastname}
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom component="h3" className={classes.menuUserEmail} >
|
||||
{this.props.user.email}
|
||||
</Typography>
|
||||
</ListItem>
|
||||
|
||||
<Divider className={classes.darkDivider} />
|
||||
{this.props.user.type=="TALENT"
|
||||
?
|
||||
<div>
|
||||
<Link href="/Candidatures" >
|
||||
<a className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
<FolderSharedIcon className={classes.icon} />
|
||||
<ListItemText primary='Mes candidatures'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
<Link href="/profileStep" >
|
||||
<a className={classes.lightMenuItem}>
|
||||
<ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
<AccountCircleIcon className={classes.icon} />
|
||||
<ListItemText primary='Mon compte'>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<Link href="/Parametres" >
|
||||
<a className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
<SettingsIcon className={classes.icon} />
|
||||
<ListItemText primary='Paramètres de notification'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
</div>
|
||||
:
|
||||
this.redirectionrecruteur(this.props)
|
||||
|
||||
// <div>
|
||||
|
||||
// <a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.lightMenuItem}>
|
||||
// <ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
// <SettingsIcon className={classes.icon} />
|
||||
// <ListItemText primary='Espace recruteur'>
|
||||
// </ListItemText>
|
||||
// </ListItem></a>
|
||||
|
||||
// </div>
|
||||
|
||||
}
|
||||
|
||||
|
||||
<Link href="/" >
|
||||
<a onClick={() => {
|
||||
localStorage.removeItem("ttJWT");
|
||||
return this.props.requestLogout();
|
||||
}} className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
|
||||
<PowerSettingsNewIcon className={classes.icon} />
|
||||
<ListItemText primary='Déconnexion'>
|
||||
</ListItemText>
|
||||
</ListItem></a>
|
||||
</Link>
|
||||
</Fragment>
|
||||
}
|
||||
</div>
|
||||
</Drawer>
|
||||
|
||||
{isWidthUp('md', this.props.width) ?
|
||||
(<AppBar position="static" className={classes.appBar}>
|
||||
<Toolbar disableGutters={true} className={classes.toolbarDesktop}>
|
||||
<section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection1}>
|
||||
<Link href="/" >
|
||||
<a className={classes.darkMenuItem}>
|
||||
<ListItem classes={{ root: classes.rootListItemDesktop }}>
|
||||
<img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-color.svg' className={classes.desktopMenuLogo} />
|
||||
</ListItem>
|
||||
</a>
|
||||
</Link>
|
||||
</section>
|
||||
<section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection2}>
|
||||
{/* <IconButton className={classes.menuButton} onClick={this.toggleDrawer('left', true)}
|
||||
color="inherit" aria-label="Open drawer">
|
||||
<MenuIcon />
|
||||
</IconButton> */}
|
||||
|
||||
<List className={classes.desktopMenuList}>
|
||||
<div>
|
||||
<ActiveLink activeClassName={classes.active} href="/Offres" >
|
||||
<a className={classes.desktopMenuItem} >
|
||||
<ListItemText primary="Offres d'emploi">
|
||||
</ListItemText>
|
||||
</a>
|
||||
</ActiveLink>
|
||||
<ActiveLink activeClassName={classes.active} href="/Entreprises" >
|
||||
<a className={classes.desktopMenuItem}>
|
||||
<ListItemText primary='Nos entreprises'>
|
||||
</ListItemText>
|
||||
</a>
|
||||
</ActiveLink>
|
||||
<ActiveLink activeClassName={classes.active} href="/Help" >
|
||||
<a className={classes.desktopMenuItem}>
|
||||
<ListItemText primary='Comment ça marche ?'>
|
||||
</ListItemText>
|
||||
</a>
|
||||
</ActiveLink>
|
||||
|
||||
<a className={classes.desktopMenuItem} target="_blank" href="https://blog.talentstube.com/">
|
||||
<ListItemText primary='Blog'>
|
||||
</ListItemText>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{!!!this.props.loading && !!!this.props.fetched &&
|
||||
<Fragment>
|
||||
<Link href="/Inscription" >
|
||||
<a className={classes.desktopMenuItem}>
|
||||
<ListItem classes={{ root: classes.rootListItemDesktop }}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
className={classes.button + ' ' + classes.desktopMenuButtonRegister}>
|
||||
<PersonAddIcon className={classes.iconDesktop} />
|
||||
<ListItemText classes={{ primary: classes.ListItemText }} primary='Inscription'></ListItemText>
|
||||
</Button >
|
||||
</ListItem>
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<Link href="/Login" >
|
||||
<a className={classes.desktopMenuItem}>
|
||||
<ListItem classes={{ root: classes.rootListItemDesktop }}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
className={classes.button + ' ' + classes.desktopMenuButtonLogin}>
|
||||
<PersonIcon className={classes.iconDesktop} />
|
||||
<ListItemText classes={{ primary: classes.ListItemText }} primary='Connexion'></ListItemText>
|
||||
</Button >
|
||||
</ListItem>
|
||||
</a>
|
||||
</Link>
|
||||
</Fragment>
|
||||
}
|
||||
{!!!this.props.loading && !!this.props.fetched &&
|
||||
<IconButton
|
||||
edge="end"
|
||||
aria-label="Profile"
|
||||
aria-controls={'primary-search-account-menu'}
|
||||
aria-haspopup="true"
|
||||
onClick={this.toggleDrawer('right', true)}
|
||||
className={classes.iconAccount + ' cypConnexionMenu'}
|
||||
>
|
||||
<AccountCircleOutlinedIcon />
|
||||
</IconButton>
|
||||
}
|
||||
</div>
|
||||
</List>
|
||||
</section>
|
||||
{/* <section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection3}>
|
||||
|
||||
<a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.desktopMenuItem}>
|
||||
<ListItemText primary='Espace recruteurs'>
|
||||
</ListItemText>
|
||||
<ArrowForward className={classes.icon} />
|
||||
</a>
|
||||
</section> */}
|
||||
</Toolbar>
|
||||
</AppBar>)
|
||||
:
|
||||
(
|
||||
<AppBar position="static" className={classes.appBar}>
|
||||
<Toolbar className={classes.toolbar}>
|
||||
{/* <IconButton className={classes.menuButton} onClick={this.toggleDrawer('left', true)}
|
||||
color="inherit" role="button">
|
||||
<MenuIcon />
|
||||
</IconButton> */}
|
||||
<ButtonBase name='back'
|
||||
focusRipple
|
||||
className={classes.back}
|
||||
focusVisibleClassName={classes.focusVisible}
|
||||
onClick={() => Router.push("/"+this.props.retour)}>
|
||||
<ArrowLeft color="primary" classes={{ root: classes.icon }}></ArrowLeft>
|
||||
</ButtonBase>
|
||||
<div className={classes.grow} />
|
||||
<Link href="/" >
|
||||
<a><img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-color.svg' className={classes.menuLogo} /></a>
|
||||
</Link>
|
||||
<div className={classes.grow} />
|
||||
<IconButton
|
||||
edge="end"
|
||||
aria-label="Profile"
|
||||
aria-controls={'primary-search-account-menu'}
|
||||
aria-haspopup="true"
|
||||
onClick={this.toggleDrawer('right', true)}
|
||||
className={classes.iconAccount + ' cypConnexionMenu'}
|
||||
|
||||
>
|
||||
<AccountCircleOutlinedIcon />
|
||||
</IconButton>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
)}
|
||||
</div >
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
user: state.user,
|
||||
fetched: !!state.user.fetched,
|
||||
loading: !!state.user.loading
|
||||
};
|
||||
}
|
||||
export default (connect(mapStateToProps, { fetchCurrentUserRequest, requestLogout })(withStyles(styles)(withWidth()(HeaderPersonnalise))));
|
||||
@@ -2,22 +2,35 @@ import React, { Component, Fragment } from 'react'
|
||||
import GridList from '@material-ui/core/GridList';
|
||||
import GridListTile from '@material-ui/core/GridListTile';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
|
||||
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
|
||||
import ArrowLeft from '@material-ui/icons/ArrowBackIosSharp';
|
||||
import ArrowRight from '@material-ui/icons/ArrowForwardIosSharp';
|
||||
import Hidden from '@material-ui/core/Hidden';
|
||||
import Tile from './Tile';
|
||||
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'space-around',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
overflow: 'hidden',
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
width: '100%',
|
||||
},
|
||||
rootGridList: {
|
||||
margin: '0 !important',
|
||||
},
|
||||
gridList: {
|
||||
position: 'relative',
|
||||
flexWrap: 'nowrap',
|
||||
scrollBehavior: 'smooth',
|
||||
width: '100%',
|
||||
// Promote the list into his own layer on Chrome. This cost memory but helps keeping high FPS.
|
||||
transform: 'translateZ(0)',
|
||||
height: '100%',
|
||||
marginBottom: theme.spacing(4),
|
||||
scrollbarWidth: 'none',
|
||||
'&::-webkit-scrollbar': {
|
||||
width: 0,
|
||||
}
|
||||
},
|
||||
gridListTile: {
|
||||
display: 'flex',
|
||||
@@ -25,44 +38,114 @@ const styles = theme => ({
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '100% !important',
|
||||
'&:first-child': {
|
||||
marginLeft: '3vw',
|
||||
//margin: '0 3vw',
|
||||
padding: '16px !important',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
margin: '0',
|
||||
paddingTop: '5vh',
|
||||
},
|
||||
},
|
||||
rootGridListTile: {
|
||||
margin: '3vw',
|
||||
|
||||
},
|
||||
tile: {
|
||||
width: '100% !important',
|
||||
overflow: 'visible !important',
|
||||
},
|
||||
anchor: {
|
||||
width: '100% !important',
|
||||
position: 'absolute',
|
||||
left: '16px',
|
||||
right: '16px',
|
||||
top: '-200px',
|
||||
visibility: 'hidden',
|
||||
},
|
||||
anchorPrevious: {
|
||||
left: '-16px',
|
||||
},
|
||||
anchorNext: {
|
||||
left: '16px',
|
||||
},
|
||||
icon: {
|
||||
width: '0.9em',
|
||||
height: '0.9em',
|
||||
padding: theme.spacing(1.5),
|
||||
color: theme.palette.secondary.main,
|
||||
background: theme.palette.primary.dark,
|
||||
borderRadius: '50%',
|
||||
},
|
||||
dNone: {
|
||||
visibility: 'hidden',
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
class HorizontalScroller extends Component {
|
||||
render() {
|
||||
const { classes } = this.props
|
||||
state = {
|
||||
defaultIndex: 2,
|
||||
direction: '',
|
||||
}
|
||||
|
||||
const children =(tile)=> React.Children.map(this.props.children, child => {
|
||||
handlePrevious = () => {
|
||||
this.setState({ direction: 'previous' })
|
||||
|
||||
if (this.state.defaultIndex == 8 || this.state.defaultIndex == 5) {
|
||||
this.setState({ defaultIndex: this.state.defaultIndex - 5 })
|
||||
}
|
||||
if (this.state.defaultIndex == 3) {
|
||||
this.setState({ defaultIndex: this.state.defaultIndex - 3 })
|
||||
}
|
||||
else if (this.state.defaultIndex == 0) {
|
||||
this.setState({ defaultIndex: this.state.defaultIndex + 8 })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
handleNext = () => {
|
||||
this.setState({ direction: 'next' })
|
||||
if (this.state.defaultIndex == 6 || this.state.defaultIndex == 7 || this.state.defaultIndex == 8) {
|
||||
this.setState({ defaultIndex: 0 })
|
||||
}
|
||||
else if (this.state.defaultIndex == 0 || this.state.defaultIndex == 3) {
|
||||
this.setState({ defaultIndex: this.state.defaultIndex + 5 })
|
||||
}
|
||||
else if (this.state.defaultIndex < 6) {
|
||||
this.setState({ defaultIndex: this.state.defaultIndex + 3 })
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes, type } = this.props
|
||||
const { defaultIndex } = this.state
|
||||
const children = (tile) => React.Children.map(this.props.children, child => {
|
||||
return React.cloneElement(child, {
|
||||
tile
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
<div> {/* Ne pas mettre de Fragment */}
|
||||
<GridList className={classes.gridList} cols={1.2}>
|
||||
{this.props.data.map(tile => (
|
||||
<GridListTile className={classes.gridListTile} classes={{ root: classes.rootGridListTile, tile: classes.tile }} key={tile.title}>
|
||||
<Tile rowData={tile}>
|
||||
{ children(tile) }
|
||||
<div className={classes.root}> {/* Ne pas mettre de Fragment */}
|
||||
<Hidden smDown>
|
||||
<a className={(defaultIndex < 3) ? classes.dNone : ''} onClick={this.handlePrevious} href={'#' + type + defaultIndex}><ArrowLeft classes={{ root: classes.icon }}></ArrowLeft></a>
|
||||
</Hidden>
|
||||
<GridList className={classes.gridList} cols={isWidthUp('md', this.props.width) ? 3 : isWidthUp('sm', this.props.width) ? 2.4 : 1.15} classes={{ root: classes.rootGridList }}>
|
||||
{this.props.data && this.props.data.map((tile, index) => (
|
||||
|
||||
<GridListTile className={classes.gridListTile} classes={{ root: classes.rootGridListTile, tile: classes.tile }} key={index}>
|
||||
<Tile rowData={tile} key={index}>
|
||||
{(this.state.direction == 'previous') ? (<a id={type + index} className={classes.anchor + ' ' + classes.anchorPrevious}></a>) : (<a id={type + index} className={classes.anchor + ' ' + classes.anchorNext}></a>)
|
||||
}
|
||||
{children(tile)}
|
||||
</Tile>
|
||||
</GridListTile>
|
||||
|
||||
))}
|
||||
</GridList>
|
||||
<Hidden smDown>
|
||||
<a className={(defaultIndex > 5) ? classes.dNone : ''} onClick={this.handleNext} href={'#' + type + defaultIndex}><ArrowRight classes={{ root: classes.icon }}></ArrowRight></a>
|
||||
</Hidden>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(HorizontalScroller)
|
||||
export default withStyles(styles)(withWidth()(HorizontalScroller))
|
||||
|
||||
@@ -1,34 +1,179 @@
|
||||
import React, { Component } from 'react'
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { connect } from "react-redux";
|
||||
import Validator from "validator";
|
||||
import { subscribeToNewsletterRequest } from "../../actions/user";
|
||||
import { Typography, Button } from '@material-ui/core';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
|
||||
import _ from "lodash";
|
||||
import SendIcon from '@material-ui/icons/Send';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Snack from '../atoms/snack'
|
||||
|
||||
const styles = theme => ({
|
||||
textField: {
|
||||
textAlign: 'center',
|
||||
justifyContent: 'center',
|
||||
root: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
},
|
||||
text: {
|
||||
fontSize: '1.2em',
|
||||
fontWeight: '600',
|
||||
paddingRight: theme.spacing(2),
|
||||
paddingBottom: theme.spacing(3),
|
||||
'& span': {
|
||||
color: theme.palette.primary.main
|
||||
},
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
width: '25%',
|
||||
paddingBottom: 0,
|
||||
},
|
||||
},
|
||||
textField: {
|
||||
textAlign: 'center',
|
||||
justifyContent: 'center',
|
||||
margin: 0,
|
||||
'& input': {
|
||||
backgroundColor: theme.palette.background.grey,
|
||||
minWidth: '65vw',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
minWidth: 'inherit',
|
||||
},
|
||||
}
|
||||
},
|
||||
button: {
|
||||
padding: theme.spacing(2, 0),
|
||||
borderBottomLeftRadius: 0,
|
||||
borderTopLeftRadius: 0,
|
||||
boxShadown: '0px',
|
||||
backgroundColor: theme.palette.primary.dark,
|
||||
},
|
||||
sendIcon: {
|
||||
fill: theme.palette.background.grey,
|
||||
},
|
||||
newsletterForm: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: theme.palette.background.grey,
|
||||
margin: theme.spacing(0, 4),
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
width: 'max-content',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
class NewsLetterRegistration extends Component {
|
||||
state = {
|
||||
data: {
|
||||
email: "",
|
||||
},
|
||||
success: false,
|
||||
errors: { message: "" },
|
||||
loading: false,
|
||||
tabIndex: 0,
|
||||
openSnack: false
|
||||
};
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
|
||||
this.setState({
|
||||
errors: !!!nextProps.errors ? { errors: { message: "" } } : nextProps.errors,
|
||||
loading: nextProps.loading,
|
||||
success: nextProps.success,
|
||||
openSnack: !_.isEmpty(nextProps.errors) || nextProps.success
|
||||
})
|
||||
}
|
||||
|
||||
onChange = e =>
|
||||
this.setState({
|
||||
data: { ...this.state.data, [e.target.name]: e.target.value }
|
||||
});
|
||||
|
||||
onSubmit = e => {
|
||||
e.preventDefault();
|
||||
const errors = this.validate(this.state.data);
|
||||
this.setState({ errors });
|
||||
if (Object.keys(errors).length === 0) {
|
||||
this.props.subscribeToNewsletterRequest(this.state.data)
|
||||
}
|
||||
};
|
||||
|
||||
submit = data => { this.props.login(data) }
|
||||
|
||||
validate = data => {
|
||||
const errors = {};
|
||||
if (!Validator.isEmail(data.email)) errors.email = "Invalid email";
|
||||
return errors;
|
||||
};
|
||||
|
||||
handleClose = e =>
|
||||
this.setState({
|
||||
openSnack: false
|
||||
});
|
||||
|
||||
render() {
|
||||
let {classes} = this.props
|
||||
const { classes } = this.props;
|
||||
const { data, success, errors, loading, openSnack } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Typography gutterBottom component="h3">
|
||||
Recevez les dernières nouvelles de Talents Tube par e-mail
|
||||
<section className={classes.root}>
|
||||
<Typography
|
||||
gutterBottom
|
||||
component="h3"
|
||||
className={classes.text}
|
||||
>
|
||||
Recevez les dernières nouvelles de <span>Talents Tube</span> par e-mail
|
||||
</Typography>
|
||||
<TextField
|
||||
id="outlined-bare"
|
||||
className={classes.textField}
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
inputProps={{ 'aria-label': 'bare' }}
|
||||
/>
|
||||
<Button variant="outlined" onClick={() => alert("Salut, tu veux faire un tuto ?")}>Ok</Button>
|
||||
</div>
|
||||
<form className={classes.newsletterForm} onSubmit={this.onSubmit}>
|
||||
<TextField
|
||||
id="outlined-with-placeholder"
|
||||
disabled={loading}
|
||||
label="Newsletter"
|
||||
name="email"
|
||||
value={data.email}
|
||||
onChange={this.onChange}
|
||||
type="email"
|
||||
placeholder="exemple@gmail.com"
|
||||
className={classes.textField}
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
margin="dense"
|
||||
variant="filled"
|
||||
/>
|
||||
<Button type="submit"
|
||||
name="registerToNewsletter"
|
||||
disabled={loading}
|
||||
variant="contained"
|
||||
className={classes.button}
|
||||
>
|
||||
<SendIcon className={classes.sendIcon}/>
|
||||
</Button >
|
||||
</form>
|
||||
<Snack name={success ? 'snackSuccess' : 'snackWarning'}
|
||||
variant={success ? 'success' : 'warning'}
|
||||
message={success ? 'Inscription validée.' : errors.message}
|
||||
openSnack={openSnack}
|
||||
onClose={this.handleClose} />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(NewsLetterRegistration)
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
openSnack: !_.isEmpty(ownProps.errors),
|
||||
loading: !!state.user.loading,
|
||||
success: state.user.NewsLetterRegistrationSuccess,
|
||||
errors: state.user.errors || ownProps.errors
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default (connect(mapStateToProps, { subscribeToNewsletterRequest })(withStyles(styles)(NewsLetterRegistration)));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,83 +1,113 @@
|
||||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import Router from 'next/router'
|
||||
import getConfig from 'next/config'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
import CardHeader from '@material-ui/core/CardHeader';
|
||||
import CardMedia from '@material-ui/core/CardMedia';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
import IconText from './../atoms/IconText';
|
||||
import KeyboardArrowleftIcon from '@material-ui/icons/PlayArrowRounded';
|
||||
import Link from 'next/link';
|
||||
import _ from 'lodash';
|
||||
|
||||
const styles = theme => ({
|
||||
card: {
|
||||
display: 'flex',
|
||||
position: 'relative',
|
||||
height: '50vh',
|
||||
minHeight: '21vh',
|
||||
// maxHeight: '32vh',
|
||||
borderRadius: '5px',
|
||||
width: '100%',
|
||||
|
||||
cursor: 'pointer',
|
||||
boxShadow: '0px 2px 4px rgba(30, 35, 39, 0.15)',
|
||||
transform: 'translateY(-0px)',
|
||||
transition: 'transform 0.25s, box-shadow ease-out',
|
||||
|
||||
'&:hover': {
|
||||
boxShadow: '0px 6px 16px rgba(30, 35, 39, 0.15)',
|
||||
transform: 'translateY(-5px)',
|
||||
transition: 'transform 0.5s, box-shadow 2s',
|
||||
'& .cardHover': {
|
||||
backgroundColor: 'rgba(0,0,0,0)',
|
||||
},
|
||||
},
|
||||
'& > div': {
|
||||
padding: '0 !important',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width : '30%',
|
||||
minHeight: '15vh',
|
||||
// maxHeight: '20vh',
|
||||
},
|
||||
[theme.breakpoints.down('md')]: {
|
||||
width : '40%',
|
||||
},
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
width : '100%',
|
||||
},
|
||||
|
||||
margin: '1vh 2vh 1vh 2vh',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
margin: '1vh 0 1vh 0',
|
||||
margin: '2vh 0 2vh 0',
|
||||
},
|
||||
borderRadius: 0
|
||||
},
|
||||
details_container: {
|
||||
detailsContainer: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
padding: '10vh 0 0 0',
|
||||
alignItems: 'flex-start',
|
||||
padding: theme.spacing(2),
|
||||
width: '75%',
|
||||
// minHeight: '200px',
|
||||
},
|
||||
company_title: {
|
||||
fontSize: '1em',
|
||||
fontWeight: 'normal',
|
||||
textTransform: 'uppercase',
|
||||
jobTitle: {
|
||||
fontSize: '1.2em',
|
||||
fontWeight: 'bold',
|
||||
color: theme.palette.offerlistitem.title,
|
||||
},
|
||||
companyTitle: {
|
||||
fontSize: '1.2em',
|
||||
fontWeight: '300',
|
||||
color: theme.palette.offerlistitem.title,
|
||||
},
|
||||
content: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
flexWrap: 'wrap',
|
||||
width: '100%',
|
||||
padding: 0,
|
||||
},
|
||||
cover: {
|
||||
width: '100%',
|
||||
height: '50%',
|
||||
position: 'relative',
|
||||
width: '125px',
|
||||
height: '100%',
|
||||
backgroundPosition: 'center',
|
||||
backgroundSize: 'cover',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundBlendMode: 'darken',
|
||||
backgroundColor: 'rgba(30,35,39,0.25)',
|
||||
transition: 'background-color 1s',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: '35%',
|
||||
},
|
||||
},
|
||||
logo_container: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: 100,
|
||||
height: 100,
|
||||
|
||||
iconPlay: {
|
||||
fontSize: '2em',
|
||||
color: theme.palette.background.grey,
|
||||
position: 'absolute',
|
||||
left: '50%',
|
||||
top: '50%',
|
||||
transform: 'translate(-50%, -66%)',
|
||||
backgroundColor: 'white',
|
||||
boxShadow: '0 8px 6px -6px grey',
|
||||
top: 'calc(50% - 0.5em)',
|
||||
left: 'calc(50% - 0.5em)',
|
||||
},
|
||||
logo: {
|
||||
width: '100%',
|
||||
height: 'auto',
|
||||
objectfit: 'contain',
|
||||
borderRadius: 0,
|
||||
iconText: {
|
||||
marginLeft: 0,
|
||||
justifyContent: 'flex-start',
|
||||
},
|
||||
iconTextIcon: {
|
||||
color: theme.palette.offerlistitem.icon,
|
||||
fontSize: '1.2em',
|
||||
},
|
||||
iconTextText: {
|
||||
color: theme.palette.offerlistitem.text,
|
||||
fontSize: '1em',
|
||||
paddingLeft: theme.spacing(1),
|
||||
},
|
||||
chip: {
|
||||
color: theme.palette.secondary.main,
|
||||
backgroundColor: theme.palette.secondary.important,
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -86,51 +116,63 @@ class OffreRowComponent extends React.Component {
|
||||
|
||||
render() {
|
||||
|
||||
const { classes, rowData } = this.props;
|
||||
const { classes, rowData, company } = this.props;
|
||||
|
||||
let companyR = company
|
||||
if (!!!company)
|
||||
companyR = rowData.company;
|
||||
else
|
||||
companyR = company;
|
||||
|
||||
const imgUrl = (rowData.video && rowData.video.thumbnails && rowData.video.thumbnails[0] && rowData.video.thumbnails[0].sizes[4]) ? rowData.video.thumbnails[0].sizes[4].link : publicRuntimeConfig.adListDefaultUrl
|
||||
|
||||
const imgUrl = (rowData.video.thumbnails[0] && rowData.video.thumbnails[0].sizes[4]) ? rowData.video.thumbnails[0].sizes[4].link : publicRuntimeConfig.adListDefaultUrl
|
||||
const logoUrl = publicRuntimeConfig.logoRootUrl + rowData.company.logo
|
||||
//rowData._embedded.company.business_name
|
||||
return (
|
||||
<Link href={`/Offre/${rowData.id}-${_.kebabCase(rowData.title)}`} >
|
||||
<Card className={classes.card + ' cypCardOffre'} >
|
||||
<CardContent className={classes.content}>
|
||||
<CardMedia
|
||||
className={ classes.cover + ' cardHover'}
|
||||
image={imgUrl}
|
||||
title={rowData.title}
|
||||
>
|
||||
<KeyboardArrowleftIcon className={classes.iconPlay} />
|
||||
</CardMedia>
|
||||
|
||||
<Card className={classes.card} onClick={() => Router.push(`/Offre?id=${rowData.id}`)}>
|
||||
<CardContent className={classes.content}>
|
||||
<CardMedia
|
||||
className={classes.cover}
|
||||
image={imgUrl}
|
||||
title={rowData.title}
|
||||
/>
|
||||
<div className={classes.detailsContainer}>
|
||||
<Typography
|
||||
gutterBottom
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h3"
|
||||
className={classes.jobTitle}>
|
||||
{rowData.title}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h3"
|
||||
className={classes.companyTitle}>
|
||||
{companyR.brand_name ? companyR.brand_name : "Non renseigné"}
|
||||
</Typography>
|
||||
<div>
|
||||
{rowData.is_promoted && (
|
||||
<Chip label="Offre pourvue" className={classes.chip} />
|
||||
)}
|
||||
|
||||
<div className={classes.logo_container}>
|
||||
<Avatar className={classes.logo} src={logoUrl} />
|
||||
</div>
|
||||
{!rowData.is_promoted && (
|
||||
<Fragment>
|
||||
<IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="business_center" text={rowData.extra.contract_type} />
|
||||
<IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="location_on" text={rowData.location.gmap_address.formatted_address} />
|
||||
{rowData.beneficiaire ? <IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="business" text={rowData.beneficiaire} /> : ""}
|
||||
|
||||
</Fragment>
|
||||
)}
|
||||
|
||||
<div className={classes.details_container}>
|
||||
<Typography
|
||||
gutterBottom
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h3"
|
||||
align="center"
|
||||
className={classes.company_title}>
|
||||
{rowData.company.business_name}
|
||||
</Typography>
|
||||
<Typography
|
||||
gutterBottom
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h4"
|
||||
align="center"
|
||||
className={classes.job_title}>
|
||||
{rowData.title}
|
||||
</Typography>
|
||||
</div>
|
||||
<div>
|
||||
<Chip label={rowData.extra.contract_type} className={classes.chip} />
|
||||
<Chip label={rowData.location.gmap_address.address_components[0].long_name} className={classes.chip} />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,85 +8,124 @@ import CardMedia from '@material-ui/core/CardMedia';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Snackbar from '@material-ui/core/Snackbar';
|
||||
import Collapse from '@material-ui/core/Collapse';
|
||||
|
||||
const styles = theme => ({
|
||||
Snackbar: {
|
||||
zIndex: 10001,
|
||||
},
|
||||
cardSnack: {
|
||||
maxWidth: 345,
|
||||
},
|
||||
media: {
|
||||
height: 140,
|
||||
}
|
||||
},
|
||||
askToInstallText: {
|
||||
fontSize: '1.4em',
|
||||
fontWeight: '600',
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
},
|
||||
installApp: {
|
||||
width: '100%',
|
||||
},
|
||||
installStepText: {
|
||||
fontSize: '1.2em',
|
||||
fontWeight: '500',
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
button: {
|
||||
color: theme.palette.primary.main,
|
||||
borderColor: theme.palette.primary.main,
|
||||
width: '50%',
|
||||
},
|
||||
buttonCompris: {
|
||||
width: '100%',
|
||||
},
|
||||
});
|
||||
|
||||
class PWAInstallSnack extends Component {
|
||||
state = {
|
||||
openSnack: false,
|
||||
buttonDisplay: true
|
||||
buttonDisplay: false
|
||||
}
|
||||
|
||||
isAvailable = () =>{
|
||||
console.log(this.buttonDisplay)
|
||||
isAvailable = () => {
|
||||
return this.state.buttonDisplay;
|
||||
}
|
||||
|
||||
initInstall = () =>
|
||||
{
|
||||
this.setState({openSnack: true})
|
||||
initInstall = () => {
|
||||
this.setState({ openSnack: true })
|
||||
}
|
||||
getStateAndHelpers() {
|
||||
return {
|
||||
on: this.state.openSnack,
|
||||
initInstall: this.initInstall,
|
||||
on: this.state.openSnack,
|
||||
initInstall: this.initInstall,
|
||||
}
|
||||
}
|
||||
}
|
||||
iOS() {
|
||||
|
||||
var iDevices = [
|
||||
'iPad Simulator',
|
||||
'iPhone Simulator',
|
||||
'iPod Simulator',
|
||||
'iPad',
|
||||
'iPhone',
|
||||
'iPod'
|
||||
'iPad Simulator',
|
||||
'iPhone Simulator',
|
||||
'iPod Simulator',
|
||||
'iPad',
|
||||
'iPhone',
|
||||
'iPod'
|
||||
];
|
||||
|
||||
|
||||
if (!!navigator.platform) {
|
||||
while (iDevices.length) {
|
||||
if (navigator.platform === iDevices.pop()){ return true; }
|
||||
}
|
||||
while (iDevices.length) {
|
||||
if (navigator.platform === iDevices.pop()) { return true; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
BeforePromptInstallTrigger() {
|
||||
this.setState({ buttonDisplay: true })
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (window !== undefined) {
|
||||
window.addEventListener('beforeinstallprompt', () => {
|
||||
this.BeforePromptInstallTrigger()
|
||||
})
|
||||
|
||||
if (!!window.deferredPrompt)
|
||||
this.setState({ buttonDisplay: true });
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
// don't show if we are in App
|
||||
if (window.navigator.standalone ||
|
||||
window.matchMedia('(display-mode: standalone)').matches)
|
||||
{
|
||||
console.log('standalone')
|
||||
this.setState({ openSnack: false, buttonDisplay: false })
|
||||
window.matchMedia('(display-mode: standalone)').matches) {
|
||||
this.setState({ openSnack: false, buttonDisplay: false })
|
||||
}
|
||||
else if(this.IsSafari())
|
||||
{
|
||||
console.log('safari')
|
||||
this.setState({ openSnack: false, buttonDisplay: false })
|
||||
// else if (window.deferredPrompt === null) {
|
||||
// this.setState({ openSnack: false, buttonDisplay: false })
|
||||
// }
|
||||
else if (this.IsSafari()) {
|
||||
this.setState({ openSnack: false, buttonDisplay: false })
|
||||
|
||||
if(this.iOS())
|
||||
this.setState({ openSnack: false, buttonDisplay: true })
|
||||
|
||||
if (this.iOS())
|
||||
{
|
||||
this.setState({ openSnack: false, buttonDisplay: true })}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
||||
window.removeEventListener('beforeinstallprompt', () => {
|
||||
this.BeforePromptInstallTrigger()
|
||||
})
|
||||
}
|
||||
|
||||
//A2HS 'Add 2 Home Screen'
|
||||
PromptA2HS = (event, reason) => {
|
||||
|
||||
this.setState({ openSnack: false })
|
||||
console.log('prompted')
|
||||
if (window !== undefined) {
|
||||
if (typeof window !== 'undefined') {
|
||||
window.promptInstall();
|
||||
}
|
||||
}
|
||||
@@ -105,38 +144,40 @@ class PWAInstallSnack extends Component {
|
||||
const { classes } = this.props;
|
||||
var safariSnack = (<Card className={classes.cardSnack}>
|
||||
<CardActionArea>
|
||||
<CardMedia
|
||||
className={classes.media}
|
||||
image="/static/images/help/addToHomeFull.png"
|
||||
title="homeScreen"
|
||||
/>
|
||||
<CardContent>
|
||||
<Typography gutterBottom variant="h5" component="h2">
|
||||
-> les PWA doivent encore s'installer manuellement sous IOS
|
||||
<Typography gutterBottom component="h2">
|
||||
Suivez les instructions ci -dessous :
|
||||
</Typography>
|
||||
<Typography gutterBottom align="center" component="h2" className={ classes.installStepText }>
|
||||
Etape 1 :
|
||||
</Typography>
|
||||
<img alt="installer-pwa" src='/static/images/help/safari-actions.png' className={classes.installApp} />
|
||||
<Typography gutterBottom align="center" component="h2" className={ classes.installStepText }>
|
||||
Etape 2 :
|
||||
</Typography>
|
||||
<img alt="installer-pwa" src='/static/images/help/safari-install-app.png' className={classes.installApp} />
|
||||
</CardContent>
|
||||
<CardActions>
|
||||
<Button name="compris" size="small" color="secondary" onClick={this.handleClose}>
|
||||
j'ai compris
|
||||
<Button name="compris" className={classes.buttonCompris} color="primary" onClick={this.handleClose}>
|
||||
j'ai compris
|
||||
</Button>
|
||||
</CardActions>
|
||||
</CardActions>
|
||||
</CardActionArea>
|
||||
|
||||
</Card>);
|
||||
|
||||
var usualSnack = (<Card className={classes.cardSnack}>
|
||||
<CardActionArea>
|
||||
<CardContent>
|
||||
<Typography gutterBottom variant="h5" component="h2">
|
||||
<Typography gutterBottom component="h2" className={ classes.askToInstallText }>
|
||||
Voulez-vous installer notre application ?
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</CardActionArea>
|
||||
<CardActions>
|
||||
<Button name='oui' size="small" color="secondary" onClick={this.PromptA2HS}>
|
||||
<Button className={classes.button} color="primary" name='oui' size="small" onClick={this.PromptA2HS}>
|
||||
oui
|
||||
</Button>
|
||||
<Button name='non' size="small" color="secondary" onClick={this.handleClose}>
|
||||
<Button className={classes.button} color="primary" name='non' size="small" onClick={this.handleClose}>
|
||||
non
|
||||
</Button>
|
||||
</CardActions>
|
||||
@@ -144,8 +185,9 @@ class PWAInstallSnack extends Component {
|
||||
|
||||
|
||||
|
||||
return <Fragment>
|
||||
return <Fragment>
|
||||
<Snackbar
|
||||
className={ classes.Snackbar }
|
||||
anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
|
||||
open={this.state.openSnack}
|
||||
onClose={this.handleClose}
|
||||
@@ -154,9 +196,11 @@ class PWAInstallSnack extends Component {
|
||||
}}>
|
||||
{this.IsSafari() ? safariSnack : usualSnack}
|
||||
</Snackbar>
|
||||
{this.state.buttonDisplay && this.props.children(this.getStateAndHelpers())}
|
||||
</Fragment>
|
||||
|
||||
<Collapse in={this.state.buttonDisplay}>
|
||||
{this.state.buttonDisplay && this.props.children(this.getStateAndHelpers())}
|
||||
</Collapse>
|
||||
</Fragment>
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ import dynamic from 'next/dynamic'
|
||||
import Button from '@material-ui/core/Button';
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import axios from 'axios'
|
||||
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||
import setAuthorizationHeader from "../../data/setAuthorizationHeader";
|
||||
import 'videojs/dist/video-js.css';
|
||||
import 'videojs-record/dist/css/videojs.record.css';
|
||||
import ArrowRight from '@material-ui/icons/ArrowRight';
|
||||
|
||||
dynamic(() => import('webrtc-adapter'), {
|
||||
ssr: false
|
||||
@@ -16,41 +16,208 @@ const RTCRecorder = dynamic(() => import('RecordRTC'), {
|
||||
ssr: false
|
||||
})
|
||||
|
||||
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
margin: theme.spacing.unit,
|
||||
maxWidth: '400px', [theme.breakpoints.down('md')]: {
|
||||
maxWidth: `${100 - (theme.spacing.unit)}vw`
|
||||
const videoJsOptions = {
|
||||
controls: true,
|
||||
width: '550',
|
||||
languages: {
|
||||
fr: {
|
||||
|
||||
Replay: 'Jouer'
|
||||
}
|
||||
},
|
||||
autoplay:true,
|
||||
preload:"auto",
|
||||
playsinline : false,
|
||||
//videoEngine: 'webm-wasm',
|
||||
//liveui : true,
|
||||
fluid: true,
|
||||
nativeControlsForTouch:false,
|
||||
controlBar: {
|
||||
// hide fullscreen and volume controls
|
||||
fullscreenToggle: false,
|
||||
volumePanel: false,
|
||||
deviceButton: false,
|
||||
recordIndicator:true,
|
||||
recordToggle: false,
|
||||
PictureInPictureToggle:false,
|
||||
PlayToggle:false
|
||||
},
|
||||
poster: '/statique/images/webrtc/module-video-talents-tube.svg',
|
||||
plugins: {
|
||||
/*
|
||||
// wavesurfer section is only needed when recording audio-only
|
||||
wavesurfer: {
|
||||
src: 'live',
|
||||
waveColor: '#36393b',
|
||||
progressColor: 'black',
|
||||
debug: true,
|
||||
cursorWidth: 1,
|
||||
msDisplayMax: 20,
|
||||
hideScrollbar: true
|
||||
},
|
||||
*/
|
||||
record: {
|
||||
audio: true,
|
||||
video: true,
|
||||
maxLength: 600,
|
||||
//debug: true
|
||||
}
|
||||
}
|
||||
};
|
||||
const styles = theme => ({
|
||||
primary: {
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
root: {
|
||||
position: 'relative',
|
||||
textAlign: 'center',
|
||||
paddingTop: theme.spacing(10),
|
||||
justifyContent: 'center',
|
||||
},
|
||||
button: {
|
||||
|
||||
margin: theme.spacing.unit,
|
||||
alignSelf: 'flex-end'
|
||||
color: '#FFFFFF',
|
||||
padding: '9.6px 16px',
|
||||
borderColor: '#25D89A',
|
||||
border: '2px solid',
|
||||
margin:'15px 8px 25px 8px',
|
||||
textTransform: 'inherit',
|
||||
backgroundColor:'#25D89A',
|
||||
},
|
||||
}
|
||||
})
|
||||
buttonRelancer:{
|
||||
color: '#1E2327',
|
||||
borderColor: '#1E2327',
|
||||
border: '2px solid',
|
||||
margin: '15px 8px 25px 8px',
|
||||
padding: '9.6px 16px',
|
||||
textTransform: 'inherit',
|
||||
color: '#1E2327',
|
||||
borderColor: '#1E2327',
|
||||
|
||||
},
|
||||
|
||||
buttonArret: {
|
||||
color: '#FFFFFF',
|
||||
borderColor: '#FF5A5F',
|
||||
border: '2px solid',
|
||||
padding: '9.6px 16px',
|
||||
margin:'15px 8px 25px 8px',
|
||||
textTransform: 'inherit',
|
||||
backgroundColor:'#FF5A5F',
|
||||
},
|
||||
buttonLire: {
|
||||
color: '#FFFFFF',
|
||||
padding: '9.6px 16px',
|
||||
margin:'15px 8px 25px 8px',
|
||||
textTransform: 'inherit',
|
||||
backgroundColor:'#1689FB',
|
||||
},
|
||||
conteneurVideo:{
|
||||
width:'550px!important'
|
||||
},
|
||||
sendContainer: {
|
||||
left: '-40px'
|
||||
},
|
||||
|
||||
|
||||
})
|
||||
|
||||
// const styles = theme => ({
|
||||
// root: {
|
||||
// margin: theme.spacing(1),
|
||||
// maxWidth: '400px', [theme.breakpoints.down('md')]: {
|
||||
// maxWidth: `${100 - (theme.spacing(1))}vw`
|
||||
// },
|
||||
// sendContainer: {
|
||||
// textAlign: 'center'
|
||||
// },
|
||||
// bouton: {
|
||||
// textTransform: 'inherit',
|
||||
// marginLeft: theme.spacing(1),
|
||||
// marginRight: theme.spacing(1),
|
||||
// padding: theme.spacing(1.2, 2),
|
||||
// color: theme.palette.secondary.main,
|
||||
// backgroundColor: theme.palette.primary.important,
|
||||
// },
|
||||
// conteneurVideo:{
|
||||
// width:'550px!important'
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
class Recorder extends Component {
|
||||
|
||||
state={
|
||||
canSend:false,
|
||||
isActiveLancer:true,
|
||||
isActiveArreter:false,
|
||||
isActiveLancerReplay:false,
|
||||
lancerText:"Démarrer l’enregistrement",
|
||||
lancerStyleRelance : 0,
|
||||
}
|
||||
|
||||
handleLancer = (replay)=>{
|
||||
this.setState({
|
||||
isActiveLancer: !this.state.isActiveLancer,
|
||||
isActiveArreter: !this.state.isActiveArreter,
|
||||
lancerText : "Refaire une vidéo",
|
||||
})
|
||||
replay==1 ? this.setState({isActiveLancerReplay: 1}) : this.setState({isActiveLancerReplay: 0})
|
||||
this.setState({lancerStyleRelance: 1})
|
||||
}
|
||||
|
||||
|
||||
async componentDidMount() {
|
||||
var record = (await import('videojs-record')).default
|
||||
// instantiate Video.js
|
||||
this.player = videojs(this.videoNode, this.props, () => {
|
||||
this.player = videojs(this.videoNode, videoJsOptions, () => {
|
||||
// print version information at startup
|
||||
var version_info = 'Using video.js ' + videojs.VERSION +
|
||||
' with videojs-record ' + videojs.getPluginVersion('record') +
|
||||
' and recordrtc ' + RTCRecorder.VERSION;
|
||||
videojs.log(version_info);
|
||||
});
|
||||
var vid= this.player;
|
||||
this.player.bigPlayButton.hide();
|
||||
|
||||
|
||||
// When you pass text in options it just creates a control text,
|
||||
// which is displayed as tooltip when hovered on
|
||||
// this button viz the span in you div,
|
||||
var myButton = this.player.controlBar.addChild("button");
|
||||
|
||||
|
||||
|
||||
// There are many functions available for button component
|
||||
// like below mentioned in this docs
|
||||
// https://docs.videojs.com/button.
|
||||
// You can set attributes and clasess as well.
|
||||
|
||||
// Getting html DOM
|
||||
var myButtonDom = myButton.el();
|
||||
//var myButtonDom2 = myButton2.el();
|
||||
// Since now you have the html dom element
|
||||
// you can add click events
|
||||
|
||||
|
||||
// Now I am setting the text as you needed.
|
||||
// myButtonDom.innerHTML = "Youi";
|
||||
|
||||
myButtonDom.onclick = function(){
|
||||
//alert("Redirecting");
|
||||
vid.pause();
|
||||
}
|
||||
|
||||
|
||||
// device is ready
|
||||
this.player.on('deviceReady', () => {
|
||||
console.log('device is ready!');
|
||||
console.info('device is ready!');
|
||||
this.player.record().start();
|
||||
this.setState({canSend:false});
|
||||
});
|
||||
|
||||
// user clicked the record button and started recording
|
||||
this.player.on('startRecord', () => {
|
||||
console.log('started recording!');
|
||||
this.setState({canSend:false});
|
||||
});
|
||||
|
||||
// user completed recording and stream is available
|
||||
@@ -58,19 +225,22 @@ class Recorder extends Component {
|
||||
// recordedData is a blob object containing the recorded data that
|
||||
// can be downloaded by the user, stored on server etc.
|
||||
console.log('finished recording: ', this.player.recordedData);
|
||||
this.setState({canSend:true});
|
||||
});
|
||||
|
||||
// error handling
|
||||
this.player.on('error', (element, error) => {
|
||||
console.warn(error);
|
||||
this.setState({canSend:false});
|
||||
});
|
||||
|
||||
this.player.on('deviceError', () => {
|
||||
console.error('device error:', this.player.deviceErrorCode);
|
||||
this.setState({canSend:false});
|
||||
});
|
||||
}
|
||||
|
||||
// destroy player on unmount
|
||||
//destroy player on unmount
|
||||
componentWillUnmount() {
|
||||
if (this.player) {
|
||||
this.player.dispose();
|
||||
@@ -78,39 +248,76 @@ class Recorder extends Component {
|
||||
}
|
||||
|
||||
sendBlob = () => {
|
||||
console.log('accessing recording: ', this.player.recordedData)
|
||||
// console.log('accessing recording: ', this.player.recordedData)
|
||||
var formData = new FormData();
|
||||
formData.append('upload', this.player.recordedData, "myupload");
|
||||
// formData.append('user', 7);//TODO: taking from auth
|
||||
|
||||
setAuthorizationHeader('eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE1NTk4OTE4ODIsImV4cCI6MTU1OTg5NTQ4Miwicm9sZXMiOlsiUk9MRV9UQUxFTlQiLCJST0xFX1VTRVIiXSwidXNlcm5hbWUiOiJ0aG9tYXMuYmVycm9kQGUtZGVjbGljLmNvbSJ9.dnXiifet5SIyZf1zOBnu6RvVqA6k-aT16O_YNy6ZAhRZUuQtqP21enNkug0KxLEFMy91gcj0gkGuETqMwcHBL_xkx7rJvb2dLoOo0yduZxJLzngWKroCZE152t-V5Edn2Gje3CHMGqTZLwjBowEgUTpgfyTE9IaJn-q2pizukWBzjmfmdz5mYFgoIQrsjThkPxRH8cNOTit0bj6SebjsCCsPb_jdM6rek03qtwELz2ABJaHJU1FiGGTLYtcF3k32AGlRwa5P9etKwQUrz0AL5q3lroKgbtwhxY3cKyRKAo-o68s3v12_T6R86WqEegOx6TyBb06GJhTcP1MIGBMMgNIm5GxSi0U0RvRDmLuFtsuZv5wBUZqkpth8Z_dK5H003k67XjLrYC4TnMhQXxUGV6Eji3lkCY5fOWbQjwXRO9R_rPCNSiPEZj0o_-ach0a4Y5nLhzVlnb3J0plpb4lwpN3D9t9FNfizKQ5VX9eLoozrzkI-apIbV-Z0is8i6j4yt7R24PR9dyreQXZ3-e_tEwu5UTKi-zYAaHaHrRgCSjWg4d6ozuyXQmzi64d1-Fnx6IkU_KtXtUYRVsZhQUvJpri2x1szLLM-Hqdsh2Ljuu5qDdJrHRKeG1gZeKWPfvZweZ3SWrfvlNZHKNWX-2pmEvz9sJdpsAO-NnmTEUVrpzY')
|
||||
|
||||
axios.post("http://localhost/app_dev.php/api/media",
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': `multipart/form-data;`
|
||||
},
|
||||
withCredentials: true
|
||||
})
|
||||
.then(res => console.log(res)).catch(err => console.log(err))
|
||||
|
||||
console.log('end send Blob')
|
||||
this.props.uploader(formData);
|
||||
}
|
||||
|
||||
recordPlayer = () => {
|
||||
// console.log('accessing recording: ', this.player.recordedData)
|
||||
if (this.player) {
|
||||
//this.player.recorder.start()
|
||||
this.player.ready();
|
||||
this.player.record().getDevice();
|
||||
this.handleLancer(0);
|
||||
}
|
||||
}
|
||||
|
||||
playPlayerAuto = () => {
|
||||
// console.log('accessing recording: ', this.player.recordedData)
|
||||
if (this.player) {
|
||||
//this.player.recorder.start()
|
||||
this.player.autoplay('play');
|
||||
|
||||
}
|
||||
}
|
||||
pausePlayerAuto = () => {
|
||||
// console.log('accessing recording: ', this.player.recordedData)
|
||||
if (this.player) {
|
||||
//this.player.recorder.start()
|
||||
this.player.autoplay('pause');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
arretPlayer = () => {
|
||||
// console.log('accessing recording: ', this.player.recordedData)
|
||||
if (this.player) {
|
||||
this.player.record().stop();
|
||||
this.handleLancer(1);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
const { classes, titreBouton } = this.props;
|
||||
let titreButtonLabel= "Choisir cette vidéo";
|
||||
|
||||
|
||||
if (titreBouton) {
|
||||
titreButtonLabel = titreBouton;
|
||||
console.log("titre");
|
||||
console.log(titreButtonLabel);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<div className={classes.conteneurVideo}>
|
||||
<div data-vjs-player>
|
||||
<video id="myVideo" ref={node => this.videoNode = node} className="video-js vjs-default-skin" playsInline></video>
|
||||
<video id="myVideo" width='550' ref={node => this.videoNode = node} className="video-js vjs-default-skin" playsInline></video>
|
||||
</div>
|
||||
<div>
|
||||
<Button type="submit" variant="outlined" color="secondary"
|
||||
<div className={classes.sendContainer}>
|
||||
|
||||
{this.state.isActiveLancer ? <Button className={this.state.lancerStyleRelance==1 ? classes.buttonRelancer: classes.button} onClick={this.recordPlayer}>{this.state.lancerText}</Button> : null }
|
||||
{this.state.isActiveArreter ?<Button className={classes.buttonArret} onClick={this.arretPlayer}>Arrêter l'enregistrement</Button> : null }
|
||||
{/* {this.state.isActiveLancerReplay ?<Button cyp="ButtonApply" variant="contained" className={classes.buttonLire} onClick={this.playPlayerAuto}><ArrowRight className={ classes.InputKeyboardArrowRightIcon }/>Relire</Button>: null } */}
|
||||
{ this.state.canSend && <Button type="submit" className={classes.button}
|
||||
className={classes.button}
|
||||
onClick={this.sendBlob}>
|
||||
Send
|
||||
</Button>
|
||||
{titreButtonLabel}
|
||||
</Button>}
|
||||
</div>
|
||||
<div id="controleNav">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,21 +1,29 @@
|
||||
import React, {Fragment} from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { connect } from "react-redux";
|
||||
import Validator from "validator";
|
||||
import {FormLabel, FormHelperText,InputLabel, Input,TextField, FormGroup, FormControlLabel, Checkbox, Button, Typography, Link } from '@material-ui/core';
|
||||
|
||||
import { TextField, FormControlLabel, Checkbox, Button, Typography, Link } from '@material-ui/core';
|
||||
import Visibility from '@material-ui/icons/Visibility';
|
||||
import VisibilityOff from '@material-ui/icons/VisibilityOff';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import InputAdornment from '@material-ui/core/InputAdornment';
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { registerUserRequest, subscribeToNewsletterRequest } from "../../actions/user"
|
||||
import SocialButtonsAuth from '../atoms/SocialButtonsAuth';
|
||||
import Snack from '../atoms/snack'
|
||||
|
||||
const styles = theme => ({
|
||||
container: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100%',
|
||||
paddingTop: theme.spacing(4),
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
padding: '5vw 10vw',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
padding: '5vw 25vw',
|
||||
},
|
||||
},
|
||||
textField: {
|
||||
width: '100%'
|
||||
@@ -24,13 +32,106 @@ const styles = theme => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
input50: {
|
||||
width: '50%',
|
||||
},
|
||||
checkboxError:{
|
||||
color:'red'
|
||||
}
|
||||
connexionRecruteur:{
|
||||
textAlign : "center",
|
||||
marginTop:"40px",
|
||||
backgroundColor:"#1E2327",
|
||||
padding:"30px 0",
|
||||
width:"100%",
|
||||
color:"#fff",
|
||||
fontSize: '1em',
|
||||
fontWeight: '300',
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
|
||||
},
|
||||
enSavoirPlus:{
|
||||
textAlign : "center",
|
||||
color:"#fff",
|
||||
fontSize: '1em',
|
||||
fontWeight: '600',
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
},
|
||||
formText: {
|
||||
padding: theme.spacing(0, 2),
|
||||
paddingTop: theme.spacing(3),
|
||||
fontSize: '0.9em',
|
||||
fontWeight: '300',
|
||||
},
|
||||
formLink: {
|
||||
paddingLeft: theme.spacing(1),
|
||||
fontWeight: '500',
|
||||
color: theme.palette.primary.dark,
|
||||
},
|
||||
checkbox: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
|
||||
'& .MuiFormControlLabel-label': {
|
||||
fontSize: '0.9em',
|
||||
fontWeight: '500',
|
||||
color: theme.palette.primary.dark,
|
||||
}
|
||||
},
|
||||
checkboxError: {
|
||||
'& .MuiFormControlLabel-label': {
|
||||
color: 'red'
|
||||
}
|
||||
},
|
||||
conditionalText: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
color: theme.palette.primary.conditional,
|
||||
textTransform: 'uppercase',
|
||||
|
||||
'&:before': {
|
||||
content: '""',
|
||||
flex: '1 1',
|
||||
borderBottom: '1px solid',
|
||||
borderColor: theme.palette.primary.conditional,
|
||||
marginRight: '10px',
|
||||
marginTop: 'auto',
|
||||
marginBottom: 'auto',
|
||||
},
|
||||
'&:after': {
|
||||
content: '""',
|
||||
flex: '1 1',
|
||||
borderBottom: '1px solid',
|
||||
borderColor: theme.palette.primary.conditional,
|
||||
marginLeft: '10px',
|
||||
marginTop: 'auto',
|
||||
marginBottom: 'auto',
|
||||
},
|
||||
},
|
||||
button: {
|
||||
textTransform: 'inherit',
|
||||
marginLeft: theme.spacing(10),
|
||||
marginRight: theme.spacing(10),
|
||||
marginTop: theme.spacing(4),
|
||||
marginBottom: theme.spacing(2),
|
||||
padding: theme.spacing(1.2, 1),
|
||||
borderRadius: '3px',
|
||||
color: theme.palette.secondary.main,
|
||||
backgroundColor: theme.palette.primary.important,
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
margin: 'auto',
|
||||
},
|
||||
},
|
||||
buttonImportant: {
|
||||
marginTop: theme.spacing(6),
|
||||
marginBottom: theme.spacing(2),
|
||||
},
|
||||
titre: {
|
||||
fontWeight: 600,
|
||||
fontSize: "1.875em",
|
||||
marginBottom:"20px",
|
||||
fontFamily: "Roboto",
|
||||
},
|
||||
cgu: {
|
||||
fontFamily: "Roboto",
|
||||
fontSize: "1em",
|
||||
fontWeight: "300",
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
class Register extends React.Component {
|
||||
@@ -38,14 +139,25 @@ class Register extends React.Component {
|
||||
data: {
|
||||
firstname: '',
|
||||
lastname: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
password: '',
|
||||
checkNewsletter: false,
|
||||
checkCGU: false,
|
||||
adId : ''
|
||||
},
|
||||
errors: {
|
||||
email:null,
|
||||
password:null,
|
||||
firstname:null,
|
||||
phone:null,
|
||||
lastname:null,
|
||||
phone:null,
|
||||
checkCGU:null
|
||||
},
|
||||
errors: {},
|
||||
loading: false,
|
||||
showPassword:false
|
||||
showPassword: false,
|
||||
passwordValid : false
|
||||
}
|
||||
|
||||
validate = data => {
|
||||
@@ -55,21 +167,29 @@ class Register extends React.Component {
|
||||
if (!!!data.firstname) errors.firstname = "Requis";
|
||||
if (!!!data.lastname) errors.lastname = "Requis";
|
||||
if (!data.checkCGU) errors.checkCGU = "Requis";
|
||||
|
||||
|
||||
if(data.password.length <8){
|
||||
errors.password = "Too short";
|
||||
}
|
||||
|
||||
return errors;
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({
|
||||
data: {...this.state.data, adId: localStorage.getItem('adId')},
|
||||
})
|
||||
}
|
||||
|
||||
onRegister = e => {
|
||||
e.preventDefault();
|
||||
const errors = this.validate(this.state.data);
|
||||
console.log('onSubmit')
|
||||
console.log(errors)
|
||||
let errors = this.validate(this.state.data);
|
||||
this.setState({ errors: errors });
|
||||
|
||||
// console.log('adId')
|
||||
// console.log(this.state.data)
|
||||
if (Object.keys(errors).length === 0) {
|
||||
this.setState({ loading: true });
|
||||
|
||||
this.props.registerUserRequest(this.state.data)
|
||||
console.log(this.props.registerUserRequest(this.state.data))
|
||||
|
||||
if (this.state.data.checkNewsletter)
|
||||
this.props.subscribeToNewsletterRequest({ email: this.state.data.email })
|
||||
@@ -77,18 +197,20 @@ class Register extends React.Component {
|
||||
|
||||
};
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
this.setState({
|
||||
errors: nextProps.errors,
|
||||
loading: nextProps.loading
|
||||
})
|
||||
}
|
||||
onChange = e =>
|
||||
onChange = e => {
|
||||
|
||||
this.setState({
|
||||
data: { ...this.state.data, [e.target.name]: e.target.value }
|
||||
});
|
||||
}
|
||||
handleCheckBoxChange = name => event => {
|
||||
this.setState({data:{ ...this.state.data, [name]: event.target.checked }});
|
||||
this.setState({ data: { ...this.state.data, [name]: event.target.checked } });
|
||||
};
|
||||
|
||||
handleChangePasswordVisibility = prop => event => {
|
||||
@@ -100,40 +222,59 @@ class Register extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
const { classes, erreurs } = this.props;
|
||||
const { data, errors } = this.state;
|
||||
console.log('render errors');
|
||||
console.log(errors);
|
||||
console.log(this.state);
|
||||
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
|
||||
<form className={classes.form}>
|
||||
<FormGroup row>
|
||||
<TextField
|
||||
value={data.firstname}
|
||||
className={classes.input50}
|
||||
onChange={this.onChange}
|
||||
id="prenom"
|
||||
name="firstname"
|
||||
label="Prénom"
|
||||
margin="normal"
|
||||
required
|
||||
error={!!errors.firstname}
|
||||
/>
|
||||
<TextField
|
||||
value={data.lastname}
|
||||
className={classes.input50}
|
||||
onChange={this.onChange}
|
||||
id="nom"
|
||||
name="lastname"
|
||||
label="Nom"
|
||||
margin="normal"
|
||||
required
|
||||
error={!!errors.lastname}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<Typography
|
||||
className={classes.titre}
|
||||
align="left"
|
||||
>
|
||||
Inscription
|
||||
</Typography>
|
||||
<TextField
|
||||
value={data.firstname}
|
||||
onChange={this.onChange}
|
||||
id="prenom"
|
||||
name="firstname"
|
||||
label="Prénom"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
required
|
||||
error={!!errors.firstname}
|
||||
helperText={!!errors.firstname && "Veuillez saisir votre prénom."}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
className={classes.champ}
|
||||
value={data.lastname}
|
||||
onChange={this.onChange}
|
||||
id="nom"
|
||||
name="lastname"
|
||||
label="Nom"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
required
|
||||
error={!!errors.lastname}
|
||||
helperText={!!errors.lastname && "Veuillez saisir votre nom."}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
className={classes.champ}
|
||||
value={data.phone}
|
||||
onChange={this.onChange}
|
||||
id="telephone"
|
||||
name="phone"
|
||||
label="Téléphone"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
<TextField
|
||||
value={data.email}
|
||||
@@ -143,82 +284,105 @@ class Register extends React.Component {
|
||||
label="Email"
|
||||
margin="normal"
|
||||
type="email"
|
||||
variant="outlined"
|
||||
required
|
||||
error={!!errors.email}
|
||||
autoComplete="username email"
|
||||
error={!!errors.email || !!erreurs}
|
||||
helperText={!!errors.email ? "Saisissez une adresse e-mail valide." : !!erreurs && erreurs}
|
||||
/>
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="adornment-password">Password *</InputLabel>
|
||||
<Input
|
||||
name="password"
|
||||
id="adornment-password"
|
||||
type={this.state.showPassword ? 'text' : 'password'}
|
||||
value={this.state.password}
|
||||
onChange={this.onChange}
|
||||
endAdornment={
|
||||
|
||||
|
||||
<TextField
|
||||
className={clsx(classes.margin, classes.textField)}
|
||||
label="Mot de passe"
|
||||
name="password"
|
||||
id="adornment-password"
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
type={this.state.showPassword ? 'text' : 'password'}
|
||||
value={this.state.password}
|
||||
onChange={this.onChange}
|
||||
error={!!errors.password}
|
||||
helperText={!!errors.password && "Votre mot de passe doit contenir au minimum 8 caractères."}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<IconButton aria-label="Toggle password visibility" onClick={this.handleClickShowPassword}>
|
||||
<IconButton
|
||||
edge="end"
|
||||
aria-label="Toggle password visibility"
|
||||
onClick={this.handleClickShowPassword}
|
||||
>
|
||||
{this.state.showPassword ? <Visibility /> : <VisibilityOff />}
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
}
|
||||
autoComplete="current-password"
|
||||
error={!!errors.password}
|
||||
/>
|
||||
</FormControl>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox value={data.checkNewsletter}
|
||||
<Checkbox
|
||||
id="cypCheckboxNewsletter"
|
||||
value={data.checkNewsletter}
|
||||
onChange={this.handleCheckBoxChange('checkNewsletter')}
|
||||
/>
|
||||
}
|
||||
className={classes.checkbox}
|
||||
label="Je souhaite recevoir la newsletter de Talents Tube"
|
||||
|
||||
|
||||
/>
|
||||
|
||||
<FormControlLabel
|
||||
name="checkCGU"
|
||||
className={!!errors.checkCGU&&classes.checkboxError}
|
||||
className={!!errors.checkCGU ? classes.checkbox + ' ' + classes.checkboxError : classes.checkbox}
|
||||
control={
|
||||
<Checkbox
|
||||
error={!!errors.checkCGU }
|
||||
<Checkbox
|
||||
id="cypCheckboxRegister"
|
||||
value={data.checkCGU}
|
||||
onChange={this.handleCheckBoxChange('checkCGU')}
|
||||
onChange={this.handleCheckBoxChange('checkCGU')} required
|
||||
/>
|
||||
|
||||
|
||||
}
|
||||
label="Je déclare avoir pris connaissance et accepte les termes et les CGU*"
|
||||
label="Je déclare avoir pris connaissance et accepte les termes et les CGU *"
|
||||
required
|
||||
/>
|
||||
<Button type="submit" variant="outlined" color="primary" onClick={this.onRegister}>
|
||||
<Link href={`/Cgu`} className={classes.cgu}>Lire les CGU</Link>
|
||||
<Button type="submit" variant="contained" className={classes.button + ' ' + classes.buttonImportant + ' cypButtonRegister'} onClick={this.onRegister}>
|
||||
S'inscrire
|
||||
</Button>
|
||||
|
||||
<Typography
|
||||
{/* <Typography
|
||||
paragraph={true}
|
||||
align="center"
|
||||
>Ou</Typography>
|
||||
className={classes.conditionalText}
|
||||
>Ou</Typography> */}
|
||||
|
||||
</form>
|
||||
<Button variant="outlined" color="primary" onClick={this.props.linkedInAuth}>
|
||||
Connexion avec Linkedin
|
||||
</Button>
|
||||
<Button variant="outlined" color="primary" onClick={this.props.facebookAuth}>
|
||||
Connexion avec Facebook
|
||||
</Button>
|
||||
<div className={classes.form}>
|
||||
|
||||
{/* <SocialButtonsAuth linkedInAuth={this.props.linkedInAuth} facebookAuth={this.props.facebookAuth} /> */}
|
||||
|
||||
<div classes={classes.form}>
|
||||
<Typography
|
||||
paragraph={true}
|
||||
align="center"
|
||||
className={classes.formText}
|
||||
>Je possède un compte Talents Tube ?
|
||||
<Link href={"/Login"} className={classes.link}>
|
||||
Se connecter
|
||||
<Link href={"/Login"} >
|
||||
<span className={classes.formLink}>
|
||||
Se connecter
|
||||
</span>
|
||||
</Link>
|
||||
</Typography>
|
||||
|
||||
</div>
|
||||
<div className={classes.connexionRecruteur}>
|
||||
Vous êtes recruteur ? <a href='https://recruteur.talentstube.com'><span className={classes.enSavoirPlus}>En savoir plus</span></a>
|
||||
</div>
|
||||
<Snack name= 'snackWarning'
|
||||
variant= 'warning'
|
||||
message={errors.message}
|
||||
/>
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -226,7 +390,14 @@ class Register extends React.Component {
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
loading: !!state.user.loading,
|
||||
errors: state.user.errors
|
||||
errors: !!state.user.errors ?state.user.errors: {
|
||||
phone:null,
|
||||
email:null,
|
||||
password:null,
|
||||
firstname:null,
|
||||
lastname:null,
|
||||
checkCGU:null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import React, { Component } from 'react'
|
||||
|
||||
import Link from 'next/link';
|
||||
import React, { Component } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Plyr from 'react-plyr';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
|
||||
|
||||
import VideoVimeo from '../atoms/VideoVimeo'
|
||||
|
||||
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
@@ -20,21 +24,100 @@ const styles = theme => ({
|
||||
video: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'relative',
|
||||
|
||||
'& .plyr__video-embed': {
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
height: '40vh',
|
||||
maxHeight: '40vh',
|
||||
},
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
height: '60vh',
|
||||
},
|
||||
|
||||
},
|
||||
'& .plyr__video-wrapper.plyr__video-embed': {
|
||||
[theme.breakpoints.up('xs')]: {
|
||||
width: '240vw',
|
||||
transform: 'translateX(-55vw)',
|
||||
paddingBottom: '50% !important',
|
||||
},
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
width: 'auto',
|
||||
transform: 'inherit',
|
||||
},
|
||||
},
|
||||
'& .plyr__controls': {
|
||||
background: 'none'
|
||||
},
|
||||
},
|
||||
videoVimeo: {
|
||||
zIndex: '888',
|
||||
height: '65vh',
|
||||
paddingBottom: '0%',
|
||||
overflow: 'hidden',
|
||||
'& iframe': {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 'calc(50% - 125vw)',
|
||||
width: '250vw',
|
||||
height: '120vw',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
height: '48vw',
|
||||
paddingBottom: '0',
|
||||
'& iframe': {
|
||||
position: 'absolute',
|
||||
left: 'calc(50% - 100vw)',
|
||||
width: '200vw',
|
||||
height: '130%',
|
||||
},
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
height: '48vw',
|
||||
},
|
||||
},
|
||||
text: {
|
||||
zIndex: '999',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
position: 'absolute',
|
||||
bottom: '17vh',
|
||||
left: '3vh',
|
||||
},
|
||||
plyr: {
|
||||
'.plyr--video .plyr__controls': {
|
||||
background: null
|
||||
}
|
||||
}
|
||||
textCompany: {
|
||||
color: theme.palette.secondary.main,
|
||||
backgroundColor: 'rgba(30,35,39,0.9)',
|
||||
padding: theme.spacing(0.8, 2),
|
||||
marginBottom: 0,
|
||||
fontWeight: 'bold',
|
||||
fontSize: '1em',
|
||||
},
|
||||
textJob: {
|
||||
color: theme.palette.secondary.main,
|
||||
backgroundColor: 'rgba(30,35,39,0.5)',
|
||||
padding: theme.spacing(0.4, 2),
|
||||
marginBottom: 0,
|
||||
fontWeight: 'lighter',
|
||||
fontSize: '0.9em',
|
||||
},
|
||||
button: {
|
||||
position: 'absolute',
|
||||
bottom: '5vh',
|
||||
left: '3vh',
|
||||
padding: theme.spacing(1, 4),
|
||||
textTransform: 'inherit',
|
||||
zIndex: '999',
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
const videoList = [{ vimeoId: '228345901', title: 'Eurofins', adTitle: 'CDI gestion', link: '/offre?id=22' },
|
||||
{ vimeoId: '230731700', title: 'MULTIPLAST', adTitle: 'CDI example', link: '/offre?id=24' },
|
||||
{ vimeoId: '232953887', title: 'Actual', adTitle: 'Chef général', link: '/offre?id=26' }]
|
||||
|
||||
const videoList = [
|
||||
{ vimeoId: '350927569', title: 'Les Vergers de Châteaubourg', adTitle: 'Conducteurs de ligne (H/F)', link: '/Offre/73-Les-Vergers-de-Châteaubourg-chateaubourg' },
|
||||
{ vimeoId: '350927551', title: 'Grand Ouest Étiquettes', adTitle: 'Conducteurs de machine d’impression', link: '/Offre/79-Grand-Ouest-Étiquettes-Saint-Brieuc' },
|
||||
{ vimeoId: '350927537', title: 'Fym Action', adTitle: 'Promoteur des ventes en alimentaire (H/F)', link: '/Offre/81-Fym-Action-Caudan' }
|
||||
]
|
||||
|
||||
class ShortVideoHooker extends Component {
|
||||
constructor(props) {
|
||||
@@ -54,7 +137,7 @@ class ShortVideoHooker extends Component {
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
this.timer = setInterval(this.tick.bind(this), 500);
|
||||
this.timer = setInterval(this.tick.bind(this), 2000);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
@@ -62,7 +145,7 @@ class ShortVideoHooker extends Component {
|
||||
}
|
||||
|
||||
tick() {
|
||||
// console.log(this.state)
|
||||
|
||||
if (new Date() - this.state.startDate >= 8000) {
|
||||
|
||||
if (this.state.i == 2)
|
||||
@@ -70,13 +153,13 @@ class ShortVideoHooker extends Component {
|
||||
else
|
||||
this.setState({ i: ++this.state.i, startDate: Date.now() })
|
||||
//Update Plyr
|
||||
if (this.plyrRef) {
|
||||
this.plyrRef.hideControls = true;
|
||||
this.plyrRef.displayDuration = false;
|
||||
this.plyrRef.updateVideoSource(videoList[this.state.i].vimeoId, 'vimeo')
|
||||
this.plyrRef.hideControls = true;
|
||||
this.plyrRef.displayDuration = false;
|
||||
}
|
||||
// if (this.plyrRef) {
|
||||
// this.plyrRef.hideControls = true;
|
||||
// this.plyrRef.displayDuration = false;
|
||||
// this.plyrRef.updateVideoSource(videoList[this.state.i].vimeoId, 'vimeo')
|
||||
// this.plyrRef.hideControls = true;
|
||||
// this.plyrRef.displayDuration = false;
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -84,45 +167,42 @@ class ShortVideoHooker extends Component {
|
||||
render() {
|
||||
let { classes } = this.props;
|
||||
let videoId = videoList[0].vimeoId;
|
||||
// console.log(videoId)
|
||||
|
||||
return (
|
||||
<div className={classes.video}>
|
||||
{/* config at : https://github.com/xDae/react-plyr */}
|
||||
<Plyr
|
||||
//autoplay
|
||||
type="vimeo" // or "vimeo"
|
||||
videoId={videoId}
|
||||
//displayDuration={false}
|
||||
hideControls={true}
|
||||
clickToPlay={false}
|
||||
fullscreen={{ enabled: false, fallback: true, iosNative: false }}
|
||||
disableContextMenu={true}
|
||||
controls={null}
|
||||
ref={this.setPlyrRef}
|
||||
className={classes.plyr}
|
||||
/>
|
||||
<Typography gutterBottom
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h4"
|
||||
align="center"
|
||||
className={classes.text}>
|
||||
{videoList[this.state.i].title}
|
||||
</Typography>
|
||||
{/* <VideoVimeo classesOverride={ classes.videoVimeo } videoId={videoId}
|
||||
options={`?byline=0&title=0&background=1&autoplay=1&mute=1`} />
|
||||
<section className={classes.text}>
|
||||
<Typography gutterBottom
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h4"
|
||||
align="center"
|
||||
className={classes.textCompany}>
|
||||
{videoList[this.state.i].title}
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h4"
|
||||
align="center"
|
||||
className={classes.text}>
|
||||
{videoList[this.state.i].adTitle}
|
||||
</Typography>
|
||||
<Button variant="outlined">
|
||||
Voir l'offre
|
||||
<Typography gutterBottom
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h4"
|
||||
align="center"
|
||||
className={classes.textJob}>
|
||||
{videoList[this.state.i].adTitle}
|
||||
</Typography>
|
||||
</section>
|
||||
<Link href={videoList[this.state.i].link}>
|
||||
<Button
|
||||
name="Offre"
|
||||
className={classes.button}
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
>
|
||||
Voir l'offre
|
||||
</Button>
|
||||
</Link> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
export default withStyles(styles)(ShortVideoHooker);
|
||||
export default withStyles(styles)(withWidth()(ShortVideoHooker))
|
||||
@@ -0,0 +1,123 @@
|
||||
import React from 'react';
|
||||
import Link from 'next/link';
|
||||
import clsx from 'clsx';
|
||||
import { loadCSS } from 'fg-loadcss';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { red } from '@material-ui/core/colors';
|
||||
import Icon from '@material-ui/core/Icon';
|
||||
import Hidden from '@material-ui/core/Hidden';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
iconHover: {
|
||||
margin: theme.spacing(2),
|
||||
'&:hover': {
|
||||
color: red[800],
|
||||
},
|
||||
},
|
||||
icon: {
|
||||
margin: theme.spacing(1.5),
|
||||
padding: theme.spacing(1.5),
|
||||
borderRadius: '20px',
|
||||
fontSize: '1em',
|
||||
textAlign: 'center',
|
||||
},
|
||||
FacebookIcon: {
|
||||
color: theme.palette.social.facebook,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.social.facebook,
|
||||
color: '#fff',
|
||||
}
|
||||
},
|
||||
TwitterIcon: {
|
||||
color: theme.palette.social.twitter,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.social.twitter,
|
||||
color: '#fff',
|
||||
}
|
||||
},
|
||||
LinkedinIcon: {
|
||||
color: theme.palette.social.linkedin,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.social.linkedin,
|
||||
color: '#fff',
|
||||
}
|
||||
},
|
||||
MailIcon: {
|
||||
color: theme.palette.social.mail,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.social.mail,
|
||||
color: '#fff',
|
||||
}
|
||||
},
|
||||
FacebookIconMobile: {
|
||||
color: theme.palette.social.facebook,
|
||||
paddingRight:'0px',
|
||||
paddingLeft:'3px'
|
||||
},
|
||||
TwitterIconMobile: {
|
||||
color: theme.palette.social.twitter,
|
||||
paddingRight:'3px' ,
|
||||
paddingLeft:'3px'
|
||||
},
|
||||
LinkedinIconMobile: {
|
||||
color: theme.palette.social.linkedin,
|
||||
paddingRight:'3px',
|
||||
paddingLeft:'3px'
|
||||
},
|
||||
MailIconMobile: {
|
||||
color: theme.palette.social.mail,
|
||||
paddingRight:'3px' ,
|
||||
paddingLeft:'3px'
|
||||
},
|
||||
}));
|
||||
|
||||
export default function SocialShare(props) {
|
||||
const classes = useStyles();
|
||||
|
||||
React.useEffect(() => {
|
||||
loadCSS(
|
||||
'https://use.fontawesome.com/releases/v5.1.0/css/all.css',
|
||||
document.querySelector('#font-awesome-css'),
|
||||
);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Hidden smDown>
|
||||
<a href={"https://www.facebook.com/sharer/sharer.php?u=" + encodeURIComponent(props.url)} target="_blank">
|
||||
<Icon className={clsx(classes.icon, classes.FacebookIcon, 'fab fa-facebook-f')} />
|
||||
</a>
|
||||
<a href={"http://twitter.com/share?url=" + encodeURIComponent(props.url)} target="_blank">
|
||||
<Icon className={clsx(classes.icon, classes.TwitterIcon, 'fab fa-twitter')} color="secondary" />
|
||||
</a>
|
||||
<a href={"https://www.linkedin.com/shareArticle?mini=true&url=" + encodeURIComponent(props.url + "&title=Talents Tube")} target="_blank">
|
||||
<Icon className={clsx(classes.icon, classes.LinkedinIcon, 'fab fa-linkedin-in')} color="secondary" />
|
||||
</a>
|
||||
{/* change because of https://github.com/zeit/next.js/blob/master/errors/invalid-href-passed.md */}
|
||||
<a href={"mailto:?subject=Offre d'emploi Talents Tube&body=Regardez cette offre : " + props.url} target="_blank"s>
|
||||
<Icon className={clsx(classes.icon, classes.MailIcon, 'fas fa-envelope')} color="secondary" />
|
||||
</a>
|
||||
</Hidden>
|
||||
<Hidden mdUp>
|
||||
<a href={"https://www.facebook.com/sharer/sharer.php?u=" + encodeURIComponent(props.url)} target="_blank">
|
||||
<Icon className={clsx(classes.icon, classes.FacebookIconMobile, 'fab fa-facebook-f')} />
|
||||
</a>
|
||||
<a href={"http://twitter.com/share?url=" + encodeURIComponent(props.url)} target="_blank">
|
||||
<Icon className={clsx(classes.icon, classes.TwitterIconMobile, 'fab fa-twitter')} color="secondary" />
|
||||
</a>
|
||||
<a href={"https://www.linkedin.com/shareArticle?mini=true&url=" + encodeURIComponent(props.url + "&title=Talents Tube")} target="_blank">
|
||||
<Icon className={clsx(classes.icon, classes.LinkedinIconMobile, 'fab fa-linkedin-in')} color="secondary" />
|
||||
</a>
|
||||
{/* change because of https://github.com/zeit/next.js/blob/master/errors/invalid-href-passed.md */}
|
||||
<a href={"mailto:?subject=Offre d'emploi Talents Tube&body=Regardez cette offre : " + props.url} target="_blank"s>
|
||||
<Icon className={clsx(classes.icon, classes.MailIconMobile, 'fas fa-envelope')} color="secondary" />
|
||||
</a>
|
||||
</Hidden>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -5,79 +5,80 @@ import getConfig from 'next/config'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
import CardHeader from '@material-ui/core/CardHeader';
|
||||
import CardMedia from '@material-ui/core/CardMedia';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
import KeyboardArrowleftIcon from '@material-ui/icons/PlayArrowRounded';
|
||||
import Link from 'next/link';
|
||||
import _ from 'lodash';
|
||||
|
||||
const styles = theme => ({
|
||||
card: {
|
||||
display: 'flex',
|
||||
position: 'relative',
|
||||
height: '60vh',
|
||||
height: '400px',
|
||||
width: '100%',
|
||||
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: '30%',
|
||||
},
|
||||
[theme.breakpoints.down('md')]: {
|
||||
width: '40%',
|
||||
},
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
width: '100%',
|
||||
cursor: 'pointer',
|
||||
transform: 'translateY(-0px)',
|
||||
transition: 'transform 0.25s',
|
||||
'&:hover': {
|
||||
transform: 'translateY(-15px)',
|
||||
transition: 'transform 0.5s, box-shadow 1.2s',
|
||||
'& .cardHover': {
|
||||
backgroundColor: 'rgba(0,0,0,0)',
|
||||
},
|
||||
},
|
||||
|
||||
margin: '2vh 3vh 3vh 1vh',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
margin: '1vh 0 1vh 0',
|
||||
height: '530px',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
height: '404px',
|
||||
},
|
||||
borderRadius: '0.2em',
|
||||
},
|
||||
details_container: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
padding: '8vh 0 0 0',
|
||||
},
|
||||
company_title: {
|
||||
fontSize: '1em',
|
||||
fontWeight: 'normal',
|
||||
textTransform: 'uppercase',
|
||||
},
|
||||
content: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
flexWrap: 'wrap',
|
||||
width: '100%',
|
||||
padding: 0,
|
||||
},
|
||||
cover: {
|
||||
width: '100%',
|
||||
height: '50%',
|
||||
height: '45%',
|
||||
backgroundSize: 'cover',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundBlendMode: 'darken',
|
||||
backgroundColor: 'rgba(30,35,39,0.25)',
|
||||
transition: 'background-color 1s',
|
||||
},
|
||||
logo_container: {
|
||||
logoContainer: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: 70,
|
||||
height: 70,
|
||||
width: 80,
|
||||
height: 80,
|
||||
position: 'absolute',
|
||||
left: '50%',
|
||||
top: '50%',
|
||||
top: '45%',
|
||||
transform: 'translate(-50%, -66%)',
|
||||
backgroundColor: 'white',
|
||||
boxShadow: '0 8px 6px -6px grey',
|
||||
border: 'solid 5px white',
|
||||
borderRadius: '0.5em',
|
||||
backgroundColor: 'white',
|
||||
boxShadow: '0px 6px 15px rgba(30, 35, 39, 0.10)',
|
||||
borderRadius: '5px',
|
||||
},
|
||||
iconPlay: {
|
||||
fontSize: '3em',
|
||||
color: theme.palette.background.grey,
|
||||
position: 'absolute',
|
||||
left: 'calc(50% - 0.5em)',
|
||||
top: 'calc(22.5% - 0.5em)',
|
||||
},
|
||||
logo: {
|
||||
width: '100%',
|
||||
height: 'auto',
|
||||
objectfit: 'contain',
|
||||
borderRadius: 'inherit',
|
||||
},
|
||||
chip: {
|
||||
margin: '0 1vh 0 1vh',
|
||||
@@ -90,28 +91,34 @@ const { publicRuntimeConfig } = getConfig()
|
||||
class Tile extends React.Component {
|
||||
|
||||
render() {
|
||||
const { classes, rowData, children, tileIndex } = this.props;
|
||||
const imgAdUrl = (rowData.video && rowData.video.thumbnails[0] && rowData.video.thumbnails[0].sizes[4]) ? rowData.video.thumbnails[0].sizes[4].link : publicRuntimeConfig.adListDefaultUrl
|
||||
const imgCompanyUrl = (rowData.presentation_video && rowData.presentation_video.thumbnails[0] && rowData.presentation_video.thumbnails[0].sizes[4]) ? rowData.presentation_video.thumbnails[0].sizes[4].link : publicRuntimeConfig.adListDefaultUrl
|
||||
const imgUrl = (rowData.video) ? imgAdUrl : imgCompanyUrl
|
||||
|
||||
const { classes, rowData, children } = this.props;
|
||||
const logoName = (rowData.company) ? rowData.company.logo : rowData.logo
|
||||
const logoUrl = publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.cachedMediaUrl + logoName
|
||||
|
||||
const imgUrl = (rowData.video.thumbnails[0] && rowData.video.thumbnails[0].sizes[4]) ? rowData.video.thumbnails[0].sizes[4].link : publicRuntimeConfig.adListDefaultUrl
|
||||
const logoUrl = publicRuntimeConfig.logoRootUrl + rowData.company.logo
|
||||
//rowData._embedded.company.business_name
|
||||
|
||||
const router = (rowData.company) ? `/Offre/${rowData.id}-${_.kebabCase(rowData.title)}` : `/Entreprise/${rowData.id}-${_.kebabCase(rowData.brand_name)}}`
|
||||
|
||||
//rowData._embedded.company.brand_name
|
||||
return (
|
||||
<Card className={classes.card} onClick={() => Router.push(`/Offre?id=${rowData.id}`)}>
|
||||
<CardContent className={classes.content}>
|
||||
<CardMedia
|
||||
className={classes.cover}
|
||||
image={imgUrl}
|
||||
title={rowData.title}
|
||||
/>
|
||||
|
||||
<div className={classes.logo_container}>
|
||||
<Avatar className={classes.logo} src={logoUrl} />
|
||||
</div>
|
||||
{ children }
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Link href={router} >
|
||||
<Card cyp="CardOneOffers" className={classes.card}>
|
||||
<CardContent className={classes.content}>
|
||||
<CardMedia
|
||||
className={classes.cover + ' cardHover'}
|
||||
image={imgUrl}
|
||||
title={rowData.title}
|
||||
/>
|
||||
<KeyboardArrowleftIcon className={classes.iconPlay} />
|
||||
<div className={classes.logoContainer}>
|
||||
<Avatar className={classes.logo} src={logoUrl} alt={rowData.title}/>
|
||||
</div>
|
||||
{ children }
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -119,7 +126,7 @@ class Tile extends React.Component {
|
||||
Tile.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
rowData: PropTypes.object.isRequired
|
||||
rowData: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withStyles(styles, { withTheme: true })(Tile);
|
||||
@@ -3,69 +3,88 @@ import PropTypes from "prop-types";
|
||||
import Router from 'next/router'
|
||||
import getConfig from 'next/config'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import IconText from './../atoms/IconText';
|
||||
|
||||
const styles = theme => ({
|
||||
details_container: {
|
||||
detailsContainer: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
padding: '8vh 0 0 0',
|
||||
justifyContent: 'space-between',
|
||||
position: 'absolute',
|
||||
top: '60%',
|
||||
width: '100%',
|
||||
minHeight: '35%',
|
||||
},
|
||||
company_title: {
|
||||
companyTitle: {
|
||||
fontSize: '1em',
|
||||
fontWeight: 'normal',
|
||||
textTransform: 'uppercase',
|
||||
paddingLeft: theme.spacing(1),
|
||||
paddingRight: theme.spacing(1),
|
||||
minHeight: '8vh',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
minHeight: 'inherit',
|
||||
},
|
||||
},
|
||||
chip: {
|
||||
height: '27px',
|
||||
padding: theme.spacing(1),
|
||||
margin: '0 1vh 0 1vh',
|
||||
},
|
||||
rootIconText: {
|
||||
margin: 0,
|
||||
padding: theme.spacing(0.5, 0),
|
||||
color: theme.palette.secondary.dark,
|
||||
'& p ': {
|
||||
color: theme.palette.secondary.text,
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
class TileCompany extends React.Component {
|
||||
class CompanyOffre extends React.Component {
|
||||
|
||||
render() {
|
||||
|
||||
const { classes, tile } = this.props;
|
||||
|
||||
const offre = (tile.count_ads == 1) ? tile.count_ads + ' offre' : tile.count_ads + ' offres'
|
||||
const nbOffre = (tile.count_ads > 0) ? offre : 'Candidature spontanée'
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={classes.details_container}>
|
||||
<Typography
|
||||
gutterBottom
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h4"
|
||||
align="center"
|
||||
className={classes.company_title}>
|
||||
{tile.company.business_name}
|
||||
</Typography>
|
||||
<section className={classes.detailsContainer}>
|
||||
<Typography
|
||||
gutterBottom
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h3"
|
||||
align="center"
|
||||
className={classes.job_title}>
|
||||
{tile.title}
|
||||
className={classes.companyTitle}>
|
||||
{tile.brand_name ? tile.brand_name : "-"}
|
||||
</Typography>
|
||||
</div>
|
||||
<div>
|
||||
<Chip label={tile.extra.contract_type} className={classes.chip} />
|
||||
<Chip label={tile.location.gmap_address.address_components[0].long_name} className={classes.chip} />
|
||||
</div>
|
||||
|
||||
{tile.addresses && tile.addresses.billing && tile.addresses.billing.city &&
|
||||
<IconText classes={{ root: classes.rootIconText }} variant="location_on" text={tile.addresses.billing.city} />
|
||||
}
|
||||
{tile.title &&
|
||||
<IconText classes={{ root: classes.rootIconText }} variant="business_center" text={tile.title} />
|
||||
}
|
||||
{nbOffre &&
|
||||
<Chip color="primary" label={nbOffre} className={classes.chip} />
|
||||
}
|
||||
|
||||
</section>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TileCompany.propTypes = {
|
||||
CompanyOffre.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
tile: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default withStyles(styles, { withTheme: true })(TileCompany);
|
||||
export default withStyles(styles, { withTheme: true })(CompanyOffre);
|
||||
|
||||
@@ -1,31 +1,44 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import Router from 'next/router'
|
||||
import getConfig from 'next/config'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Icon from '@material-ui/core/Icon';
|
||||
import IconText from './../atoms/IconText';
|
||||
|
||||
const styles = theme => ({
|
||||
details_container: {
|
||||
detailsContainer: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
padding: '8vh 0 0 0',
|
||||
justifyContent: 'space-between',
|
||||
position: 'absolute',
|
||||
top: '44%',
|
||||
width: '100%',
|
||||
},
|
||||
company_title: {
|
||||
fontSize: '0.8em',
|
||||
fontWeight: 'normal',
|
||||
companyTitle: {
|
||||
fontSize: '1em',
|
||||
fontWeight: '100',
|
||||
padding: theme.spacing(0, 2),
|
||||
marginTop: '4vh',
|
||||
minHeight: '6vh',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
minHeight: '3vh',
|
||||
},
|
||||
},
|
||||
job_title: {
|
||||
fontSize: '1em',
|
||||
marginLeft: theme.spacing(1),
|
||||
marginRight: theme.spacing(1),
|
||||
jobTitle: {
|
||||
fontSize: '1.2em',
|
||||
padding: theme.spacing(0, 2),
|
||||
minHeight: '8vh',
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
minHeight: '50px',
|
||||
},
|
||||
},
|
||||
chip: {
|
||||
margin: '0 1vh 0 1vh',
|
||||
rootIconText: {
|
||||
margin: 0,
|
||||
padding: theme.spacing(0.5, 2),
|
||||
color: theme.palette.secondary.dark,
|
||||
justifyContent: 'flex-start',
|
||||
'& p ': {
|
||||
color: theme.palette.secondary.text,
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
@@ -38,31 +51,41 @@ class TileOffre extends React.Component {
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<section className={classes.details_container}>
|
||||
<section className={classes.detailsContainer} >
|
||||
<Typography
|
||||
gutterBottom
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h4"
|
||||
align="center"
|
||||
className={classes.company_title}>
|
||||
{tile.company.business_name}
|
||||
className={classes.companyTitle}>
|
||||
{tile.company.brand_name && tile.company.brand_name}
|
||||
</Typography>
|
||||
<Typography
|
||||
gutterBottom
|
||||
variant="headline"
|
||||
variant="h6"
|
||||
component="h3"
|
||||
align="center"
|
||||
className={classes.job_title}>
|
||||
{tile.title}
|
||||
align="left"
|
||||
className={classes.jobTitle}>
|
||||
{tile.title && tile.title}
|
||||
</Typography>
|
||||
</section>
|
||||
<section>
|
||||
<Chip label={tile.extra.contract_type} className={classes.chip} />
|
||||
<Chip label={tile.location.gmap_address.address_components[0].long_name} className={classes.chip} />
|
||||
<IconText />
|
||||
<Icon>add_circle</Icon>
|
||||
|
||||
{/*
|
||||
<IconText classes={{root: classes.rootIconText}} variant="business_center" text={tile.title} />
|
||||
*/}
|
||||
|
||||
|
||||
{tile.location && tile.location.gmap_address && tile.location.gmap_address.address_components && tile.location.gmap_address.address_components[0].long_name &&
|
||||
<IconText classes={{ root: classes.rootIconText }} variant="location_on" text={tile.location.gmap_address.address_components[0].long_name} />
|
||||
}
|
||||
{tile.extra && tile.extra.contract_type &&
|
||||
<IconText classes={{ root: classes.rootIconText }} variant="assignment" text={tile.extra.contract_type} />
|
||||
}
|
||||
|
||||
{tile.beneficiaire &&
|
||||
<IconText classes={{ root: classes.rootIconText }} variant="business" text={tile.beneficiaire} />
|
||||
}
|
||||
</section>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import videojs from 'video.js'
|
||||
import React, { lazy } from 'react';
|
||||
const videojs = lazy(() => import('video.js'));
|
||||
//import videojs from 'video.js'
|
||||
|
||||
export default class VideoPlayer extends React.Component {
|
||||
componentDidMount() {
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import Link from 'next/link'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import BottomToolbar from '../organisms/BottomToolbar';
|
||||
import { Fragment } from 'react';
|
||||
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
position: 'relative',
|
||||
height: '10vh'
|
||||
},
|
||||
});
|
||||
|
||||
function Footer(props) {
|
||||
const { classes } = props;
|
||||
return (
|
||||
<Fragment>
|
||||
|
||||
</Fragment>
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
export default withStyles(styles)(Footer)
|
||||
@@ -1,15 +1,68 @@
|
||||
import Griddle, { utils } from "griddle-react";
|
||||
import Griddle, { utils, plugins } from "griddle-react";
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import OffreRow from "../organisms/OffreRow"
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { Button } from '@material-ui/core';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import GriddleCustomTable from "../organisms/GriddleCustomTableComponent";
|
||||
import GriddleCustomNextButton from "../organisms/GriddleCustomNextButton"
|
||||
import GriddleCustomPreviousButton from "../organisms/GriddleCustomPreviousButton"
|
||||
import GriddleCustomPageDropdown from "../organisms/GriddleCustomPageDropdown"
|
||||
import Loader from './loader'
|
||||
import IconSearch from '@material-ui/icons/Search';
|
||||
import NoResult from './../atoms/NoResult';
|
||||
import _ from "lodash";
|
||||
|
||||
//insights
|
||||
//
|
||||
//https://codesandbox.io/s/pw9zy43v1m?module=%2FGrid.js
|
||||
|
||||
const styles = theme => ({
|
||||
textField: {
|
||||
textAlign: 'center',
|
||||
justifyContent: 'center',
|
||||
margin: 0,
|
||||
'& input': {
|
||||
fontWeight: '300',
|
||||
color: theme.palette.primary.dark,
|
||||
backgroundColor: theme.palette.background.grey,
|
||||
minWidth: '75vw',
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
paddingLeft: theme.spacing(2),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
minWidth: '85vw',
|
||||
},
|
||||
}
|
||||
},
|
||||
griddle: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
'& .griddle-pagination': {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
},
|
||||
button: {
|
||||
padding: theme.spacing(2, 0),
|
||||
boxShadown: '0px',
|
||||
backgroundColor: theme.palette.background.grey,
|
||||
},
|
||||
filterForm: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
backgroundColor: theme.palette.background.grey,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100% !important',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
justifyContent: 'space-evenly',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const CustomTableBody = ({ rowIds, Row, style, className }) => (
|
||||
<div style={style} className={className}>
|
||||
@@ -24,65 +77,189 @@ class Grid extends Component {
|
||||
success: false,
|
||||
data: {},
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 12,
|
||||
recordCount: 0,
|
||||
filterText: ""
|
||||
promoted: false,
|
||||
filterText: "",
|
||||
// options: [],
|
||||
};
|
||||
|
||||
async componentDidMount() {
|
||||
|
||||
this.setState({pageSize:this.props.limit})
|
||||
let data = sessionStorage.getItem(this.props.type+'_currentPage');
|
||||
let current;
|
||||
if(data){
|
||||
current=data;
|
||||
}else{
|
||||
current=this.state.currentPage;
|
||||
}
|
||||
this.props.dataFetcher(
|
||||
{
|
||||
offset: this.state.currentPage,
|
||||
limit: this.state.pageSize
|
||||
offset: ((current-1)*this.props.limit)+1,
|
||||
limit: this.props.limit
|
||||
}
|
||||
);
|
||||
// let options = [];
|
||||
// let startIndex = Math.max(this.props.currentPage - 5, 0);
|
||||
// let endIndex = Math.min(startIndex + 11, this.props.maxPage);
|
||||
|
||||
// if (this.props.maxPage >= 11 && (endIndex - startIndex) <= 10) {
|
||||
// startIndex = endIndex - 11;
|
||||
// }
|
||||
|
||||
// for(let i = startIndex; i < endIndex ; i++){
|
||||
// let selected = this.props.currentPage == i ? "current-page-selected" : "";
|
||||
// options.push(<button className={selected} data-value={i} onClick={this.pageChange}>{i + 1}</button>);
|
||||
// }
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
|
||||
this.setState({ data: nextProps.data });
|
||||
this.setState({ currentPage: nextProps.currentPage });
|
||||
this.setState({ recordCount: nextProps.recordCount });
|
||||
this.setState({ loading: nextProps.loading });
|
||||
this.setState({ limit: nextProps.limit });
|
||||
|
||||
|
||||
const { currentPage, pageSize, filterText, promoted } = this.state;
|
||||
|
||||
if (nextProps.promoted != this.state.promoted) {
|
||||
let data = sessionStorage.getItem(this.props.type+'_currentPage');
|
||||
let current;
|
||||
if(data){
|
||||
current=data;
|
||||
}else{
|
||||
current=this.state.currentPage;
|
||||
}
|
||||
this.setState({ promoted: nextProps.promoted });
|
||||
this.props.dataFetcher(
|
||||
{
|
||||
offset: ((current-1)*(this.state.pageSize+1))+1,
|
||||
limit: this.state.pageSize,
|
||||
keyword: filterText,
|
||||
isPromoted: nextProps.promoted
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
_onNext = () => {
|
||||
const { currentPage, pageSize, filterText } = this.state;
|
||||
console.debug(`-- _onNext -- ${0} -- ${1} -- ${2} --`, currentPage, pageSize, filterText)
|
||||
this.props.dataFetcher({ offset: currentPage * pageSize, limit: pageSize, keyword: filterText })
|
||||
const { currentPage, pageSize, filterText, promoted } = this.state;
|
||||
this.props.dataFetcher({ offset: currentPage * pageSize, limit: pageSize, keyword: filterText, isPromoted: promoted })
|
||||
sessionStorage.setItem(this.props.type+'_currentPage', currentPage+1);
|
||||
|
||||
};
|
||||
|
||||
_onPrevious = () => {
|
||||
const { currentPage, pageSize, filterText } = this.state;
|
||||
this.props.dataFetcher({ offset: (currentPage - 2) * pageSize + 1, limit: pageSize, keyword: filterText });
|
||||
const { currentPage, pageSize, filterText, promoted } = this.state;
|
||||
this.props.dataFetcher({ offset: (currentPage - 2) * pageSize + 1, limit: pageSize, keyword: filterText, isPromoted: promoted });
|
||||
sessionStorage.setItem(this.props.type+'_currentPage', currentPage-1);
|
||||
|
||||
};
|
||||
|
||||
_onGetPage = pageNumber => {
|
||||
const { pageSize, filterText } = this.state;
|
||||
this.props.dataFetcher({ offset: (pageNumber - 1) * pageSize + 1, limit: pageSize, keyword: filterText });
|
||||
_onGetPage = (pageNumber, page) => {
|
||||
const { pageSize, filterText, promoted } = this.state;
|
||||
this.props.dataFetcher({ offset: (page - 1) * pageSize + 1, limit: pageSize, keyword: filterText, isPromoted: promoted });
|
||||
console.log(pageNumber);
|
||||
console.log(page);
|
||||
sessionStorage.setItem(this.props.type+'_currentPage', page);
|
||||
console.log("On get Page");
|
||||
};
|
||||
|
||||
_onSetPage = pageNumber => {
|
||||
const { pageSize, filterText, promoted } = this.state;
|
||||
this.props.dataFetcher({ offset: (pageNumber - 1) * pageSize + 1, limit: pageSize, keyword: filterText, isPromoted: promoted });
|
||||
console.log("On set Page");
|
||||
};
|
||||
|
||||
_onFilter = filterText => {
|
||||
sessionStorage.setItem(this.props.type+'_currentPage', 1);
|
||||
this.setState({ currentPage: 1 });
|
||||
const { currentPage, pageSize } = this.state;
|
||||
const { currentPage, pageSize, promoted } = this.state;
|
||||
this.setState({ filterText });
|
||||
this.props.dataFetcher({ offset: (currentPage - 1) * pageSize + 1, limit: pageSize, keyword: filterText });
|
||||
this.props.dataFetcher({ offset: (currentPage - 1) * pageSize + 1, limit: pageSize, keyword: filterText, isPromoted: promoted });
|
||||
};
|
||||
|
||||
searchChange = e => {
|
||||
this.setState({ filterText: e.target.value });
|
||||
}
|
||||
|
||||
searchSubmit = () => {
|
||||
const { currentPage, pageSize, promoted, filterText } = this.state;
|
||||
sessionStorage.setItem(this.props.type+'_currentPage', 1);
|
||||
this.props.dataFetcher({ offset: 1, limit: pageSize, keyword: filterText, isPromoted: promoted });
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const { classes, placeholder } = this.props
|
||||
const style = {
|
||||
styles: {
|
||||
TableBody: { display: "flex", flexWrap: "wrap", justifyContent: "space-around" },
|
||||
TableBody: {
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'space-around'
|
||||
},
|
||||
Pagination: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingTop: '32px',
|
||||
},
|
||||
NextButton: {
|
||||
fontSize: '0.9em',
|
||||
fontWeight: '600',
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
textTransform: 'inherit',
|
||||
marginLeft: '64px',
|
||||
marginRight: '64px',
|
||||
marginTop: '32px',
|
||||
marginBottom: '16px',
|
||||
padding: '9px 16px',
|
||||
borderRadius: '3px',
|
||||
backgroundColor: 'transparent',
|
||||
border: '1px solid #E8E8E9',
|
||||
color: '#787B7D',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
PreviousButton: {
|
||||
fontSize: '0.9em',
|
||||
fontWeight: '600',
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
textTransform: 'inherit',
|
||||
marginLeft: '64px',
|
||||
marginRight: '64px',
|
||||
marginTop: '32px',
|
||||
marginBottom: '16px',
|
||||
padding: '9px 16px',
|
||||
borderRadius: '3px',
|
||||
backgroundColor: 'transparent',
|
||||
border: '1px solid #E8E8E9',
|
||||
color: '#787B7D',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
PageDropdown: {
|
||||
fontSize: '0.9em',
|
||||
fontWeight: '600',
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
// display: 'none',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const { data, currentPage, pageSize, recordCount } = this.state;
|
||||
// console.debug("-- render -- ")
|
||||
// console.debug(data)
|
||||
const { filterText, data, currentPage, pageSize, recordCount, loading } = this.state;
|
||||
|
||||
const NewLayout = ({ Table, Pagination, Filter }) => (
|
||||
|
||||
<div>
|
||||
<Filter />
|
||||
<Pagination />
|
||||
{/* <Filter /> */}
|
||||
<Table />
|
||||
<Pagination />
|
||||
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -103,39 +280,88 @@ class Grid extends Component {
|
||||
|
||||
|
||||
return (
|
||||
|
||||
<div>
|
||||
<Griddle
|
||||
data={data}
|
||||
pageProperties={{
|
||||
currentPage,
|
||||
pageSize,
|
||||
recordCount
|
||||
}}
|
||||
components={{
|
||||
Layout: NewLayout,
|
||||
Row: this.props.CustomRowComponent,
|
||||
TableContainer: GriddleCustomTable,
|
||||
TableBody: CustomTableBody
|
||||
}}
|
||||
events={{
|
||||
onNext: this._onNext,
|
||||
onPrevious: this._onPrevious,
|
||||
onGetPage: this._onGetPage,
|
||||
onFilter: this._onFilter
|
||||
}}
|
||||
styleConfig={style}
|
||||
/>
|
||||
{this.props.searchable &&
|
||||
<div className={classes.filterForm}>
|
||||
<TextField
|
||||
id="standard-search"
|
||||
disabled={loading}
|
||||
name="search"
|
||||
value={filterText}
|
||||
onChange={this.searchChange}
|
||||
placeholder={placeholder}
|
||||
className={classes.textField}
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
margin="dense"
|
||||
variant="filled"
|
||||
onKeyPress={(ev) => {
|
||||
if (ev.key === 'Enter') {
|
||||
this.searchSubmit()
|
||||
}
|
||||
}}
|
||||
type="search"
|
||||
/>
|
||||
<Button onClick={this.searchSubmit}
|
||||
disabled={loading}
|
||||
variant="contained"
|
||||
className={classes.button}>
|
||||
<IconSearch />
|
||||
</Button >
|
||||
</div>
|
||||
}
|
||||
{loading ?
|
||||
(<Loader />)
|
||||
: !_.isEmpty(data) ? (
|
||||
<Griddle
|
||||
className={classes.griddle}
|
||||
data={data}
|
||||
pageProperties={{
|
||||
currentPage,
|
||||
pageSize,
|
||||
recordCount,
|
||||
}}
|
||||
useCustomPagerComponent="true"
|
||||
plugins={plugins.localPlugin}
|
||||
components={{
|
||||
Layout: NewLayout,
|
||||
Row: this.props.CustomRowComponent,
|
||||
TableContainer: GriddleCustomTable,
|
||||
TableBody: CustomTableBody,
|
||||
PreviousButton: GriddleCustomPreviousButton,
|
||||
NextButton: GriddleCustomNextButton,
|
||||
PageDropdown: GriddleCustomPageDropdown,
|
||||
|
||||
}}
|
||||
events={{
|
||||
onNext: this._onNext,
|
||||
onPrevious: this._onPrevious,
|
||||
onGetPage: this._onGetPage,
|
||||
onFilter: this._onFilter,
|
||||
onSetPage: this._onSetPage
|
||||
}}
|
||||
styleConfig={style}
|
||||
/>
|
||||
) : (<NoResult text='Aucun résultat.' />)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Grid.defaultProps = {
|
||||
offset: 1,
|
||||
limit: 12,
|
||||
searchable: true
|
||||
}
|
||||
|
||||
Grid.propTypes = {
|
||||
dataFetcher: PropTypes.func.isRequired,
|
||||
CustomRowComponent: PropTypes.any.isRequired,
|
||||
data: PropTypes.any
|
||||
data: PropTypes.any,
|
||||
searchable: PropTypes.bool
|
||||
}
|
||||
|
||||
export default Grid;
|
||||
export default withStyles(styles)(Grid);
|
||||
|
||||
@@ -1,43 +1,25 @@
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import RootContainer from '../atoms/RootContainer'
|
||||
import Header from '../organisms/Header'
|
||||
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
height: '100%'
|
||||
},
|
||||
head: {
|
||||
width: '100%',
|
||||
|
||||
height: '56px',
|
||||
background: 'silver',
|
||||
height: '64px',
|
||||
background: theme.palette.secondary.main,
|
||||
position: 'fixed',
|
||||
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
height: '64px'
|
||||
}
|
||||
|
||||
zIndex: '1199',
|
||||
},
|
||||
foot: {
|
||||
height: '56px',
|
||||
height: '64px',
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
top: '56px',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
height: '64px',
|
||||
top: '64px'
|
||||
},
|
||||
|
||||
top: '64px',
|
||||
},
|
||||
content: {
|
||||
top: '56px',
|
||||
height: 'calc(100vh - 112px)',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
top: '64px',
|
||||
height: 'calc(100vh - 128px)',
|
||||
},
|
||||
top: '64px',
|
||||
height: 'calc(100vh - 64px)',
|
||||
position: 'relative',
|
||||
overflow: 'auto',
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -46,7 +28,7 @@ function Layout(props) {
|
||||
const { classes } = props;
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<RootContainer>
|
||||
<div id="H" className={classes.head}>
|
||||
<div className={classes.inner}>
|
||||
<Header searchBar={true}/>
|
||||
@@ -56,7 +38,7 @@ function Layout(props) {
|
||||
{props.children}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</RootContainer>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
import React, { Component, useEffect } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import Router from 'next/router';
|
||||
import RootContainer from '../atoms/RootContainer'
|
||||
import ButtonBase from "@material-ui/core/ButtonBase";
|
||||
import ArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { Button, Hidden } from '@material-ui/core';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
import DialogContentText from '@material-ui/core/DialogContentText';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
|
||||
|
||||
const styles = theme => ({
|
||||
inner: {
|
||||
height: '100%',
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.04), 0 1px 10px 0 rgba(0, 0, 0, 0.04), 0 3px 5px -1px rgba(0, 0, 0, 0.04)',
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
},
|
||||
head: {
|
||||
zIndex: '999',
|
||||
width: '100%',
|
||||
height: '64px',
|
||||
background: theme.palette.background.main,
|
||||
position: 'fixed',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
height: '64px'
|
||||
}
|
||||
},
|
||||
icon: {
|
||||
fontSize: '2.5em',
|
||||
},
|
||||
title: {
|
||||
color: theme.palette.primary.dark,
|
||||
},
|
||||
content: {
|
||||
top: '64px',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
top: '64px',
|
||||
position: 'relative',
|
||||
},
|
||||
contentFixed: {
|
||||
height: 'calc(100vh - 64px)',
|
||||
},
|
||||
back: {
|
||||
zIndex: 10,
|
||||
border: 'none',
|
||||
padding: theme.spacing(0.2),
|
||||
textAlign: 'center',
|
||||
textDecoration: 'none',
|
||||
borderRadius: '50%',
|
||||
position: 'absolute',
|
||||
left: theme.spacing(1),
|
||||
},
|
||||
retour:{
|
||||
fontFamily: 'Roboto',
|
||||
color: '#1E2327',
|
||||
fontSize: '0.8rem',
|
||||
fontWeight: '500',
|
||||
|
||||
},
|
||||
popup:{
|
||||
fontFamily: 'Roboto',
|
||||
color: '#1E2327',
|
||||
fontSize: '0.8rem',
|
||||
fontWeight: '500',
|
||||
}
|
||||
});
|
||||
|
||||
class LayoutBack extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
}
|
||||
|
||||
state = {
|
||||
open: false,
|
||||
|
||||
};
|
||||
openDialog() {
|
||||
this.setState({ open: true });
|
||||
}
|
||||
|
||||
closeDialog() {
|
||||
this.setState({ open: false });
|
||||
}
|
||||
|
||||
refreshDialog() {
|
||||
this.setState({ open: false });
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Add a listener to prevent browser page refresh
|
||||
componentWillMount() {
|
||||
if (typeof window !== "undefined") {
|
||||
window.onbeforeunload = (e) => {
|
||||
console.log('Stop this');
|
||||
// this.openDialog();
|
||||
e.preventDefault()
|
||||
e.returnValue = '';
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Clear listener
|
||||
componentWillUnmount() {
|
||||
window.onbeforeunload = null
|
||||
}
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
const { classes, height} = this.props;
|
||||
|
||||
//height fixed = height 100vh
|
||||
var openStudio = this.props.openStudio ? 1 : 0;
|
||||
const content = (height == 'fixed') ? classes.content+' '+classes.contentFixed : classes.content
|
||||
return (
|
||||
<RootContainer align='center'>
|
||||
<div id="H" className={classes.head}>
|
||||
<div className={classes.inner}>
|
||||
<ButtonBase name='back'
|
||||
focusRipple
|
||||
className={classes.back}
|
||||
focusVisibleClassName={classes.focusVisible}
|
||||
|
||||
>
|
||||
<ArrowLeft color="primary" classes={{ root: classes.icon }}></ArrowLeft>
|
||||
{/* <Hidden mdUp className={classes.retour}></Hidden> */}
|
||||
<Hidden smDown className={classes.retour}>
|
||||
<div onClick={this.props.step==1 || openStudio==1 ? this.openDialog.bind(this) : () => Router.back()}>Retour</div>
|
||||
|
||||
</Hidden>
|
||||
|
||||
<Dialog open={this.state.open}>
|
||||
<DialogTitle className={classes.popup}> Souhaitez-vous poursuivre votre candidature ?</DialogTitle>
|
||||
<DialogContent className={classes.popup}> Si vous cliquez sur le bouton Supprimer, tous les éléments associés à votre candidature (vidéo, CV…) seront définitivement supprimés. </DialogContent>
|
||||
<DialogActions className={classes.popup}>
|
||||
|
||||
|
||||
<Button onClick={this.refreshDialog.bind(this)} >
|
||||
Supprimer
|
||||
</Button>
|
||||
<Button onClick={this.closeDialog.bind(this)} autoFocus>
|
||||
Poursuivre
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</ButtonBase>
|
||||
<Typography
|
||||
component="h1"
|
||||
align="center"
|
||||
className={classes.title}
|
||||
>
|
||||
{this.props.text}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<div id="C" className={content}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
|
||||
</RootContainer>
|
||||
)
|
||||
}
|
||||
}
|
||||
LayoutBack.defaultProps = {
|
||||
step: 0,
|
||||
openStudio:false
|
||||
}
|
||||
|
||||
export default withStyles(styles)(LayoutBack)
|
||||
@@ -0,0 +1,105 @@
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import Router from 'next/router';
|
||||
import RootContainer from '../atoms/RootContainer'
|
||||
import ButtonBase from "@material-ui/core/ButtonBase";
|
||||
import Close from '@material-ui/icons/Close';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
const styles = theme => ({
|
||||
inner: {
|
||||
height: '100%',
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
// boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.04), 0 1px 10px 0 rgba(0, 0, 0, 0.04), 0 3px 5px -1px rgba(0, 0, 0, 0.04)',
|
||||
backgroundColor: '#1E2327',
|
||||
right:'30px'
|
||||
},
|
||||
head: {
|
||||
zIndex: '999',
|
||||
width: '100%',
|
||||
height: '100px',
|
||||
backgroundColor: '#1E2327',
|
||||
position: 'fixed',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
height: '100px'
|
||||
}
|
||||
},
|
||||
icon: {
|
||||
fontSize: '3em',
|
||||
textAlign :'right',
|
||||
top:'30px',
|
||||
right:'30px',
|
||||
color:'#fff',
|
||||
margin:'20px'
|
||||
},
|
||||
title: {
|
||||
color: theme.palette.primary.dark,
|
||||
},
|
||||
content: {
|
||||
top: '100px',
|
||||
width: '100%',
|
||||
minHeight: '1000px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
position: 'relative',
|
||||
backgroundColor: '#1E2327',
|
||||
},
|
||||
contentFixed: {
|
||||
height: 'calc(100vh - 100px)',
|
||||
backgroundColor: '#1E2327',
|
||||
},
|
||||
back: {
|
||||
zIndex: 10,
|
||||
border: 'none',
|
||||
padding: theme.spacing(0.2),
|
||||
textAlign: 'center',
|
||||
textDecoration: 'none',
|
||||
borderRadius: '50%',
|
||||
position: 'absolute',
|
||||
right: theme.spacing(1),
|
||||
backgroundColor: '#34383C'
|
||||
},
|
||||
player: {
|
||||
background:'#1E2327'
|
||||
},
|
||||
});
|
||||
|
||||
function LayoutBack(props) {
|
||||
|
||||
const { classes, height} = props;
|
||||
|
||||
//height fixed = height 100vh
|
||||
const content = (height == 'fixed') ? classes.content+' '+classes.contentFixed : classes.content
|
||||
return (
|
||||
<RootContainer align='center' className={content}>
|
||||
<div id="H" className={classes.head}>
|
||||
<div className={classes.inner}>
|
||||
<ButtonBase name='back'
|
||||
focusRipple
|
||||
className={classes.back}
|
||||
focusVisibleClassName={classes.focusVisible}
|
||||
onClick={() => Router.push(props.url)}>
|
||||
<Close color="#fff" classes={{ root: classes.icon }}></Close>
|
||||
</ButtonBase>
|
||||
<Typography
|
||||
component="h1"
|
||||
align="center"
|
||||
className={classes.title}
|
||||
>
|
||||
{props.text}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<div id="C" className={content}>
|
||||
{props.children}
|
||||
</div>
|
||||
|
||||
</RootContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export default withStyles(styles)(LayoutBack)
|
||||
@@ -0,0 +1,120 @@
|
||||
import React, { Fragment, useState } from 'react';
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import RootContainer from '../atoms/RootContainer'
|
||||
import Header from '../organisms/Header'
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import IconAdd from '@material-ui/icons/Add';
|
||||
|
||||
import { Button } from '@material-ui/core';
|
||||
|
||||
const styles = theme => ({
|
||||
head: {
|
||||
width: '100%',
|
||||
height: '64px',
|
||||
background: theme.palette.secondary.main,
|
||||
position: 'fixed',
|
||||
zIndex: '999',
|
||||
},
|
||||
foot: {
|
||||
height: '64px',
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
boxShadow: '0px 0px 10px rgba(30, 35, 39, 0.10)',
|
||||
},
|
||||
content: {
|
||||
top: '64px',
|
||||
height: 'calc(100vh - 64px)',
|
||||
position: 'relative',
|
||||
},
|
||||
filterForm: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
backgroundColor: theme.palette.input.main,
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
width: '100% !important',
|
||||
},
|
||||
textField: {
|
||||
textAlign: 'center',
|
||||
justifyContent: 'center',
|
||||
margin: 0,
|
||||
'& input': {
|
||||
fontWeight: '300',
|
||||
color: theme.palette.primary.dark,
|
||||
backgroundColor: theme.palette.input.main,
|
||||
minWidth: '65vw',
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
paddingLeft: theme.spacing(2),
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const chatSubmit = () => {
|
||||
|
||||
}
|
||||
|
||||
function LayoutCandidature(props) {
|
||||
|
||||
const { classes, children } = props;
|
||||
const [text, setText] = useState("");
|
||||
const [displayMessageBar, toggleMessageBar] = useState(false);
|
||||
|
||||
const handleChange = (v) => {
|
||||
toggleMessageBar(v)
|
||||
}
|
||||
const toggleDisplay = (v) => {
|
||||
toggleMessageBar(v)
|
||||
}
|
||||
return (
|
||||
<RootContainer>
|
||||
<div id="H" className={classes.head}>
|
||||
<div className={classes.inner}>
|
||||
<Header searchBar={true} />
|
||||
</div>
|
||||
</div>
|
||||
<div id="C" className={classes.content}>
|
||||
{
|
||||
React.Children.map(props.children, child => {
|
||||
return React.cloneElement(child, { toggleMessageBar: handleChange });
|
||||
})
|
||||
}
|
||||
|
||||
</div>
|
||||
{displayMessageBar &&
|
||||
(<section id="F" className={classes.foot}>
|
||||
<div className={classes.filterForm}>
|
||||
<TextField
|
||||
id="standard-search"
|
||||
name="chattext"
|
||||
value={text}
|
||||
onChange={(e) => setText(e.target.value)}
|
||||
placeholder={"Message"}
|
||||
className={classes.textField}
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
// margin="dense"
|
||||
//variant="filled"
|
||||
onKeyPress={(ev) => {
|
||||
|
||||
if (ev.key === 'Enter') {
|
||||
// Do code here
|
||||
chatSubmit()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Button onClick={chatSubmit}
|
||||
variant="contained"
|
||||
className={classes.button}>
|
||||
<IconAdd />
|
||||
</Button >
|
||||
</div>
|
||||
</section>)}
|
||||
</RootContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export default withStyles(styles)(LayoutCandidature)
|
||||
@@ -0,0 +1,142 @@
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button } from '@material-ui/core';
|
||||
import Router from 'next/router';
|
||||
import RootContainer from '../atoms/RootContainer'
|
||||
import ButtonBase from "@material-ui/core/ButtonBase";
|
||||
import ArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
|
||||
import HideOnScroll from '../atoms/CollapsibleBack';
|
||||
import SocialShare from '../organisms/SocialShare'
|
||||
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
|
||||
import HeaderEntreprise from '../organisms/HeaderPersonnalise'
|
||||
import {AppBar,CssBaseline,Container,Toolbar,IconButton,Typography} from "@material-ui/core";
|
||||
import Hidden from '@material-ui/core/Hidden';
|
||||
import Link from 'next/link'
|
||||
|
||||
const styles = theme => ({
|
||||
RootContainer: {
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
maxWidth: 'inherit',
|
||||
},
|
||||
appBar: {
|
||||
backgroundColor: 'transparent',
|
||||
boxShadow: 'none',
|
||||
},
|
||||
foot: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
position: 'fixed',
|
||||
bottom: 0,
|
||||
padding: theme.spacing(1.2, 0),
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
boxShadow: '0px 0px 10px rgba(30, 35, 39, 0.10)',
|
||||
},
|
||||
content: {
|
||||
height: 'calc(100vh - 64px)',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
height: 'calc(100vh - 64px)',
|
||||
},
|
||||
position: 'relative',
|
||||
paddingBottom: '10vh',
|
||||
},
|
||||
back: {
|
||||
alignSelf: 'flex-start',
|
||||
position: 'absolute',
|
||||
zIndex: '999',
|
||||
color: 'white',
|
||||
backgroundColor: theme.palette.menu.backArrow,
|
||||
border: 'none',
|
||||
color: 'white',
|
||||
padding: theme.spacing(0.2),
|
||||
textAlign: 'center',
|
||||
textDecoration: 'none',
|
||||
display: 'inlineBlock',
|
||||
margin: theme.spacing(2),
|
||||
borderRadius: '50%',
|
||||
},
|
||||
icon: {
|
||||
fontSize: '2.5em',
|
||||
},
|
||||
rootButton: {
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.primary.important + '!important',
|
||||
},
|
||||
},
|
||||
button: {
|
||||
textTransform: 'inherit',
|
||||
marginLeft: theme.spacing(1),
|
||||
marginRight: theme.spacing(1),
|
||||
padding: theme.spacing(1.2, 2),
|
||||
color: theme.palette.secondary.main,
|
||||
backgroundColor: theme.palette.primary.important,
|
||||
textDecoration:'none',
|
||||
},
|
||||
voirOffre: {
|
||||
textTransform: 'inherit',
|
||||
marginLeft: theme.spacing(1),
|
||||
marginRight: theme.spacing(1),
|
||||
padding: theme.spacing(1.2, 2),
|
||||
color: '#BBBCBD',
|
||||
backgroundColor: '#F3F3F4',
|
||||
},
|
||||
lien:{
|
||||
textDecoration:'none',
|
||||
color:'#fff'
|
||||
},
|
||||
})
|
||||
|
||||
function LayoutCompany(props) {
|
||||
|
||||
const { classes, companyId, companyLibelle } = props;
|
||||
const socialShareUrl = typeof window !== 'undefined' ? window.location : publicRuntimeConfig.frontServerUrl + `/Entreprise/${companyId}-${_.kebabCase(companyLibelle)}`;
|
||||
return (
|
||||
|
||||
<RootContainer>
|
||||
<HeaderEntreprise retour="Entreprises" menu="Entreprises"/>
|
||||
<div id="C" className={classes.content}>
|
||||
{props.children}
|
||||
</div>
|
||||
|
||||
<Hidden mdUp>
|
||||
<div id="F" className={classes.foot}>
|
||||
<Button
|
||||
variant="contained"
|
||||
className={classes.button + ' cypButtonApply'}
|
||||
classes={{ root: classes.rootButton}}
|
||||
|
||||
>
|
||||
<a href={`/Reponse?companyId=${companyId}`} className={classes.lien }>Postuler</a>
|
||||
</Button>
|
||||
<SocialShare url={socialShareUrl} />
|
||||
{/* <Link href="#discover" >
|
||||
<Button
|
||||
variant="contained"
|
||||
className={classes.voirOffre + ' cypButtonApply'}
|
||||
>Voir les offres</Button>
|
||||
|
||||
</Link> */}
|
||||
{/* <a
|
||||
href={`/Reponse?companyId=${companyId}`}
|
||||
variant="contained"
|
||||
className={classes.button}
|
||||
classes={{ root: classes.rootButton }}
|
||||
// onClick={() => Router.push(`/Reponse?companyId=${companyId}`)}
|
||||
>
|
||||
Candidature spontanée</a> */}
|
||||
</div>
|
||||
</Hidden>
|
||||
|
||||
</RootContainer>
|
||||
|
||||
|
||||
)
|
||||
}
|
||||
LayoutCompany.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
company: PropTypes.object,
|
||||
};
|
||||
|
||||
export default withStyles(styles)(withWidth()(LayoutCompany))
|
||||
@@ -1,17 +1,15 @@
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import Header from '../organisms/Header'
|
||||
import RootContainer from '../atoms/RootContainer'
|
||||
import Footer from '../organisms/Footer';
|
||||
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
height: '100%'
|
||||
},
|
||||
head: {
|
||||
width: '100%',
|
||||
|
||||
height: '56px',
|
||||
background: 'silver',
|
||||
zIndex: '999',
|
||||
height: '64px',
|
||||
background: theme.palette.secondary.main,
|
||||
position: 'fixed',
|
||||
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
@@ -20,16 +18,17 @@ const styles = theme => ({
|
||||
|
||||
},
|
||||
content: {
|
||||
top: '56px',
|
||||
height: 'calc(100vh - 56px)',
|
||||
background: theme.palette.background.grid,
|
||||
top: '64px',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
top: '64px',
|
||||
height: 'calc(100vh - 64px)',
|
||||
},
|
||||
position: 'relative',
|
||||
overflow: 'auto',
|
||||
|
||||
}
|
||||
},
|
||||
footer: {
|
||||
marginTop: theme.spacing(10),
|
||||
},
|
||||
});
|
||||
|
||||
function LayoutGrid(props) {
|
||||
@@ -37,25 +36,28 @@ function LayoutGrid(props) {
|
||||
const { classes } = props;
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<RootContainer>
|
||||
<div id="H" className={classes.head}>
|
||||
<div className={classes.inner}>
|
||||
<Header backLink={props.backLink}/>
|
||||
<Header backLink={props.backLink} />
|
||||
</div>
|
||||
</div>
|
||||
<div id="C" className={classes.content}>
|
||||
{props.children}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="F" className={classes.footer}>
|
||||
<Footer />
|
||||
</div>
|
||||
|
||||
</RootContainer>
|
||||
)
|
||||
}
|
||||
|
||||
LayoutGrid.defaultProps = {
|
||||
backLink:"/"
|
||||
backLink: "/"
|
||||
}
|
||||
LayoutGrid.propTypes = {
|
||||
backLink : PropTypes.string
|
||||
backLink: PropTypes.string
|
||||
}
|
||||
|
||||
export default withStyles(styles)(LayoutGrid)
|
||||
@@ -1,81 +1,151 @@
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import Header from '../organisms/Header'
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button } from '@material-ui/core';
|
||||
import Router from 'next/router';
|
||||
import RootContainer from '../atoms/RootContainer'
|
||||
import ButtonBase from "@material-ui/core/ButtonBase";
|
||||
|
||||
import ArrowLeft from '@material-ui/icons/keyboardArrowLeft';
|
||||
|
||||
|
||||
import ArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
|
||||
import HeaderPersonnalise from '../organisms/HeaderPersonnalise'
|
||||
import SocialShare from '../organisms/SocialShare'
|
||||
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
|
||||
import Hidden from '@material-ui/core/Hidden';
|
||||
import Link from 'next/link'
|
||||
import getConfig from 'next/config'
|
||||
import _ from "lodash/string";
|
||||
const { publicRuntimeConfig } = getConfig()
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
height: '100%'
|
||||
},
|
||||
foot: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
|
||||
width: '100%',
|
||||
position: 'fixed',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
height: '64px'
|
||||
},
|
||||
bottom: 0,
|
||||
padding: theme.spacing(1.2, 0),
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
boxShadow: '0px 0px 10px rgba(30, 35, 39, 0.10)',
|
||||
},
|
||||
content: {
|
||||
height: 'calc(100vh - 56px)',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
height: 'calc(100vh - 64px)',
|
||||
},
|
||||
lien:{
|
||||
textDecoration:'none',
|
||||
color:'#fff'
|
||||
},
|
||||
contentDefault: {
|
||||
height: 'auto',
|
||||
position: 'relative',
|
||||
paddingBottom: '10vh',
|
||||
},
|
||||
contentProvided: {
|
||||
height: '100%',
|
||||
position: 'relative',
|
||||
overflow: 'auto',
|
||||
|
||||
},
|
||||
back:
|
||||
{
|
||||
alignSelf: 'flex-start',
|
||||
position: 'absolute',
|
||||
zIndex:10,
|
||||
color : 'white',
|
||||
backgroundColor: 'grey',
|
||||
zIndex: '999',
|
||||
color: 'white',
|
||||
backgroundColor: theme.palette.menu.backArrow,
|
||||
border: 'none',
|
||||
color: 'white',
|
||||
padding: '10px',
|
||||
padding: theme.spacing(0.2),
|
||||
textAlign: 'center',
|
||||
textDecoration: 'none',
|
||||
display: 'inlineBlock',
|
||||
fontSize: '38px',
|
||||
margin:' 10px 16px',
|
||||
margin: theme.spacing(2),
|
||||
borderRadius: '50%',
|
||||
}
|
||||
},
|
||||
icon: {
|
||||
fontSize: '2.5em',
|
||||
},
|
||||
rootButton: {
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.primary.important + '!important',
|
||||
},
|
||||
},
|
||||
button: {
|
||||
textTransform: 'inherit',
|
||||
marginLeft: theme.spacing(4.5),
|
||||
marginRight: theme.spacing(4.5),
|
||||
padding: theme.spacing(1.2, 2),
|
||||
color: theme.palette.secondary.main,
|
||||
backgroundColor: theme.palette.primary.important,
|
||||
},
|
||||
voirEntreprise: {
|
||||
textTransform: 'inherit',
|
||||
marginLeft: theme.spacing(1),
|
||||
marginRight: theme.spacing(1),
|
||||
padding: theme.spacing(1.2, 2),
|
||||
color: '#BBBCBD',
|
||||
backgroundColor: '#F3F3F4',
|
||||
|
||||
},
|
||||
pourvuButton:{
|
||||
padding :'10px',
|
||||
textTransform: 'inherit',
|
||||
},
|
||||
})
|
||||
|
||||
function Layout(props) {
|
||||
|
||||
const { classes } = props;
|
||||
function LayoutOffre(props) {
|
||||
|
||||
const { classes, offreId, offre, isProvided } = props;
|
||||
const contentClass = (!isProvided) ? classes.contentDefault : classes.contentProvided
|
||||
const socialShareUrl = typeof window !== 'undefined' ? window.location : publicRuntimeConfig.frontServerUrl + `/Offre/${offreId}-${_.kebabCase(offre.title)}`;
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<ButtonBase name='back'
|
||||
focusRipple
|
||||
className={classes.back}
|
||||
focusVisibleClassName={classes.focusVisible}
|
||||
|
||||
onClick={() => Router.back()}>
|
||||
<ArrowLeft></ArrowLeft>
|
||||
</ButtonBase>
|
||||
<div id="C" className={classes.content}>
|
||||
<RootContainer>
|
||||
|
||||
<HeaderPersonnalise retour="Offres" menu="Offres d'emploi"/>
|
||||
|
||||
<div id="C" className={contentClass}>
|
||||
{props.children}
|
||||
</div>
|
||||
<div id="F" className={classes.foot}>
|
||||
{/* <div className={classes.inner}>
|
||||
<div className={classes.grow} /> */}
|
||||
<Button variant="outlined" color="secondary" >Postuler</Button>
|
||||
{/* <div className={classes.grow} />
|
||||
</div> */}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<Hidden mdUp>
|
||||
{!isProvided && (
|
||||
<div id="F" className={classes.foot}>
|
||||
{/* <div className={classes.inner}>
|
||||
<div className={classes.grow} /> */}
|
||||
{/* <Link href={`/Entreprise/${offre.company.id}-${_.kebabCase(offre.company.brand_name)}`} >
|
||||
<Button
|
||||
variant="contained"
|
||||
className={classes.voirEntreprise + ' cypButtonApply'}
|
||||
>Voir l'entreprise</Button>
|
||||
</Link> */}
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
className={classes.button + ' cypButtonApply'}
|
||||
classes={{ root: classes.rootButton}}
|
||||
|
||||
>
|
||||
<a href={`/Reponse?adId=${offreId}`} className={classes.lien }>Postuler</a>
|
||||
</Button>
|
||||
<SocialShare url={socialShareUrl} />
|
||||
|
||||
{/* <div className={classes.grow} />
|
||||
</div> */}
|
||||
</div>
|
||||
)}
|
||||
{isProvided && (
|
||||
<div id="F" className={classes.foot}>
|
||||
{/* <div className={classes.inner}>
|
||||
<div className={classes.grow} /> */}
|
||||
|
||||
|
||||
<Button variant="contained" disabled className={classes.pourvuButton}>
|
||||
Offre pourvue
|
||||
</Button>
|
||||
{/* <div className={classes.grow} />
|
||||
</div> */}
|
||||
</div>
|
||||
)}
|
||||
</Hidden>
|
||||
|
||||
</RootContainer>
|
||||
)
|
||||
}
|
||||
LayoutOffre.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
offre: PropTypes.object,
|
||||
};
|
||||
|
||||
export default withStyles(styles)(Layout)
|
||||
export default withStyles(styles)(LayoutOffre)
|
||||
@@ -1,101 +1,29 @@
|
||||
import React from 'react'
|
||||
import React, { Fragment } from 'react'
|
||||
import CircularProgress from '@material-ui/core/CircularProgress'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
const styles = theme => ({
|
||||
loader: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
textAlign: 'center',
|
||||
justifyContent: 'center',
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
fontWeight: '500',
|
||||
fontSize: '1em',
|
||||
padding: theme.spacing(6,0),
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
})
|
||||
|
||||
export default class extends React.Component {
|
||||
class Loader extends React.Component {
|
||||
render() {
|
||||
if (this.props.fullscreen) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<style jsx global>{`
|
||||
.circle-loader {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 50%;
|
||||
z-index: 100;
|
||||
text-align: center;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<div className={classes.loader + ' ' + 'alert alert-info'}><CircularProgress color="primary" />Chargement... </div>
|
||||
)
|
||||
|
||||
.circle-loader .circle {
|
||||
fill: transparent;
|
||||
stroke: rgba(0,0,0,0.2);
|
||||
stroke-width: 4px;
|
||||
animation: dash 2s ease infinite, rotate 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes dash {
|
||||
0% {
|
||||
stroke-dasharray: 1,95;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
50% {
|
||||
stroke-dasharray: 85,95;
|
||||
stroke-dashoffset: -25;
|
||||
}
|
||||
100% {
|
||||
stroke-dasharray: 85,95;
|
||||
stroke-dashoffset: -93;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
0% {transform: rotate(0deg); }
|
||||
100% {transform: rotate(360deg); }
|
||||
}
|
||||
`}</style>
|
||||
<span className="circle-loader">
|
||||
<svg className="circle" width="60" height="60" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="30" cy="30" r="15"/>
|
||||
</svg>
|
||||
</span>
|
||||
</React.Fragment>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<style jsx global>{`
|
||||
.circle-loader {
|
||||
display: block;
|
||||
text-center;
|
||||
padding-left: 50%;
|
||||
}
|
||||
|
||||
.circle-loader .circle {
|
||||
position: relative;
|
||||
left: -30px;
|
||||
fill: transparent;
|
||||
stroke: rgba(0,0,0,0.2);
|
||||
stroke-width: 4px;
|
||||
animation: dash 2s ease infinite, rotate 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes dash {
|
||||
0% {
|
||||
stroke-dasharray: 1,95;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
50% {
|
||||
stroke-dasharray: 85,95;
|
||||
stroke-dashoffset: -25;
|
||||
}
|
||||
100% {
|
||||
stroke-dasharray: 85,95;
|
||||
stroke-dashoffset: -93;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
0% {transform: rotate(0deg); }
|
||||
100% {transform: rotate(360deg); }
|
||||
}
|
||||
`}</style>
|
||||
<span className="circle-loader">
|
||||
<svg className="circle" width="60" height="60" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="30" cy="30" r="15"/>
|
||||
</svg>
|
||||
</span>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(Loader)
|
||||
@@ -0,0 +1,55 @@
|
||||
import React, { Fragment } from 'react'
|
||||
import CircularProgress from '@material-ui/core/CircularProgress'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import LinearProgress from '@material-ui/core/LinearProgress';
|
||||
const styles = theme => ({
|
||||
loader: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
textAlign: 'center',
|
||||
justifyContent: 'center',
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
fontWeight: '500',
|
||||
fontSize: '1em',
|
||||
padding: theme.spacing(6,0),
|
||||
margin:'50px 0',
|
||||
},
|
||||
loaderGras:{
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
paddingTop:'10px',
|
||||
fontSize: '1.875em',
|
||||
fontWeight: '500',
|
||||
marginBottom:'30px',
|
||||
|
||||
},
|
||||
loaderSecondaire:{
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
|
||||
fontSize: '1em',
|
||||
fontWeight: '300',
|
||||
},
|
||||
root: {
|
||||
top:"200px",
|
||||
width: '100%',
|
||||
'& > * + *': {
|
||||
marginTop: theme.spacing(2),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
class LoaderVideo extends React.Component {
|
||||
render() {
|
||||
const { classes, textePrincipal, texteSecondaire } = this.props;
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<div className={classes.loader }><CircularProgress color="primary" /><span className={classes.loaderGras }>{textePrincipal}</span><br/><span className={classes.loaderSecondaire }> {texteSecondaire}</span><br/></div>
|
||||
<div >
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(LoaderVideo)
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:8000/",
|
||||
"env":{
|
||||
"nom":"toto",
|
||||
"prenom": "toto",
|
||||
"email":"thomasberrodedeclic42@gmail.com",
|
||||
"password": "123456"
|
||||
},
|
||||
"chromeWebSecurity": false
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,28 @@
|
||||
|
||||
|
||||
describe('RegisterTest', function() {
|
||||
before(function(){
|
||||
|
||||
cy.exec('yarn dropAndCreateDB',{failOnNonZeroExit: false});
|
||||
})
|
||||
it('Test if Register works', function() {
|
||||
cy.viewport(375, 667)
|
||||
cy.visit('/')
|
||||
cy.get('.cypConnexionMenu').click()
|
||||
cy.get('.cypRegister').click({ force: true })
|
||||
cy.url().should('contain', 'Login')
|
||||
cy.get('#nom').type(Cypress.env('nom'))
|
||||
cy.get('#prenom').type(Cypress.env('prenom'))
|
||||
cy.get('#emailRegister').type(Cypress.env('email'))
|
||||
cy.get('#adornment-password').type(Cypress.env('password'))
|
||||
cy.get('#cypCheckboxRegister').check()
|
||||
cy.get('.cypButtonRegister').click().wait(3000)
|
||||
cy.url().should('contain','VerifyEmail')
|
||||
cy.get('span').should('contain',Cypress.env('email'))
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
|
||||
// describe('ConfirmMailTest', function() {
|
||||
// it("Register Form: Email is delievered", function() {
|
||||
// const incoming_mailbox = `thomasberrodedeclic42@gmail.com`;
|
||||
// cy
|
||||
// .task("gmail:check", {
|
||||
// from: "noreply@talentstube.com",
|
||||
// to: incoming_mailbox,
|
||||
// subject: `Bienve nue ${incoming_mailbox} 🔑`
|
||||
// })
|
||||
// .then(email => {
|
||||
// assert.isNotNull(email, `Email was not found`);
|
||||
// });
|
||||
// });
|
||||
// })
|
||||
|
||||
describe("Email assertion:", () => {
|
||||
it("Look for an email with specific subject and link in email body", function() {
|
||||
// debugger; //Uncomment for debugger to work...
|
||||
cy.wait(5000)
|
||||
cy
|
||||
.task("gmail:get-messages", {
|
||||
options: {
|
||||
include_body: true,
|
||||
}
|
||||
})
|
||||
.then(emails => {
|
||||
const found_email = emails.find(email => {
|
||||
return (
|
||||
email.from.indexOf("noreply@talentstube.com") >= 0 &&
|
||||
email.subject.indexOf("Bienvenue thomasberrodedeclic42@gmail.com 🔑") >= 0
|
||||
);
|
||||
});
|
||||
assert.isNotNull(found_email, "Found email👍");
|
||||
const body = found_email.body.text;
|
||||
assert.isTrue(
|
||||
body.indexOf(
|
||||
"http://localhost:8000/ConfirmAccount/"
|
||||
) >= 0,
|
||||
"Found reset link👍"
|
||||
);
|
||||
|
||||
var startUrl = body.indexOf("http://");
|
||||
var endUrl = body.indexOf("*");
|
||||
var link = body.substring(startUrl, endUrl);
|
||||
|
||||
cy.visit(link);
|
||||
|
||||
|
||||
cy.get('p').should('contain','e-mail validé')
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
describe('Visit the whole site as anonymous', function() {
|
||||
it('visit the whole site to see if errors', function() {
|
||||
|
||||
cy.viewport(375, 667)
|
||||
|
||||
//Page d'accueil
|
||||
cy.visit('/')
|
||||
cy.get('p').should('contain', 'à la une')
|
||||
cy.get('.cypConnexionMenu').click()
|
||||
cy.get('span').should('contain', 'Connexion')
|
||||
cy.get('body').click('left')
|
||||
cy.get('button').first().click()
|
||||
cy.get('span').should('contain', 'Accueil')
|
||||
|
||||
//Page de Login
|
||||
cy.visit('/Login')
|
||||
cy.get('.cypButtonConnexion').should('exist')
|
||||
cy.get('.cypLinkedInConnexion').should('exist')
|
||||
|
||||
//Page d'offre(s)
|
||||
cy.visit('/Offres')
|
||||
cy.get('h1').should('contain', 'offres d\'emploi vidéo en cours')
|
||||
cy.get('.cypCardOffre').first().click()
|
||||
cy.get('.cypButtonApply').should('exist')
|
||||
cy.get('p').should('contain','Détails de l\'offre d\'emploi')
|
||||
cy.get('.player').should('exist')
|
||||
|
||||
//Page des entreprises
|
||||
cy.visit('/Entreprises')
|
||||
cy.get('.cypCardCompany').last().click()//could use .eq(2) instead of .last()
|
||||
cy.get('.player').should('exist')
|
||||
|
||||
//Help
|
||||
cy.visit('/Help')
|
||||
cy.get('h1').should('contain','Comment ça marche')
|
||||
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,13 @@
|
||||
describe('Wrong Login Test', function() {
|
||||
it('Teste la connexion d\'un utilisateur', function() {
|
||||
cy.viewport(375, 667)
|
||||
cy.visit('/')
|
||||
cy.get('.cypConnexionMenu').click()
|
||||
cy.get('.cypConnexion').click({ force: true })
|
||||
cy.url().should('contain', 'Login')
|
||||
cy.get('.cypInputEmail input').type('wrongmail@wrong.fr')
|
||||
cy.get('.cypInputPassword input').type('wrongpassword')
|
||||
cy.get('.cypButtonConnexion').click()
|
||||
cy.get('#client-snackbar').should('contain','Mauvais identifiants')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,31 @@
|
||||
describe('Apply to an offer', function() {
|
||||
it('Go to an offer and apply to it', function() {
|
||||
|
||||
cy.viewport(375, 667)
|
||||
cy.visit('/')
|
||||
|
||||
cy.get('.cypConnexionMenu').click()
|
||||
cy.get('.cypConnexion').click({ force: true })
|
||||
cy.url().should('contain', 'Login')
|
||||
cy.get('.cypInputEmail input').type(Cypress.env('email'))
|
||||
cy.get('.cypInputPassword input').type(Cypress.env('password'))
|
||||
cy.get('.cypButtonConnexion').click().wait(3000)
|
||||
|
||||
|
||||
cy.get('.cypButtonOffers').click().wait(3000)
|
||||
cy.url().should('contain', 'Offres')
|
||||
cy.get('.cypCardOffre').first().click().wait(3000)
|
||||
cy.url().should('contain', 'Offre')
|
||||
cy.get('.cypButtonApply').first().click().wait(3000)
|
||||
cy.url().should('contain', 'Reponse')
|
||||
|
||||
cy.fixture('cypVid.mov', 'base64').then(fileContent => {
|
||||
cy.get('.cypButtonImportVid').invoke('show').upload(
|
||||
{ fileContent, fileName: 'cypVid.mov', mimeType: 'video/quicktime', encoding: 'base64' },
|
||||
{ subjectType: 'input', force: true }
|
||||
)}).wait(3000)
|
||||
cy.get('.cypButtonSendApplication').click().wait(3000)
|
||||
})
|
||||
|
||||
//Should verify if application is received
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
describe('ConnexionTest', function() {
|
||||
it('Test login', function() {
|
||||
cy.viewport(375, 667)
|
||||
cy.visit('/')
|
||||
cy.get('.cypConnexionMenu').click()
|
||||
cy.get('.cypConnexion').click({ force: true })
|
||||
cy.url().should('contain', 'Login')
|
||||
cy.get('.cypInputEmail input').type(Cypress.env('email'))
|
||||
cy.get('.cypInputPassword input').type(Cypress.env('password'))
|
||||
cy.get('.cypButtonConnexion').click().wait(3000)
|
||||
cy.get('.cypConnexionMenu').click()
|
||||
cy.get('h3').should('contain', Cypress.env('email') )
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,17 @@
|
||||
describe('VisitAsUser', function() {
|
||||
it('Test if user can access to his pages', function() {
|
||||
cy.viewport(375, 667)
|
||||
cy.visit('/')
|
||||
cy.get('.cypConnexionMenu').click()
|
||||
cy.get('.cypConnexion').click({ force: true })
|
||||
cy.url().should('contain', 'Login')
|
||||
cy.get('.cypInputEmail input').type(Cypress.env('email'))
|
||||
cy.get('.cypInputPassword input').type(Cypress.env('password'))
|
||||
cy.get('.cypButtonConnexion').click().wait(3000)
|
||||
|
||||
cy.visit('/Candidatures')
|
||||
|
||||
|
||||
// cy.get('h1').should('contain', Cypress.env('Mes candidatures') )
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,17 @@
|
||||
describe('test_name', function() {
|
||||
|
||||
it('what_it_does', function() {
|
||||
|
||||
cy.viewport(1536, 674)
|
||||
|
||||
cy.visit('http://localhost:8000/')
|
||||
|
||||
cy.get('.MuiList-root > div > .jss56:nth-child(1) > .MuiListItemText-root > .MuiTypography-root').click()
|
||||
|
||||
cy.get('.MuiList-root > div > .jss56:nth-child(2) > .MuiListItemText-root > .MuiTypography-root').click()
|
||||
|
||||
cy.get('.MuiList-root > div > .jss56:nth-child(3) > .MuiListItemText-root > .MuiTypography-root').click()
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
@@ -0,0 +1 @@
|
||||
{"installed":{"client_id":"438657734125-poo68tqp3dosq2od8udgipdqietbav0d.apps.googleusercontent.com","project_id":"tt-app-251309","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"m_zcFplh1LZlMHl6bwkBBFl8","redirect_uris":["http://localhost"],"javascript_origins":["http://localhost"]}}
|
||||
@@ -0,0 +1 @@
|
||||
{"access_token":"ya29.Glt0B7O-MEh7BOQ6yJyZY1628D2mH1lbVz7LaJfiUgKJJv5mt1DljeQsZU49z-5F9GYsWVn0E5ylYj2yWuGLGb2J0sZJjVUWMLYn333dRbk-0469E08Hmc3GkIOO","refresh_token":"1/42U4Ny2XVLbf3D3xO4S2bwyyX183RuqQ2kcBmND7hpr5japueYf6psdLEWzIFfCx","scope":"https://www.googleapis.com/auth/gmail.readonly","token_type":"Bearer","expiry_date":1567156006741}
|
||||
@@ -0,0 +1,52 @@
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
const gmail = require("gmail-tester");
|
||||
const path = require("path");
|
||||
module.exports = (on, config) => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
on("before:browser:launch", (browser = {}, args) => {
|
||||
if (browser.name === "chrome") {
|
||||
args.push("--remote-debugging-port=9221");
|
||||
return args;
|
||||
}
|
||||
});
|
||||
|
||||
// on("task", {
|
||||
// "gmail:check": async args => {
|
||||
// const { from, to, subject } = args;
|
||||
// const email = await gmail.check_inbox(
|
||||
// path.resolve(__dirname, "credentials.json"), // credentials.json is inside plugins/ directory.
|
||||
// path.resolve(__dirname, "gmail_token.json"), // gmail_token.json is inside plugins/ directory.
|
||||
// subject,
|
||||
// from,
|
||||
// to,
|
||||
// 10, // Poll interval (in seconds)
|
||||
// 30 // Maximum poll interval (in seconds). If reached, return null, indicating the completion of the task().
|
||||
// );
|
||||
// return email;
|
||||
// }
|
||||
// });
|
||||
|
||||
on("task", {
|
||||
"gmail:get-messages": async args => {
|
||||
const messages = await gmail.get_messages(
|
||||
path.resolve(__dirname, "credentials.json"),
|
||||
path.resolve(__dirname, "gmail_token.json"),
|
||||
args.options
|
||||
);
|
||||
return messages;
|
||||
}
|
||||
});
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
|
After Width: | Height: | Size: 140 KiB |
@@ -0,0 +1,46 @@
|
||||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add("login", (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||
|
||||
import 'cypress-file-upload';
|
||||
|
||||
Cypress.Commands.add('login', () => {
|
||||
cy.viewport(375, 667)
|
||||
cy.visit('/')
|
||||
cy.request({
|
||||
method: 'POST',
|
||||
url: 'http://localhost/api/login_check',
|
||||
body: {
|
||||
|
||||
username: 'cypress.tt.edeclic@gmail.com',
|
||||
password: 'qJxY4kovD13W'
|
||||
|
||||
}
|
||||
})
|
||||
.then((resp) => {
|
||||
window.localStorage.setItem('ttJWT', resp.body.token)
|
||||
})
|
||||
|
||||
})
|
||||
@@ -0,0 +1,31 @@
|
||||
// ***********************************************************
|
||||
// This example support/index.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
|
||||
// before(() => {
|
||||
// cy.exec('yarn dropAndCreateDB');
|
||||
// })
|
||||
|
||||
Cypress.on('uncaught:exception', (err, runnable) => {
|
||||
// returning false here prevents Cypress from
|
||||
// failing the test
|
||||
return false
|
||||
})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user