Compare commits

...

793 Commits

Author SHA1 Message Date
llaniau 8be4c6d08c Image page accueil 2021-03-09 12:30:53 +01:00
llaniau b519451a0c page accueil 2021-03-09 12:25:46 +01:00
llaniau 04d03aa736 page accueil web app 2021-03-08 19:43:14 +01:00
llaniau c71fe2b452 Inscription tel 2021-02-24 15:41:44 +01:00
llaniau ee45ef810b Correction de bugs 2021-02-24 14:01:30 +01:00
llaniau 63bd801281 retour de recette et page accueil 2021-02-22 18:01:33 +01:00
llaniau ddb1abbe70 sitemap 2021-02-18 14:00:35 +01:00
llaniau e7b9298a3b Param pre prod 2021-02-16 17:18:58 +01:00
llaniau ea69a5f308 Nouvelle page accueil redirect 2021-02-16 17:14:19 +01:00
llaniau 8fe612824b referencement , fonts 2021-02-15 18:17:04 +01:00
llaniau e02f90634b sitemap 2021-02-11 14:10:41 +01:00
llaniau c9284e800a sous titre 2021-02-11 10:24:49 +01:00
llaniau 3e26ba8bca MEP V2.6.2 2021-02-10 16:28:54 +01:00
llaniau f53743a03e Version V2.6.2 2021-02-10 15:15:21 +01:00
llaniau d90682c710 Referencement player 2021-02-10 15:03:31 +01:00
llaniau 5456dfd4c4 Optimisation referencement + geoloc 2021-02-08 09:14:31 +01:00
llaniau df81b18194 async defer 2021-02-02 08:37:21 +01:00
llaniau ed9bfff65d Optimisation referencement (typo, et async) 2021-02-02 08:37:05 +01:00
llaniau 39d29567ce Optimisation referencement 2021-02-01 22:38:27 +01:00
llaniau 10897f633d siteMap optimisé 2021-01-24 20:01:23 +01:00
llaniau 41916bc451 sitempa et robots.txt 2021-01-24 12:40:38 +01:00
llaniau 06e6b615b1 MEP V2.5.4 2021-01-21 14:46:23 +01:00
llaniau ce95cb2d66 Ne pas afficher champ geoloc 2021-01-21 13:44:28 +01:00
llaniau fe1747ea90 version V2.5.4 2021-01-20 18:17:32 +01:00
llaniau f6edb107b2 retour recette Corentin 2021-01-20 18:15:39 +01:00
llaniau 28ae59b7e4 lmodif taille image mini 2021-01-20 11:30:14 +01:00
llaniau 65b6a9b9dc Reglage partage facebook 2021-01-20 11:24:46 +01:00
llaniau d0ce6516dc Og head partage image 2021-01-20 11:03:58 +01:00
llaniau 12c3b2e1cd version 2.5.2 2021-01-20 10:21:41 +01:00
llaniau 3fc5bc6424 non referencement test4 2021-01-19 19:39:17 +01:00
llaniau f0fe21a14e Layoutback 2021-01-19 16:28:38 +01:00
llaniau 9c19993bcc Bug Og suite retour pre prod 2021-01-19 15:59:19 +01:00
llaniau 00fdb164af bug og entreprise 2021-01-18 17:33:14 +01:00
llaniau 6e6ac8e440 Correction OgHead 2021-01-18 17:25:43 +01:00
llaniau 8259112aac Bug og suite 2021-01-18 16:10:26 +01:00
llaniau b0f66eb9fd Changement _document.js pour mettre un og par def 2021-01-18 11:12:49 +01:00
llaniau c08f3db680 bug og suite 2021-01-18 10:33:33 +01:00
llaniau de1a56285d Bug og suite 2021-01-18 10:30:23 +01:00
llaniau 1e78256886 Bug Og 2021-01-18 10:20:08 +01:00
llaniau 37c54c4dd0 Pb og facebook sur image 2021-01-18 10:15:07 +01:00
llaniau 21c61e6128 OgHead en haut 2021-01-18 10:03:11 +01:00
llaniau 32e3826c27 facebook id pour poartage og 2021-01-18 09:58:56 +01:00
llaniau 9d647525b3 Mise en place dev@talentstube.com 2021-01-18 09:43:57 +01:00
llaniau ed19b99bba US482.488 Permettre aux d'envoyer plusieurs videos 2021-01-14 17:02:31 +01:00
llaniau 9c38c8c03d Mise en place de stats 2021-01-13 17:28:54 +01:00
llaniau f200235ced LayoutBack avec popup 2021-01-12 18:50:33 +01:00
llaniau 92a93452bb US451 : Chgt mise en page sticky 2021-01-11 15:56:43 +01:00
llaniau 5626e2d592 US451 : refonte page entreprise 2021-01-06 17:25:30 +01:00
llaniau a52c855ec2 Init V2.5.1 2021-01-06 13:39:42 +01:00
llaniau 16e5218f16 MEP V2.5.0 2021-01-05 17:52:08 +01:00
llaniau 68e5abb088 Bug sur le cv papier 2021-01-05 13:37:09 +01:00
llaniau b52f05002b Bug cv papier 2021-01-04 18:13:23 +01:00
llaniau e1bb5de959 Bug reducer Media mediaCv 2021-01-04 17:56:23 +01:00
llaniau aaf1226ea0 US 430 : refonte parcours talent 2021-01-04 14:07:50 +01:00
llaniau e06cb60bfb Parcours talents avec Cv papier en etape2 2020-12-30 17:06:09 +01:00
llaniau 11eedf3a8b Modif du mail d'inscription 2020-12-29 09:54:13 +01:00
llaniau f9a8b598da Bug chromebook 2020-12-29 09:09:54 +01:00
llaniau b488e3399c Envoi mail template mailjet 2020-12-28 16:29:18 +01:00
llaniau c82cd3be1e Envoi contact liste mailjet 2020-12-28 16:28:36 +01:00
llaniau fed0d99e64 Envoi contact dans liste mailjet 2020-12-28 16:28:13 +01:00
llaniau 24e05ff7fc version pre prod 2020-12-24 10:20:37 +01:00
llaniau 9af90d3fd0 Bug65, 152,165,140 2020-12-24 10:06:14 +01:00
llaniau 0b3d5c9ebb Bug 169 sur les candidatures spontanées 2020-12-21 10:06:44 +01:00
llaniau c3f4832b30 Packaging MEP V2.4.0 2020-12-15 13:32:35 +01:00
llaniau 4bd6e8c580 Probleme confirmAccount 2020-12-15 10:15:56 +01:00
llaniau 8e896114bf changement de version dans next config 2020-12-15 09:09:23 +01:00
llaniau f757997392 Retour recette Audrey Corentin 2020-12-14 18:17:42 +01:00
llaniau 67b3c97806 no follow 2020-12-13 23:47:51 +01:00
llaniau ee636e27ff US 238 : Mise en place de la version 2020-12-11 16:14:48 +01:00
llaniau ff5055c411 US 435 et 355 sur le module webRTC new look 2020-12-11 15:34:22 +01:00
llaniau d5b1fcd74a Reglage mise en page Offre emploi 2020-12-10 17:31:58 +01:00
llaniau 5ace82986f US 443: Stocker id annonce dans le mail 2020-12-10 16:57:22 +01:00
llaniau c989b6ddfe Point mise en page Corentin 2020-12-10 16:52:29 +01:00
llaniau f3f94e9b51 Navigation intelligente lors du login 2020-12-09 14:08:35 +01:00
llaniau 6c34cad1e7 Social Share 2020-12-03 16:43:29 +01:00
llaniau cb5268bf27 Header maj 2020-12-03 16:20:51 +01:00
llaniau 7b77b2195d US403, US413, US404 2020-12-03 16:17:52 +01:00
llaniau dad7e6b2eb US 420,412,421,414 2020-12-02 16:40:57 +01:00
llaniau 146d1a5061 Mise en place du nouveau parcours talent 2020-12-01 19:21:23 +01:00
llaniau ed626137cf Correction entreprise rattaché à territoir en prod 2020-12-01 11:23:22 +01:00
llaniau 224cedac65 Bug video territoire 2020-11-26 15:03:54 +01:00
llaniau b5b41b4849 next.config.js en mode prod 2020-11-25 09:14:32 +01:00
llaniau d1ee296684 Pour mise en prod, balise nofolow 2020-11-24 13:55:54 +01:00
llaniau 6cf3bcc658 Forcage web app 2020-11-24 11:48:29 +01:00
llaniau b20efef730 Tel + collapse 2020-11-17 17:40:27 +01:00
llaniau 459ff88e9d Correction navigation 2020-10-28 17:06:53 +01:00
llaniau dcdbfed2a3 Garder historique des pages de recherche 2020-10-27 18:23:34 +01:00
llaniau d235b08fe3 Mise en place du lazy 2020-10-22 17:27:28 +02:00
llaniau e5b9f2b75d Nofollow pour pre prod 2020-10-20 09:17:21 +02:00
llaniau 563107e649 Modif mise en page diverses 2020-10-20 09:14:13 +02:00
llaniau 5545dbfad0 Modif next.config.js 2020-10-20 08:50:47 +02:00
llaniau 353128fa8e Suppression balise meta pour mise en prod 2020-10-15 15:12:07 +02:00
llaniau 2e9fa7e9d0 Corrections mineures 2020-10-15 14:45:36 +02:00
llaniau c0e5ec6e90 Test api pole emploi 2020-10-14 17:36:43 +02:00
llaniau 33adc4c819 oghead 2020-10-13 17:24:48 +02:00
llaniau ebe81cd588 Mise en place de googgle place 2020-10-12 18:28:03 +02:00
llaniau c3ced21cce US466 : Chgt postuler en envoyer sa candidature 2020-10-07 16:16:00 +02:00
llaniau a156050184 Import icon watch later 2020-10-05 23:05:23 +02:00
llaniau 535069bb64 Texte temp de travail en francais 2020-10-05 18:06:39 +02:00
llaniau e4603f4ca8 Amélioration employmentType 2020-10-05 17:53:58 +02:00
llaniau cab481cd2f Amélioration job posting 2020-10-05 17:21:00 +02:00
llaniau 34d1384fb7 Job Posting ajout dept, ville, ... 2020-10-05 14:05:16 +02:00
llaniau 4b2fabd4b4 Amelioration Parcours talent 2020-10-01 17:01:06 +02:00
llaniau 130fb89c5f Modif applicationServerPublicKey pour pre prod 2020-09-29 14:12:07 +02:00
llaniau eeee4d3f45 changement next.config.js pour pre prod 2020-09-29 14:08:18 +02:00
llaniau 7f2c8374a4 Video de pres (module video telephone) 2020-09-29 09:59:22 +02:00
llaniau e380dec152 Envoi message apres candidature 2020-09-24 17:10:25 +02:00
llaniau 58bf654651 applicationServerPublicKey de prod 2020-09-22 15:15:07 +02:00
llaniau ead5370495 Modif pour eviter cvtheque.talentstube.com 2020-09-22 15:12:08 +02:00
llaniau ce8f8660f3 modif title offre pour referencement 2020-09-21 18:16:32 +02:00
llaniau 28fbf3a013 lien espace recruteur 2020-09-21 16:31:16 +02:00
llaniau 726cd78bd3 MEP 21 sept 2020-09-21 16:08:41 +02:00
llaniau 70a0e47d28 Version stabilisé pre prod avant mise en prod 2020-09-21 15:51:54 +02:00
llaniau d338cfaad4 recette avant mise en prod 2020-09-21 13:16:26 +02:00
llaniau 1815b2834e Modif Tel francais 2020-09-20 21:02:02 +02:00
llaniau 27ac00bafb Modif suite recette 18_09 2020-09-19 11:46:12 +02:00
llaniau 6a7024d5ac Suppression bouton connexion linkedin et fb 2020-09-17 16:36:10 +02:00
llaniau 485ccece1e Modif ref 2020-09-16 18:06:22 +02:00
llaniau 1fd45a00a3 Referencement Offre et Modif profil 2020-09-16 11:49:04 +02:00
llaniau 36571b5cca suppresion ville dans url Entreprise 2020-09-15 17:49:20 +02:00
llaniau 7ad96db928 maj referencement 2020-09-15 17:43:34 +02:00
llaniau 5ce9f108cd changement d email de ref 2020-09-15 14:11:44 +02:00
llaniau 99bb737647 changement page contact (blog) 2020-09-15 12:43:27 +02:00
llaniau e2ef540aac Modif adblock maj de ads->jobs 2020-09-15 11:46:21 +02:00
llaniau 6e6119ffaf Correction recette avant MEP sept 2020 2020-09-15 10:53:40 +02:00
llaniau 473edf7472 Ajout Etape CV apres candidature 2020-09-14 18:26:04 +02:00
llaniau 96b08352a0 Minheight à 200px sur les offres pour les écrans mac 2020-09-09 17:09:37 +02:00
llaniau 7a45d19d2b Amelioration parcours talent 2020-09-08 17:37:18 +02:00
llaniau c73b08c1aa referencement 2020-09-07 18:44:54 +02:00
llaniau b6e4347abb Mise a jour Borganisation cliente 2020-09-07 15:58:55 +02:00
llaniau adb9d2ccde Changement de la page Help pour intéger les pages comment faire un cv video 2020-09-03 17:35:11 +02:00
llaniau edd7f705ab Cv video detachement 2020-09-02 18:39:08 +02:00
llaniau ea372ba0f2 AccountEtape3 modif du lien Front 2020-09-02 08:53:53 +02:00
llaniau 779b722662 bug requete offre 2020-08-24 18:29:00 +02:00
llaniau 6bb8baf636 variablisation url symfony 2020-08-20 17:40:42 +02:00
llaniau 083f7b9c16 cas cabinet recrutement (champ entreprise) 2020-08-18 18:15:31 +02:00
llaniau 0eed896aec next config 2020-08-18 10:40:41 +02:00
llaniau e8ae224414 VARIABILISATION DES URL EN DUR (CHANGEMENT DE NOM DE DOMAINE) 2020-08-17 11:28:32 +02:00
llaniau fa3dcd8fd2 suppression d'un attribut (job) pour jobposting 2020-08-13 18:14:56 +02:00
llaniau 2c0c0a2632 Mise en place Job Posting 2020-08-13 17:12:45 +02:00
llaniau 501ee57430 referencement index.js 2020-08-13 12:43:28 +02:00
llaniau 0f6ec17fef OgHead 2020-08-13 11:40:03 +02:00
llaniau 112541275b Modif Referencement 2020-08-13 11:36:41 +02:00
llaniau e08b879691 gestion adresse json webapp 2020-08-12 15:43:53 +02:00
llaniau 527351c232 video de pres Web app V2 2020-08-11 17:30:55 +02:00
llaniau 0ed8da11e1 package.json 2020-07-22 12:11:35 +02:00
llaniau f522e4389e bug 2020-07-22 11:55:33 +02:00
llaniau efb6527b9b v2.0.1 2020-07-22 08:23:55 +02:00
llaniau ba43bcddc7 mise en place modif profile 2020-07-20 14:38:00 +02:00
llaniau 3523cc95ee Design update profile et video 2020-07-16 17:10:27 +02:00
llaniau c0d32cee12 Mise en place uplaod cv papier 2020-07-15 16:05:33 +02:00
llaniau 3b6aa331db after merge 2020-07-09 15:27:59 +02:00
llaniau fe7932e5ae commit 2020-07-09 15:20:43 +02:00
llaniau 05b64ac44c Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2020-07-09 15:18:57 +02:00
llaniau 446e13ceba Enregistrement video APP V2 2020-07-09 14:54:55 +02:00
llaniau 6570e28bbd Mise en place upload video presentation cote react/nextjs 2020-07-08 19:52:04 +02:00
llaniau d146da7ab3 package.json de V2 2020-07-07 18:00:00 +02:00
llaniau ae06e730ad edit profile web app 2020-07-06 14:08:15 +02:00
llaniau f386b93dd2 Web app V2.0.1 avec gestion du profil (step) 2020-07-06 10:37:31 +02:00
Sébastien cebdf4d1d2 Feat: test install préprod 2020-06-30 15:50:56 +02:00
Sébastien e6738a1565 Feat: test conseils 2020-06-30 15:22:41 +02:00
Sébastien ce9b8b6031 Fix: Too much space 2020-06-30 15:19:23 +02:00
Huaoe 00eac45913 liste de correctif MEP
tt-app/app/Saga There was a failure building this commit
2019-11-06 14:13:40 +01:00
Grégoire 89719a8bbc config webpush 2019-11-05 17:13:04 +01:00
Huaoe 901280363e supp import
tt-app/app/saga Build queued...
2019-11-05 14:10:26 +01:00
Huaoe 6612f91047 push notification fixed 2019-11-04 16:36:20 +01:00
Huaoe 5e7fabe1ce Merge branch 'webRTCIntegration' into saga 2019-11-04 14:10:50 +01:00
Huaoe e05aadd5c3 fix slash positionning in /api/talent?bearer= 2019-11-04 12:26:27 +01:00
Huaoe 567a282dcf Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-11-04 10:25:08 +01:00
Sébastien 3eb5f6852f Fix: Home card height responsive
tt-app/app/Saga There was a failure building this commit
2019-10-29 11:45:48 +01:00
Grégoire 7ddab7d95c Redirect to monCompte on website 2019-10-29 11:04:24 +01:00
Huaoe 400340aaef repair Reponse + public folder usage
tt-app/app/webRTCIntegration There was a failure building this commit
2019-10-18 12:20:09 +02:00
Huaoe 5a43a2a9e1 upload webrtc + Link stalling 2019-10-18 10:54:10 +02:00
Huaoe 69848dbe38 made this url work
tt-app/app/webRTCIntegration There was a failure building this commit
: http://localhost:3000/Reponse?adId=80
2019-10-17 17:24:52 +02:00
Huaoe ad40f73997 webRtc repaired 2019-10-16 16:34:05 +02:00
Grégoire fbdc460ee0 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
tt-app/app/Saga There was a failure building this commit
2019-10-16 09:15:40 +02:00
Grégoire e30c7f8daf fix console.info 2019-10-16 09:15:06 +02:00
Grégoire 9a87bc6627 Fix bug offres pourvues / offres en cours 2019-10-16 09:14:37 +02:00
Huaoe a2042e48e7 captcha rehearse 2019-10-15 09:45:41 +02:00
Huaoe cc02119938 Recaptcha fix
tt-app/app/Saga There was a failure building this commit
2019-10-14 17:04:31 +02:00
Huaoe b2affbd87b repa 2019-10-14 11:15:44 +02:00
Huaoe 0526286554 right version 2019-10-14 11:15:18 +02:00
Huaoe 2b5e024bd0 fix quotes 2019-10-14 10:31:44 +02:00
Huaoe ed74d6f882 fix paramaeteres 2019-10-14 10:19:52 +02:00
Grégoire ff2225a47b Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-10-14 10:16:45 +02:00
Grégoire 23832d2c4f save subscription 2019-10-14 10:15:23 +02:00
Sébastien 655bce3fca Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
tt-app/app/Saga There was a failure building this commit
tt-app/app/ALPHA There was a failure building this commit
2019-10-11 16:13:59 +02:00
Sébastien 1c33d5f7cf Feat: Add Slider dependencies 2019-10-11 16:13:55 +02:00
Sébastien 3737e34f32 Feat: Update next config for slider (not working) 2019-10-11 16:13:13 +02:00
Sébastien 36644308b8 Feat: Add slider component 2019-10-11 16:12:46 +02:00
Grégoire 080deea1e5 add fetchUserSubscriptionToPush ( old:isUserSubscribedToPush) 2019-10-11 15:16:04 +02:00
Sébastien a0caba4009 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-10-11 14:17:23 +02:00
Grégoire 3c1deffbf1 merge work 2019-10-11 12:21:35 +02:00
Grégoire c07482e340 add isUserSubscribedToPush 2019-10-11 12:05:06 +02:00
Huaoe cc80821658 fix nofollow 2019-10-11 11:24:44 +02:00
Huaoe b0cbafdf44 fix nofollow 2019-10-11 11:24:29 +02:00
Grégoire 6869085f6d Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-10-11 11:00:46 +02:00
Huaoe 9f8e61069c fix reducer after onUpdateSubscriptionOnServer 2019-10-11 09:26:36 +02:00
Sébastien 0b6b8451d1 Feat: Add new component slider 2019-10-11 09:21:44 +02:00
Grégoire 17041758cb Add visit record companies and ads pages 2019-10-10 16:56:15 +02:00
Sébastien ddfbd344f6 Feat: update placeholder 2019-10-10 09:02:18 +02:00
Huaoe 64d750fb9e comment 2019-10-09 17:19:54 +02:00
Huaoe ebe9f62a8f reset search button 2019-10-09 11:49:46 +02:00
Huaoe fd8cb20f52 merge seb changes 2019-10-09 11:42:52 +02:00
Huaoe 7526059543 search fix 2019-10-09 11:36:41 +02:00
Sébastien d0bd5103cf Fix: content height
tt-app/app/Saga There was a failure building this commit
2019-10-09 11:34:41 +02:00
Sébastien c9a3ae62ce Fix: Change recaptcha key 2019-10-09 11:34:20 +02:00
Sébastien 7d2ca2bad3 Feat: add phone field 2019-10-09 11:34:01 +02:00
Sébastien ab59d8872d Fix: edit style 2019-10-09 11:33:37 +02:00
Sébastien 4da821ce79 Feat: add prop height 2019-10-09 11:32:46 +02:00
Grégoire 501af4b3f6 Chat : video in bubble 2019-10-09 10:50:45 +02:00
Huaoe 3c61032cf0 publicRuntimeConfig changes 2019-10-09 10:18:18 +02:00
Huaoe af4e3207b4 User picture update final 2019-10-09 09:45:51 +02:00
Huaoe 3b835a4461 add upload picture : not working 2019-10-08 17:29:25 +02:00
Huaoe f5a1fce6ac changes after arret de travail 2019-10-07 09:49:16 +02:00
Huaoe 604b030045 avant arret travail 2019-10-07 09:17:34 +02:00
Sébastien 9857a2363f Feat: Add currentjob and phone
tt-app/app/Saga There was a failure building this commit
2019-10-04 13:46:48 +02:00
Sébastien 892084cd41 Feat: Update README informations about integration 2019-10-04 13:43:29 +02:00
Sébastien 47fca4b73a Feat: add react-google-recaptcha for forms 2019-10-04 13:42:58 +02:00
Sébastien d1c865dbd8 Feat: Update icon of input 2019-10-04 13:42:09 +02:00
Sébastien f35b9d2037 Feat: Add condition for territories and Tags of offer 2019-10-04 13:41:48 +02:00
Sébastien a4e039706d Feat: Add arrow to home slider 2019-10-04 13:40:59 +02:00
Sébastien 13f4790a36 Feat: add Crisp to app 2019-10-04 13:36:54 +02:00
Sébastien 829b1476d6 Feat: Add Recaptcha on login form 2019-10-01 18:09:42 +02:00
Sébastien 5c579cb592 Feat: territory style 2019-10-01 18:09:05 +02:00
Sébastien 2464d4b6bc Fix: Tile size 16:9 2019-10-01 18:08:34 +02:00
Sébastien cb6729aa77 Fix: image width 2019-10-01 18:07:46 +02:00
Sébastien d396fcc83a Fix: import video from library 2019-10-01 18:07:30 +02:00
Sébastien d888c173f4 Feat: Add territory part
tt-app/app/Saga There was a failure building this commit
2019-09-26 11:46:21 +02:00
Sébastien 9d0f25984e Feat: Add current page link color 2019-09-26 11:45:26 +02:00
Sébastien f2550a2df7 Feat: Add new prop to VideoVimeo 2019-09-26 11:44:45 +02:00
Sébastien 8f034b61de Fix: height bug 2019-09-26 11:43:42 +02:00
Sébastien 53ccf11d87 Fix: little fix 2019-09-26 11:43:27 +02:00
Sébastien fcfae5408b Feat: Enable linkedin twitter and website in form 2019-09-26 11:42:31 +02:00
Huaoe 370e58494c fe
tt-app/app/Saga There was a failure building this commit
2019-09-20 15:24:18 +02:00
Huaoe 9d5fbedb2c sh
tt-app/app/Saga There was a failure building this commit
2019-09-20 15:19:35 +02:00
Huaoe cf7d4fc6bc test
tt-app/app/Saga There was a failure building this commit
2019-09-20 14:56:36 +02:00
Huaoe a960426a6d gitignore stalling 2019-09-20 11:31:28 +02:00
Huaoe 87862a26df .gitignore is now working 2019-09-20 11:29:32 +02:00
Huaoe c29681cb7c dirt
tt-app/app/Saga There was a failure building this commit
2019-09-20 10:56:33 +02:00
Huaoe f01af4813e jenkins sucks 2019-09-20 10:27:28 +02:00
Huaoe de9a4f7b38 jenkins hell
tt-app/app/Saga There was a failure building this commit
2019-09-20 10:12:06 +02:00
Huaoe b394f5fa5d jenkinsfile
tt-app/app/Saga There was a failure building this commit
2019-09-20 09:54:40 +02:00
Huaoe 9d9c777c93 volume out
tt-app/app/Saga There was a failure building this commit
2019-09-19 16:56:59 +02:00
Huaoe bddf254005 without Dockerfile
tt-app/app/Saga There was a failure building this commit
2019-09-19 16:56:37 +02:00
Huaoe 1a90223e22 jenkins file docker image config
tt-app/app/Saga There was a failure building this commit
2019-09-19 16:49:11 +02:00
Huaoe b963814067 jenkins 2019-09-19 16:48:31 +02:00
Huaoe 921030d6c0 gitignore accepting Jenkins
tt-app/app/Saga There was a failure building this commit
2019-09-19 15:05:07 +02:00
Huaoe 80e03c29e9 jenkins README 2019-09-19 14:39:40 +02:00
Huaoe 6cb252e031 cypress test stalling 2019-09-19 14:39:27 +02:00
Huaoe bfbb31ce25 Next.js 9 stalling + new DB + cypress stalling 2019-09-19 10:55:03 +02:00
Huaoe 849e0a5b18 next.js 9 installed ! 2019-09-18 14:57:10 +02:00
Huaoe 9f497b83d5 SEO optim
tt-app/app/Saga There was a failure building this commit
2019-09-17 10:02:18 +02:00
Huaoe 344bdca41c SEO optim 2019-09-17 09:41:04 +02:00
Huaoe a05780ee39 tag manager try fix 2019-09-16 15:28:57 +02:00
Huaoe f7ac5e669f tag 2019-09-16 14:37:32 +02:00
Huaoe b28ec325b8 noscript 2019-09-16 09:21:05 +02:00
Huaoe 6a6bfa3e39 merge
tt-app/app/Saga There was a failure building this commit
2019-09-13 16:50:30 +02:00
Huaoe 753c990fc6 12 items entreprise 2019-09-13 16:46:56 +02:00
Sébastien 8069a54d1a Fix: logo border radius 2019-09-13 12:16:05 +02:00
Huaoe 9e2e58d45c gitignore 2019-09-13 11:54:42 +02:00
Sébastien e7c59003cf Fix: Add login redirect 2019-09-13 11:46:54 +02:00
Sébastien 8c435db886 Feat: Add new page 2019-09-13 11:41:17 +02:00
Sébastien 2d41de8568 Fix: align arrow, change font size etc 2019-09-13 11:41:05 +02:00
Sébastien a4a5096eb8 Fix: bottom bar hover on mobile 2019-09-13 11:40:09 +02:00
Sébastien d7128d7ddc Fix: Add new box shadow 2019-09-13 11:39:27 +02:00
Sébastien e06b23e73a Feat: add new default picture company 2019-09-13 11:38:24 +02:00
Huaoe 90aefa56c2 camel case in iFRame video 2019-09-13 10:54:19 +02:00
Huaoe 6ceae61685 entreprise pagesize 12 2019-09-13 10:29:41 +02:00
Sébastien d8033ec4ef Feat: Add props title
tt-app/app/Saga There was a failure building this commit
2019-09-12 12:07:05 +02:00
Sébastien b4b9a0f5c4 Fix: card height 2019-09-12 12:06:35 +02:00
Sébastien d4933d9535 Fix: menu height of logo part 2019-09-12 12:06:21 +02:00
Sébastien 024c34753c Fix: menu width 2019-09-12 12:06:03 +02:00
Sébastien d348f0d618 Fix: video_title 2019-09-12 12:05:51 +02:00
Sébastien 4662d0b30d Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-09-12 11:30:33 +02:00
Sébastien e6b873b861 Fix: add condition to display this part 2019-09-12 11:30:24 +02:00
Sébastien 88d0f8a222 Fix: Menu override with width 50% 2019-09-12 11:30:00 +02:00
Sébastien 15b94ea080 Feat: Update box shadow animation 2019-09-12 11:29:28 +02:00
Sébastien e4218c708e Fix: TT logo width 2019-09-12 11:28:43 +02:00
Sébastien 772aa99c21 Fix: delete useless files 2019-09-12 11:28:31 +02:00
Sébastien e1c6729d04 Fix: Card size 2019-09-12 11:28:16 +02:00
Sébastien 4bd910fe6b Fix: vimeo autoplay 2019-09-12 11:27:51 +02:00
Huaoe fe1b554dce Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
tt-app/app/Saga There was a failure building this commit
2019-09-12 11:02:55 +02:00
Huaoe a75b4509a0 agent { dockerfile true } 2019-09-12 11:01:49 +02:00
Sébastien e36330bcc2 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-09-12 10:37:10 +02:00
Sébastien 51b36943ef Fix: Card adjustment and horizontal scroller width 2019-09-12 10:36:52 +02:00
Sébastien 78f80b4d7b Feat: Add new background 2019-09-12 10:34:10 +02:00
Sébastien 65beb482c2 Fix: search bar width and cursor on button 2019-09-12 10:33:45 +02:00
Sébastien ec7cab4b98 Fix: link and font size 2019-09-12 10:33:22 +02:00
Sébastien 2089bd5c76 Fix: font size 2019-09-12 10:31:38 +02:00
Sébastien 36cfa25d09 Fix: box shadow override 2019-09-12 10:30:34 +02:00
Sébastien 2394319605 Feat: Add new background color 2019-09-12 10:30:15 +02:00
Sébastien fb002efaec Fix: title position center 2019-09-12 10:30:03 +02:00
Sébastien 4b49371b08 Fix: menu logo width 2019-09-12 10:29:46 +02:00
Sébastien b5261ff528 Feat: Add new content 2019-09-12 10:29:32 +02:00
Huaoe 61f03f4208 mhart
tt-app/app/Saga There was a failure building this commit
2019-09-12 10:10:14 +02:00
Huaoe d140bfeb38 install
tt-app/app/Saga There was a failure building this commit
2019-09-12 09:40:59 +02:00
Huaoe edb1ba680a cdd
tt-app/app/Saga There was a failure building this commit
2019-09-12 09:15:21 +02:00
Huaoe b3f927a46f kiki
tt-app/app/Saga There was a failure building this commit
2019-09-12 09:03:55 +02:00
Huaoe 288b8b1f51 cd cd 2019-09-12 09:03:23 +02:00
Huaoe 416eb4129c cd
tt-app/app/Saga There was a failure building this commit
2019-09-12 09:00:23 +02:00
Huaoe 613f0e755f test
tt-app/app/Saga There was a failure building this commit
2019-09-12 08:49:13 +02:00
Huaoe ed8562f95b node:node
tt-app/app/Saga There was a failure building this commit
2019-09-11 17:28:58 +02:00
Huaoe c95775194d su
tt-app/app/Saga There was a failure building this commit
2019-09-11 17:25:00 +02:00
Huaoe 783b65b5e9 sudo
tt-app/app/Saga There was a failure building this commit
2019-09-11 17:22:15 +02:00
Huaoe 38fef5c514 node_modules
tt-app/app/Saga There was a failure building this commit
2019-09-11 17:21:12 +02:00
Huaoe e6286c97e4 node
tt-app/app/Saga There was a failure building this commit
2019-09-11 17:19:34 +02:00
Huaoe 55a2979814 echpo
tt-app/app/Saga There was a failure building this commit
2019-09-11 17:16:13 +02:00
Huaoe b5dc00eb7b tres
tt-app/app/Saga Something is wrong with the build of this commit
2019-09-11 17:05:27 +02:00
Huaoe 813c085e3b chown
tt-app/app/Saga Something is wrong with the build of this commit
2019-09-11 16:55:39 +02:00
Huaoe 550688a99e change docker image
tt-app/app/Saga Build queued...
2019-09-11 16:49:41 +02:00
Huaoe 061e756237 steps
tt-app/app/Saga Something is wrong with the build of this commit
2019-09-11 16:46:27 +02:00
Huaoe d6091fb496 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
tt-app/app/Saga There was a failure building this commit
2019-09-11 16:44:16 +02:00
Huaoe 52221edbee test1 2019-09-11 16:42:52 +02:00
Sébastien 4cf4347611 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
tt-app/app/Saga There was a failure building this commit
2019-09-11 16:23:59 +02:00
Sébastien 60c9fa9b6f Add new pages cgu mentions etc 2019-09-11 16:23:29 +02:00
Huaoe 80c48533d7 testset
tt-app/app/Saga There was a failure building this commit
2019-09-11 16:02:11 +02:00
Huaoe 3dfd5d2c89 test
tt-app/app/Saga There was a failure building this commit
2019-09-11 15:53:29 +02:00
Huaoe ba4118be38 test re
tt-app/app/Saga Something is wrong with the build of this commit
2019-09-11 15:01:58 +02:00
Huaoe 9967eab3c5 test again
tt-app/app/Saga There was a failure building this commit
2019-09-11 14:47:14 +02:00
Huaoe 861a0bf45f jenkins script call
tt-app/app/Saga There was a failure building this commit
2019-09-11 14:42:40 +02:00
Huaoe 1b7089a694 jenkins file modif test
tt-app/app/Saga There was a failure building this commit
2019-09-11 14:32:05 +02:00
Huaoe d6e345b2f3 test
tt-app/app/Saga Build queued...
2019-09-11 14:28:35 +02:00
Huaoe d720b08ccb jenkins readme and makefile windows compat 2019-09-11 14:12:33 +02:00
Huaoe b773d04e4d Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-09-11 13:56:04 +02:00
Sébastien bd247c9ebd Jenkins: update jenkinsfile
tt-app/app/Saga There was a failure building this commit
2019-09-11 12:32:15 +02:00
Sébastien e08c0f3605 Jenkins: update jenkinsfile
tt-app/app/Saga There was a failure building this commit
2019-09-11 11:57:40 +02:00
Sébastien f86fcfe3d8 Jenkins: Update jenkinsfile
tt-app/app/Saga There was a failure building this commit
2019-09-11 11:48:04 +02:00
Sébastien 6629cd8156 Fix: External link -> talentstube.com 2019-09-11 11:39:18 +02:00
Huaoe 5a29559ee7 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-09-11 11:05:36 +02:00
Huaoe eab5e57e4b brand_name everywhere 2019-09-11 11:05:31 +02:00
Sébastien 90ce3b1e6d Fix: general box shadow hover 2019-09-11 10:53:26 +02:00
Sébastien 97a438ac39 Fix: box shadow hover animation
tt-app/app/Saga Build queued...
2019-09-11 10:32:39 +02:00
Sébastien a804655113 Fix: text align left 2019-09-11 10:32:19 +02:00
Sébastien 079cc18f5f Fix: zIndex value 2019-09-11 10:31:45 +02:00
Huaoe 18abd46de6 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-09-11 09:36:10 +02:00
Sébastien 4728107d9a Jenkins: Update scripts path 2019-09-11 08:24:19 +02:00
Sébastien 52f5c361d2 Jenkins: Update jenkinsfile
tt-app/app/Saga There was a failure building this commit
2019-09-10 16:21:55 +02:00
Sébastien efcd8002d5 Jenkins: add conf files
tt-app/app/Saga Something is wrong with the build of this commit
2019-09-10 16:00:25 +02:00
Sébastien 2d9017bd5d Update gitignore 2019-09-10 16:00:09 +02:00
Sébastien 7637ffd11c Fix: height of ad card on mobile 2019-09-10 14:26:37 +02:00
Sébastien b7fa1c403e Fix: chip width (fit-content) 2019-09-10 11:58:29 +02:00
Sébastien 48936e7150 Fix: Company card size (height and chips position) 2019-09-10 11:41:36 +02:00
Sébastien 3dcd837a9e Fix: video responsive 2019-09-10 11:41:05 +02:00
Huaoe a859e045cd google tag manager added 2019-09-10 10:37:42 +02:00
Sébastien 3a4637bc1a Jenkins: add conf files 2019-09-10 08:44:35 +02:00
Sébastien a230f02005 Jenkins: add conf files 2019-09-10 08:44:16 +02:00
Sébastien 3c4e06a84e Add README file 2019-09-10 08:43:27 +02:00
Sébastien 0c8b1b5fe5 Jenkins: add conf files
tt-app/app/Saga There was a failure building this commit
2019-09-06 16:22:45 +02:00
Sébastien 74b4de0543 Jenkins: move scripts and JenkinsFile to nextjs folder 2019-09-06 16:18:39 +02:00
Sébastien 730a61cddb Jenkins: update Jenkinsfile 2019-09-06 15:47:45 +02:00
Sébastien df7f3604f9 Jenkins: add config files 2019-09-06 15:43:34 +02:00
Sébastien 15e74aab9f Update scripts 2019-09-06 15:41:59 +02:00
Sébastien 7dd7071a0a Add readme file 2019-09-06 15:41:41 +02:00
Sébastien 8393f22ea6 Update docker config 2019-09-06 15:41:27 +02:00
Sébastien 985ed33346 Jenkins: add conf files
tt-app/app/Saga There was a failure building this commit
2019-09-06 09:31:05 +02:00
Sébastien c357846ecf Cypress: Test output when running in command line 2019-09-06 09:30:25 +02:00
Sébastien 7685f304bf Jenkins: add conf files 2019-09-06 09:28:35 +02:00
Sébastien 327d9d05c4 Add scripts sh 2019-09-06 09:26:24 +02:00
Sébastien f577733522 Add new pipeline 2019-09-06 09:22:10 +02:00
Sébastien 2a82a3758e Update test script 2019-09-06 09:21:46 +02:00
Sébastien 80f7ef2da4 Jenkins: add conf files
tt-app/app/Saga This commit looks good
2019-09-05 11:41:17 +02:00
Sébastien 1ac0b286a9 Fix: zIndex problems on Menu and Home video 2019-09-05 11:40:27 +02:00
Sébastien 20805afd31 Fix: checkbox color 2019-09-05 11:39:54 +02:00
Sébastien 47376ff7b7 Add image for help page 2019-09-05 11:39:39 +02:00
Sébastien a787a1f870 Delete useless images 2019-09-05 11:39:27 +02:00
Sébastien 2ca49a9566 Add image 2019-09-05 11:37:23 +02:00
Sébastien a4961638f2 Add Jenkinsfile 2019-09-05 11:37:02 +02:00
Huaoe 583ab9480f app_dev purge 2019-09-04 16:10:55 +02:00
Huaoe 73bf25904f test server 2019-09-02 16:07:33 +02:00
Huaoe 5206050f6a add server logs 2019-09-02 15:44:07 +02:00
Huaoe 5ca4abd2ac sitemap gen 2019-08-30 17:09:55 +02:00
Huaoe 9bfc3ac023 sitemapgenerator 2019-08-30 17:04:26 +02:00
Huaoe 088ad46a2f Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-30 16:40:14 +02:00
Huaoe d115add2ea tests 2019-08-30 16:39:57 +02:00
Sébastien 9cdb2889d5 Jenkins: add missing file 2019-08-30 16:32:38 +02:00
Sébastien 5cd1391ade Jenkins: add plugin Gogs 2019-08-30 16:32:19 +02:00
Sébastien e74e915060 fix: zindex problem 2019-08-30 16:12:44 +02:00
Sébastien e94f20ef78 Fix: side of message 2019-08-30 16:12:33 +02:00
Sébastien 25a335f2f0 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-30 15:52:22 +02:00
Sébastien 26d243f658 Add: Jenkins missing files 2019-08-30 15:52:17 +02:00
Sébastien 3c0702022d Add Jenkins folder and container 2019-08-30 15:51:13 +02:00
Huaoe 9bfe4fb198 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-30 15:50:18 +02:00
Huaoe 90b56c0471 test cypress 2019-08-30 15:49:28 +02:00
Sébastien 28bb8e5299 Fix: width of content 2019-08-30 08:28:20 +02:00
Huaoe a18accb39c small changes 2019-08-29 16:41:29 +02:00
Sébastien 092b6cb655 Fix: overflow-x to overflow 2019-08-29 16:10:29 +02:00
Sébastien 24d733b4f7 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-29 16:06:25 +02:00
Sébastien e3170e07dd Fix: video width overflow 2019-08-29 16:06:20 +02:00
Huaoe bda41ff48b Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-29 14:44:06 +02:00
Huaoe bf9be45efd console.log purge 2019-08-29 14:44:02 +02:00
Sébastien 323fe4b2c1 Add vimeo video 2019-08-29 14:21:32 +02:00
Sébastien 81938e714d Fix: vimeo video slider width 2019-08-29 14:21:18 +02:00
Sébastien 6ab1b74342 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-29 11:32:35 +02:00
Sébastien 1bedb3e467 Fix: bug video 2019-08-29 11:31:48 +02:00
Huaoe b1cd82c346 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-29 11:21:52 +02:00
Huaoe a8df08e2f2 clean Plyr 2019-08-29 11:21:38 +02:00
Sébastien 6b2a99caee Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
# Conflicts:
#	nextjs/components/atoms/VideoVimeo.js
2019-08-29 11:05:13 +02:00
Sébastien fbaf665ce9 Update cypress 2019-08-29 11:02:06 +02:00
Sébastien 4cfd8bde6f Update props 2019-08-29 11:01:34 +02:00
Sébastien b6e1a8b864 Add video 2019-08-29 11:01:18 +02:00
Huaoe 80eeb91f79 dynamic usage for first contentful paint optim 2019-08-29 09:53:53 +02:00
Huaoe 0063ef68f5 the end of Plyr 2019-08-29 09:33:26 +02:00
Huaoe eb6d281332 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-28 09:47:36 +02:00
Huaoe ff0bb50414 try dynamic for time to interactive shortennings matters 2019-08-28 09:47:31 +02:00
Huaoe fb528ebc84 url mangling 2019-08-28 09:31:05 +02:00
Sébastien a0504ec5fb Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
# Conflicts:
#	nextjs/components/organisms/Chat.js
2019-08-28 09:15:01 +02:00
Sébastien e40110a038 Update: script cypress + restoredb + backupdb 2019-08-28 09:12:35 +02:00
Sébastien 7512ed04e2 Fix: chat message position 2019-08-28 09:12:09 +02:00
Sébastien 5c23dc39bf Fix: shit enter in input type text 2019-08-28 09:11:56 +02:00
Sébastien 5488844845 Add cypress class 2019-08-28 09:11:31 +02:00
Sébastien 33670ee1d6 Fix height bug and add cypress class 2019-08-28 09:11:11 +02:00
Sébastien f569559f56 Update cypress id 2019-08-28 09:10:49 +02:00
Sébastien d4083e4701 Add cypress order with file name 2019-08-28 09:09:52 +02:00
Sébastien ee808cffb2 Fix offer card width 2019-08-28 09:08:32 +02:00
Huaoe 99f1c4d117 url mangling entreprise fix 2019-08-28 09:00:02 +02:00
Huaoe a54e85d359 .env 2019-08-27 16:55:52 +02:00
Huaoe d10d03e6bb seo url mangling setup 2019-08-27 16:49:27 +02:00
Huaoe 1d959f88f2 classes fix 2019-08-27 12:21:29 +02:00
Sébastien 31d566a9c7 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-27 09:37:41 +02:00
Sébastien 127e5e9d8d Fix: chat style 2019-08-27 09:37:35 +02:00
Sébastien c57b1402e9 Fix width of card when 1 result 2019-08-27 09:37:20 +02:00
Sébastien 3c759d3572 Fix scroll bug 2019-08-27 09:37:00 +02:00
Sébastien 51deea06b8 Fix spacing between candidatures 2019-08-27 09:36:46 +02:00
Huaoe b9ba409c99 register typo 2019-08-27 09:36:01 +02:00
Huaoe 77d1f9954e head fix 2019-08-26 17:00:20 +02:00
Sébastien a3ad2c0030 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
# Conflicts:
#	nextjs/components/atoms/ChatCard.js
#	nextjs/components/organisms/Chat.js
2019-08-26 16:28:00 +02:00
Sébastien bc95306a15 Add chat style 2019-08-26 16:23:33 +02:00
Huaoe 45efd6b556 head title everywhere 2019-08-26 16:22:33 +02:00
Huaoe 1ddbc65e14 console.log purge 2019-08-26 15:44:13 +02:00
Huaoe da90a3283a chat 2019-08-26 15:16:06 +02:00
Huaoe efaf7ef6dd Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-26 11:16:41 +02:00
Huaoe 9999cc3417 mesasge 2019-08-26 11:16:37 +02:00
Sébastien f931c25a9e Little fix 2019-08-26 11:12:34 +02:00
Sébastien 0ac6abb5b5 Add condition to imgUrl and imgUrlDesktop 2019-08-26 11:12:26 +02:00
Sébastien 79b8223c8c Add style to checkbox 2019-08-26 11:12:06 +02:00
Thomas Berrod 0633ece7ba entreprise dust broom 2019-08-21 12:01:22 +02:00
Thomas Berrod a474f0740f OGHead done 2019-08-21 10:39:28 +02:00
Thomas Berrod 65e2ab90d2 update package.json for linkedin bug 2019-08-20 09:54:07 +02:00
Thomas Berrod a7d31d6f4d git blocked linkedin bug 2019-08-19 16:54:46 +02:00
Thomas Berrod 042394d87d webpush dust 2019-08-19 14:34:31 +02:00
Thomas Berrod 9d2fefe4ed push provider integrated 2019-08-16 17:26:38 +02:00
Thomas Berrod 3a08038da5 provider working 2019-08-16 16:40:39 +02:00
Thomas Berrod 4cfad7bbca push standalone in param page 2019-08-13 17:27:50 +02:00
Thomas Berrod cf8f8086d7 push -foloowings 2019-08-13 15:21:17 +02:00
Thomas Berrod 36f7d5698b push - begin 2019-08-12 17:14:34 +02:00
Thomas Berrod b0fd71ee0f Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-12 09:21:47 +02:00
Thomas Berrod 0f8fe8cfd8 candidature spontanée avancement 2019-08-12 09:21:37 +02:00
Sébastien GLATZ c0e209ab67 Add next previous style 2019-08-09 16:30:40 +02:00
Sébastien GLATZ 6c091c3fac Fix useless padding 2019-08-09 14:08:34 +02:00
Sébastien GLATZ 8a7b425e90 Fix responsive 2019-08-09 14:02:50 +02:00
Sébastien GLATZ 7ee7ab7e90 Add bottom spacing for discover container 2019-08-09 14:02:11 +02:00
Sébastien GLATZ ae603ba41d Remove link style 2019-08-09 14:01:54 +02:00
Sébastien GLATZ 58c36dbf2d Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-09 12:22:52 +02:00
Sébastien GLATZ d70ab851aa Add url to access account 2019-08-09 12:22:45 +02:00
Thomas Berrod de57d33a17 comment switch 2019-08-09 12:15:33 +02:00
Thomas Berrod 3caa419579 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-09 12:14:48 +02:00
Thomas Berrod fd9bc060cc hack back 2019-08-09 12:09:50 +02:00
Sébastien GLATZ d705f062ed Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-09 12:09:41 +02:00
Sébastien GLATZ a15a2ad831 Add new page parametres 2019-08-09 12:09:35 +02:00
Thomas Berrod 4372c7a1e5 hack to change file name 2019-08-09 12:09:27 +02:00
Sébastien GLATZ d0dd09cce6 Fix screen orientation card 2019-08-09 12:08:45 +02:00
Thomas Berrod db5670ffe2 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-09 11:42:48 +02:00
Thomas Berrod dd6e2cdf4b reset handle snack off 2019-08-09 11:42:36 +02:00
Sébastien GLATZ 154fe260dc Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-09 10:56:59 +02:00
Sébastien GLATZ 583e568085 Add style 2019-08-09 10:56:52 +02:00
Thomas Berrod 3a137d4282 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-09 10:56:50 +02:00
Thomas Berrod 9c47f93e17 reset 2019-08-09 10:56:45 +02:00
Sébastien GLATZ 2b585216da Fix component VideoVimeo name 2019-08-09 10:43:27 +02:00
Sébastien GLATZ 77be2fd0c9 Fix: form width and responsive 2019-08-09 10:40:29 +02:00
Sébastien GLATZ 96ccc64eae Little fix 2019-08-09 10:28:56 +02:00
Sébastien GLATZ 9e9527686f Fix video vimeo width 2019-08-09 10:26:37 +02:00
Sébastien GLATZ 6b0cb02afc Fix title height 2019-08-09 10:25:57 +02:00
Sébastien GLATZ 4f5b03cdff Add footer 2019-08-09 10:25:01 +02:00
Thomas Berrod 63042e0e83 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-08 16:43:12 +02:00
Thomas Berrod 35ef8f28c0 misc 2019-08-08 16:43:07 +02:00
Sébastien GLATZ a9c3d382cf Fix line break 2019-08-08 16:42:14 +02:00
Sébastien GLATZ de45ba36c6 Add new conditional color 2019-08-08 16:28:11 +02:00
Sébastien GLATZ 7b227fb1f5 Fix: align center icons 2019-08-08 16:27:56 +02:00
Sébastien GLATZ b2e75da6f8 Fix logo container border size and radius 2019-08-08 16:27:43 +02:00
Sébastien GLATZ 7aaf059e55 Fix title top spacing 2019-08-08 16:26:57 +02:00
Sébastien GLATZ 608283a6e6 Fix searchbar background color 2019-08-08 16:26:35 +02:00
Sébastien GLATZ 9235571dcb Fix header style 2019-08-08 16:26:15 +02:00
Sébastien GLATZ 5e806b6c64 Add style and border 2019-08-08 16:26:01 +02:00
Sébastien GLATZ 989d215ef8 Fix: link region 2019-08-08 16:25:32 +02:00
Thomas Berrod 9daacb05d6 fix index in list 2019-08-08 16:19:48 +02:00
Sébastien GLATZ b152cb5aea Fix: scrollbar on chrome 2019-08-08 14:44:53 +02:00
Sébastien GLATZ 9ec2bf5cb6 Add hover effect on card 2019-08-08 14:44:43 +02:00
Sébastien GLATZ b8b18d5403 Fix: style 2019-08-08 13:45:12 +02:00
Sébastien GLATZ cfc895b5dd Fix: box shadow 2019-08-08 13:43:45 +02:00
Sébastien GLATZ 287170ac96 Fix: video width 2019-08-08 13:43:29 +02:00
Sébastien GLATZ 6b636d0af3 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
# Conflicts:
#	nextjs/components/organisms/Chat.js
2019-08-08 11:47:27 +02:00
Sébastien GLATZ bd0e394d8a Add new layout for message input 2019-08-08 11:45:18 +02:00
Thomas Berrod 7f3764ae67 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-08 11:37:42 +02:00
Thomas Berrod 7363e9133b bug fix : Register + login 2019-08-08 11:37:38 +02:00
Thomas Berrod 4d17137922 uniquement les offres publiées sur entreprise detail 2019-08-08 09:44:13 +02:00
Sébastien GLATZ fa24a9b292 Little style fix 2019-08-08 09:05:07 +02:00
Sébastien GLATZ 4d637240aa Delete horizontal scrollbar 2019-08-08 08:58:20 +02:00
Sébastien GLATZ 2b617226f6 Fix: Appbar bug on scroll and scroll in page 2019-08-08 08:57:50 +02:00
Sébastien GLATZ 988440f5fd Fix: change title when promoted 2019-08-08 08:57:29 +02:00
Thomas Berrod 9d0d9f04ff chat saga building 2019-08-07 17:10:21 +02:00
Sébastien GLATZ ab76048563 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-07 15:43:22 +02:00
Sébastien GLATZ 62e8f483c9 Fix: avatar border radius 2019-08-07 15:43:14 +02:00
Sébastien GLATZ 0ab872a2db Little style fix 2019-08-07 15:43:01 +02:00
Sébastien GLATZ ed38d28fc5 Fix: cursor pointer 2019-08-07 15:42:37 +02:00
Sébastien GLATZ 2368f3f520 Fix: app name 2019-08-07 15:41:41 +02:00
Sébastien GLATZ 7a861a77d1 Fix: content width 2019-08-07 15:41:26 +02:00
Thomas Berrod f21bbadb5b wait : comment upload photo 2019-08-07 15:24:21 +02:00
Thomas Berrod beab21d889 background color android 2019-08-07 15:03:07 +02:00
Sébastien GLATZ c77ec3c9b0 Fix appbar 2019-08-07 11:20:20 +02:00
Sébastien GLATZ d8c289a6a8 Add VideoVimeo component and Fix button postuler 2019-08-07 11:20:02 +02:00
Sébastien GLATZ 77ba7c5f94 Add VideoVimeo component 2019-08-07 11:18:58 +02:00
Thomas Berrod 39baa0ab66 Chat beta 2019-08-07 09:38:37 +02:00
Sébastien GLATZ 1c05c16041 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-07 09:35:41 +02:00
Sébastien GLATZ 62d13d66e5 Fix video bug with vimeo player 2019-08-07 09:35:33 +02:00
Sébastien GLATZ 1db0fab8e1 Add account access on desktop 2019-08-07 09:35:04 +02:00
Thomas Berrod 7e39a35997 fix quote on offre d'emploi 2019-08-06 17:20:26 +02:00
Thomas Berrod 8f97f706f0 candidature : id on Plyr 2019-08-06 16:32:51 +02:00
Sébastien GLATZ f5a6e86c61 Fix: double scrollbar bug 2019-08-06 16:27:57 +02:00
Sébastien GLATZ 9eeee67f03 Test: video vimeo 2019-08-06 16:27:30 +02:00
Sébastien GLATZ 314407806e Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-06 12:24:46 +02:00
Sébastien GLATZ 9b196e3106 Fix: display bottom bar only on mobile devices 2019-08-06 12:24:41 +02:00
Thomas Berrod c380260645 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-06 12:21:42 +02:00
Thomas Berrod 06d620ecba test mute only 2019-08-06 12:16:58 +02:00
Sébastien GLATZ ba41a79caa Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-06 12:13:27 +02:00
Sébastien GLATZ 0c443bc341 Fix: size of visible text 2019-08-06 12:13:21 +02:00
Sébastien GLATZ 9db04e1f5b Fix: image filter when card hover 2019-08-06 12:12:58 +02:00
Thomas Berrod 1be8ac03fe prepro test : autoplay off 2019-08-06 12:06:09 +02:00
Thomas Berrod dfaeb05bf4 autoplay off 2019-08-06 12:00:26 +02:00
Thomas Berrod 0b0a94e98b test preprod iphone sound issue 2019-08-06 11:56:26 +02:00
Sébastien GLATZ 8878c1c57a Fix: Plyr sound for iPhone test preprod 2019-08-06 11:48:52 +02:00
Sébastien GLATZ afe458cefd Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-06 11:12:50 +02:00
Thomas Berrod bf4fa0dd30 merge brand_name issue 2019-08-06 11:10:22 +02:00
Sébastien GLATZ 9407dab844 Little fix 2019-08-06 11:08:59 +02:00
Sébastien GLATZ e34cc49a4f Add properties for plyr video 2019-08-06 11:07:22 +02:00
Sébastien GLATZ 1de11320fd Add dark overlay on cards 2019-08-06 11:07:05 +02:00
Thomas Berrod dffd974ba6 misc fixes 2019-08-06 11:03:41 +02:00
Sébastien GLATZ 7f70c3951e Fix: sound on iPhone Plyr player 2019-08-06 10:27:41 +02:00
Sébastien GLATZ d8b66eda0d Fix: scroll to top with grid 2019-08-06 10:27:22 +02:00
Sébastien GLATZ 42ad13bb93 Fix bug with footer when change page 2019-08-05 12:17:11 +02:00
Sébastien GLATZ 1bc5a9c2c8 Add new style and pictures 2019-08-05 11:56:56 +02:00
Sébastien GLATZ c3517cdced Fix links 2019-08-05 11:56:25 +02:00
gregoire baf8c7cea0 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-02 16:38:40 +02:00
gregoire 3d4d90e46b cypress test 2019-08-02 16:38:37 +02:00
Thomas Berrod c46cddcdaf misc fixes 2019-08-02 16:24:48 +02:00
Thomas Berrod c5e631064a Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-02 16:07:31 +02:00
Thomas Berrod e5bdbe0bc8 test on offer + company data not well formed from preprod 2019-08-02 16:07:26 +02:00
gregoire 14e216d448 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-02 15:08:37 +02:00
Thomas Berrod 1a7d811e8a fix 'isInStandaloneMode' has already been declared 2019-08-02 14:46:18 +02:00
gregoire af478d49bc merge 2019-08-02 12:02:02 +02:00
Thomas Berrod 902665f0af unix case fix 2019-08-02 11:10:34 +02:00
Thomas Berrod c042ae0ef7 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-02 10:53:43 +02:00
Sébastien GLATZ 988f179f14 Add color for specific appBar 2019-08-02 10:53:10 +02:00
Sébastien GLATZ 77ad925b02 Add style 2019-08-02 10:52:56 +02:00
gregoire d1a6aef77f cypress test 2019-08-02 10:49:46 +02:00
gregoire 2daa191b90 cypress test 2019-08-02 10:47:56 +02:00
Thomas Berrod b02dcb5baf answer pseudo check 2019-08-02 10:43:12 +02:00
Sébastien GLATZ acc007ca81 Add style round avatar 2019-08-02 10:37:26 +02:00
Sébastien GLATZ 142f673a17 Add style answer card 2019-08-02 10:23:12 +02:00
Sébastien GLATZ 40725cef90 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-02 10:16:20 +02:00
Sébastien GLATZ 389d2f4fac Fix: bug on Iphone 2019-08-02 10:16:14 +02:00
Sébastien GLATZ d70d27299c Fix overriding 2019-08-02 10:15:41 +02:00
Sébastien GLATZ a6b8a7f555 Add link style 2019-08-02 10:15:22 +02:00
Sébastien GLATZ 518e5e75dc Comment part because no data 2019-08-02 10:15:09 +02:00
Sébastien GLATZ 91b056274e Correct href link 2019-08-02 10:14:47 +02:00
Thomas Berrod ce9dbdfb1c 404 2019-08-02 09:30:16 +02:00
Thomas Berrod 878335ef6d fix min help 2019-08-02 09:22:59 +02:00
Thomas Berrod 064979dd90 companies -> entreprises 2019-08-01 17:46:32 +02:00
Thomas Berrod 87d283763b fix Fragment issue 2019-08-01 15:40:28 +02:00
Thomas Berrod 5ae3750c3f Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-01 15:27:23 +02:00
Thomas Berrod ebbb380c71 fetchCurrentUserRequest in Reponse 2019-08-01 15:27:19 +02:00
gregoire f430471cd4 Merge commit class cypress 2019-08-01 15:25:48 +02:00
gregoire 4bca554c4f Cypress + class cypress 2019-08-01 15:15:08 +02:00
Sébastien GLATZ 61f547494b Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-01 14:55:46 +02:00
Sébastien GLATZ 3c74d6e809 Add footer in layout grid 2019-08-01 14:54:00 +02:00
Sébastien GLATZ 8045f38eac Little fix 2019-08-01 14:53:48 +02:00
Sébastien GLATZ 94dd549943 Add loader 2019-08-01 14:53:16 +02:00
Sébastien GLATZ ae47b6a838 Little style fix 2019-08-01 14:36:23 +02:00
Sébastien GLATZ 9de0a394d7 Add logged in icons 2019-08-01 14:35:38 +02:00
Sébastien GLATZ ce29a6438d Add newsletter and install pwa in footer 2019-08-01 14:35:21 +02:00
Sébastien GLATZ ef93e66968 Add icon 2019-08-01 14:34:23 +02:00
Sébastien GLATZ e32903baa5 Fix style 2019-08-01 14:34:05 +02:00
Thomas Berrod 753e76ccb1 misc changes 2019-08-01 12:26:42 +02:00
Thomas Berrod 7a523c50a0 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-08-01 10:41:05 +02:00
Thomas Berrod 7f5e323cd9 resetPassword 2019-08-01 10:40:59 +02:00
Sébastien GLATZ b9e6c2ad21 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-31 16:30:47 +02:00
Sébastien GLATZ b42ad17f06 Add responsive 2019-07-31 16:30:38 +02:00
Thomas Berrod ca8999a2d1 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-31 15:08:49 +02:00
Thomas Berrod bbe4a2eaa7 hooker prefetch + server config 2019-07-31 15:08:45 +02:00
Sébastien GLATZ ee6923c0a7 Little style fix 2019-07-31 15:06:46 +02:00
Sébastien GLATZ b97ff9cc7c Add NoResult component 2019-07-31 15:06:26 +02:00
Sébastien GLATZ 64f1c40594 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-31 11:52:41 +02:00
Sébastien GLATZ 13b55f50d7 Little fix 2019-07-31 11:52:31 +02:00
Sébastien GLATZ 2bbbcbae82 Add detail responsive 2019-07-31 11:52:22 +02:00
Sébastien GLATZ 0b49b1a07b Add tests on data 2019-07-31 11:51:39 +02:00
Sébastien GLATZ eb08fffb3e Update box shadow 2019-07-31 11:51:25 +02:00
Thomas Berrod 10180345d3 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-31 09:51:12 +02:00
Thomas Berrod dbeb6bac94 try cors policy 2019-07-31 09:51:07 +02:00
gregoire bdfa5d911c Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-30 16:38:37 +02:00
gregoire cb71bd841c cypress test 2019-07-30 16:38:29 +02:00
Sébastien GLATZ 3d9a4fb063 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-30 16:19:36 +02:00
Sébastien GLATZ 736b83d8d3 Add new component 2019-07-30 16:19:26 +02:00
Sébastien GLATZ 20b7ac31f4 Add pagination 2019-07-30 16:19:15 +02:00
Sébastien GLATZ 9a7f9c3993 fix responsive desktop 2019-07-30 16:19:05 +02:00
Thomas Berrod 13fb868117 url redirect fix 2019-07-30 15:39:25 +02:00
gregoire 360bd1d60f Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-30 11:41:32 +02:00
gregoire 4a75e4de1e Cypress test 2019-07-30 11:34:35 +02:00
Thomas Berrod 55247fde6b Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-30 10:25:43 +02:00
Thomas Berrod 0b2dd9a546 linkedin preprod fix 2019-07-30 10:25:37 +02:00
Sébastien GLATZ 69906acd22 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
# Conflicts:
#	nextjs/pages/Login.js
2019-07-30 08:21:46 +02:00
Sébastien GLATZ 985ef46648 Little fix 2019-07-30 08:11:14 +02:00
Sébastien GLATZ e0af97ac41 Responsive fix 2019-07-30 08:11:02 +02:00
Thomas Berrod 73b5f427cd envelop without heart 2019-07-29 17:28:10 +02:00
Thomas Berrod 9e1449e7fa Loader tolower for unix ports 2019-07-29 17:00:36 +02:00
Thomas Berrod 007fdd2fac chat WIP 2019-07-29 16:58:52 +02:00
Thomas Berrod dc62eac5e4 login merge 2019-07-29 14:39:36 +02:00
Thomas Berrod b921d3eb46 login fix 2019-07-29 14:37:59 +02:00
gregoire c50f6fe858 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-29 12:09:55 +02:00
gregoire 7e08ee6b6f cypress test 2019-07-29 12:09:50 +02:00
gregoire 29e1c2550f cypress class 2019-07-29 12:09:33 +02:00
Thomas Berrod a96f83dca5 video back to Candidature 2019-07-26 16:56:59 +02:00
Thomas Berrod dc8687b794 merge grid 2019-07-26 16:53:28 +02:00
Thomas Berrod c216aec6c0 Candidatures + offreDetail 2019-07-26 16:50:19 +02:00
Sébastien GLATZ 97bb5d3a75 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-26 16:26:12 +02:00
Sébastien GLATZ 956deb7dc4 Responsive desktop 2019-07-26 16:26:04 +02:00
Sébastien GLATZ 512e5cf74f Update layout 2019-07-26 16:25:36 +02:00
Thomas Berrod 8951d83423 401 redirect to login 2019-07-26 15:23:23 +02:00
Thomas Berrod 3a0e9c1938 cyp tag + 2019-07-26 12:21:58 +02:00
Thomas Berrod eb27aa74ab OffreDetail Component added 2019-07-26 12:21:44 +02:00
Thomas Berrod 20bf564648 Mes candidatures WIP 2019-07-26 12:18:08 +02:00
Sébastien GLATZ bda3eb3302 Add Cypress tag for tests 2019-07-26 12:03:41 +02:00
Sébastien GLATZ 3ad44318b1 Little fix 2019-07-26 09:55:16 +02:00
Sébastien GLATZ f703a2bd8f Fix newsletter and install app responsive 2019-07-26 09:55:04 +02:00
Sébastien GLATZ 55c921c214 Fix header bottom spacing 2019-07-26 09:54:39 +02:00
Sébastien GLATZ 6188dc60a8 Fix appbar shadow 2019-07-26 09:54:10 +02:00
Sébastien GLATZ fd4bad6477 Add style for responsive 2019-07-25 16:28:41 +02:00
Sébastien GLATZ 7fa2bb1e10 Add style for responsive 2019-07-25 16:28:18 +02:00
Sébastien GLATZ 3c5b4f4f24 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-25 11:22:04 +02:00
Sébastien GLATZ dbcb06cac8 Appbar responsive 2019-07-25 11:21:57 +02:00
Sébastien GLATZ af417f1b3d Color update 2019-07-25 11:21:36 +02:00
Thomas Berrod 7d918ad5ec fix store persistance issues 2019-07-25 10:31:23 +02:00
Thomas Berrod 569f7aac9f last updates on PersistStore 2019-07-24 17:51:25 +02:00
Thomas Berrod 92df989fe3 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-24 17:02:00 +02:00
Thomas Berrod ba116d0919 Store persistance work in progress 2019-07-24 17:01:56 +02:00
Thomas Berrod 6e553077d2 Company fix 2019-07-24 17:01:06 +02:00
Sébastien GLATZ d2a87c0daa Fix button hover 2019-07-24 16:20:28 +02:00
Sébastien GLATZ abfe12415f Desktop responsive 2019-07-24 16:20:16 +02:00
Sébastien GLATZ 57dac37437 Change footer call 2019-07-24 16:19:46 +02:00
Sébastien GLATZ 4df163eb30 Add new logo region svg 2019-07-24 16:19:15 +02:00
Sébastien GLATZ 3b5bb425a1 Update style responsive 2019-07-24 13:36:47 +02:00
Sébastien GLATZ bbe9970485 Little fix 2019-07-24 08:42:17 +02:00
Sébastien GLATZ 037424f103 Fix menu inline 2019-07-24 08:42:11 +02:00
Sébastien GLATZ 6f4530c63c Add loader to horizontal scroller 2019-07-24 08:35:54 +02:00
Thomas Berrod 551b6af2d5 persist store 2019-07-23 17:26:36 +02:00
Thomas Berrod 570c8482f6 Mes candidatures start 2019-07-23 17:11:53 +02:00
Thomas Berrod fe84754a0e Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-23 16:25:47 +02:00
Thomas Berrod 8cc797f2ca Candidatures 2019-07-23 16:25:31 +02:00
Sébastien GLATZ 825e658401 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-23 16:13:06 +02:00
Sébastien GLATZ 416758c178 Import fix 2019-07-23 16:12:22 +02:00
Sébastien GLATZ 398b2ab85a Add style 2019-07-23 16:12:13 +02:00
Sébastien GLATZ 40e272ade1 Add custom loader and new component Loader 2019-07-23 16:11:47 +02:00
Sébastien GLATZ fb3809039f Little fix 2019-07-23 16:11:04 +02:00
Sébastien GLATZ 199bfb3ccb Use withWidth 2019-07-23 16:10:42 +02:00
Sébastien GLATZ 7f571b3917 Verify email + pass email to component 2019-07-23 16:09:18 +02:00
Sébastien GLATZ d4640944ee Add custom pagination 2019-07-23 16:08:29 +02:00
Thomas Berrod 61891d7cd7 menu lwhen logged in 2019-07-23 12:22:53 +02:00
Thomas Berrod 035137df0f Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-23 11:33:53 +02:00
Thomas Berrod 7354b66453 Candidature(s) ready to dev 2019-07-23 11:33:46 +02:00
Sébastien GLATZ 652d3bac27 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-23 08:12:56 +02:00
Sébastien GLATZ b6c35ba444 Style little fix 2019-07-23 08:10:50 +02:00
Sébastien GLATZ 9bb874ae2f Add inscription in url 2019-07-23 08:10:37 +02:00
Sébastien GLATZ 7ce22883d2 Add props align 2019-07-23 08:10:00 +02:00
Sébastien GLATZ 2d6210c1e7 Mail confirmation after register 2019-07-23 08:09:14 +02:00
Sébastien GLATZ 8f6c22d109 Add new layout 2019-07-23 08:07:52 +02:00
Thomas Berrod 2c4bff2e7d company ads stall 2019-07-22 11:50:43 +02:00
Sébastien GLATZ 4f66501811 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-19 16:24:16 +02:00
Sébastien GLATZ 3ad52a1e0b Bug expected string but go object 2019-07-19 16:24:02 +02:00
Thomas Berrod b3c335fb25 update user success 2019-07-19 15:20:43 +02:00
Thomas Berrod f1383d875e pending work on response 2019-07-19 12:05:47 +02:00
Sébastien GLATZ 648517180a Add back arrow on scroll up 2019-07-19 11:41:11 +02:00
Sébastien GLATZ 539e2d301f Add company detail + content collapse 2019-07-19 11:40:40 +02:00
Sébastien GLATZ dfe4a9aeef Add default avatar file 2019-07-18 10:16:00 +02:00
Sébastien GLATZ ddae8c9b82 Filter style on lists 2019-07-18 10:08:24 +02:00
Sébastien GLATZ 0f1762312f Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-18 09:52:38 +02:00
Sébastien GLATZ b22c9f7fbd Little fix 2019-07-18 09:52:12 +02:00
Thomas Berrod daeb381f8b Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-18 09:51:29 +02:00
Thomas Berrod f19d065c37 company stalling 2019-07-18 09:51:16 +02:00
Sébastien GLATZ 258ad73daa Little fix 2019-07-18 08:46:28 +02:00
Sébastien GLATZ d2eb717aab Fix logo header 2019-07-18 08:46:11 +02:00
Thomas Berrod 860b420608 fix Company saga 2019-07-17 16:47:02 +02:00
Sébastien GLATZ 3f18f70649 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
# Conflicts:
#	nextjs/components/templates/Grid.js
2019-07-17 16:18:57 +02:00
Sébastien GLATZ b6ab0bfd2b Little fix 2019-07-17 16:18:23 +02:00
Sébastien GLATZ b17f156f38 Add request answer 2019-07-17 16:18:01 +02:00
Sébastien GLATZ 9a333d58c4 Add request answer 2019-07-17 16:17:45 +02:00
Thomas Berrod 58c34e6c47 grid aucun résultat 2019-07-17 15:44:40 +02:00
Thomas Berrod 1869fa4a07 search bar working 2019-07-17 15:36:55 +02:00
Thomas Berrod 8a16b8a47a search bar working 2019-07-17 15:34:20 +02:00
Sébastien GLATZ 212a2a1afc Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
# Conflicts:
#	nextjs/components/templates/Grid.js
2019-07-17 15:23:46 +02:00
Sébastien GLATZ e4c2b7fe2c clean imports & styles + classes in CamelCase 2019-07-17 15:20:17 +02:00
Thomas Berrod 788c58ecad api merge 2019-07-17 14:49:36 +02:00
Thomas Berrod 4860438487 bug fix onapi fetchcompanies 2019-07-17 14:47:15 +02:00
Sébastien GLATZ ec8d55640d Bug: add company request 2019-07-17 14:40:53 +02:00
Sébastien GLATZ 1ac2510ca3 Little fix 2019-07-17 14:39:58 +02:00
Sébastien GLATZ 53a7045e43 Bug : add company request saga 2019-07-17 14:38:46 +02:00
Sébastien GLATZ b368f477ca Add layout company 2019-07-17 14:13:06 +02:00
Sébastien GLATZ 87346e9ac5 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
# Conflicts:
#	nextjs/components/organisms/TileCompany.js
2019-07-17 09:43:15 +02:00
Sébastien GLATZ 8565f2142e Little fix provided ads 2019-07-17 09:41:52 +02:00
Thomas Berrod 24b957365f Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-17 09:37:07 +02:00
Thomas Berrod 39a86b5a62 emphasis Companies 2019-07-17 09:36:38 +02:00
Sébastien GLATZ 6febb3a654 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-16 15:40:54 +02:00
Sébastien GLATZ 409c396e68 Little fix 2019-07-16 15:40:46 +02:00
Sébastien GLATZ ecf6605eb5 Edit page help 2019-07-16 15:40:29 +02:00
Sébastien GLATZ d88c50e3bb New component SocialButtonsAuth on Login and Register 2019-07-16 15:40:11 +02:00
Sébastien GLATZ a1f8618843 Update material UI 2019-07-16 15:39:30 +02:00
Sébastien GLATZ d9820e49e0 Little fix 2019-07-16 15:39:05 +02:00
Thomas Berrod 8b876369c3 fix pourvues 2019-07-16 14:13:54 +02:00
Thomas Berrod 86aa81bdcc fix promoted 2019-07-16 11:31:12 +02:00
Thomas Berrod 23c38245a3 emphasis 2019-07-16 11:19:05 +02:00
Sébastien GLATZ 48b8851657 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
# Conflicts:
#	nextjs/data/api.js
2019-07-16 09:13:23 +02:00
Sébastien GLATZ 2ed985518d Add offer to answer 2019-07-16 09:10:50 +02:00
Sébastien GLATZ 9d06e89f5f Bug: get promoted(pourvue) ads 2019-07-16 09:10:16 +02:00
Sébastien GLATZ 3a49f735b6 Edit page help 2019-07-16 09:09:16 +02:00
Sébastien GLATZ 69b1e087f9 Little fix 2019-07-16 09:08:34 +02:00
Thomas Berrod 980fc787bc social shar 2019-07-15 17:32:23 +02:00
Thomas Berrod 39f33690dc Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-12 17:03:40 +02:00
Thomas Berrod 0f81c9bab8 enableVideo in config 2019-07-12 17:03:27 +02:00
Sébastien GLATZ ad98b0513a Transfer data from offer to answer 2019-07-12 16:35:27 +02:00
Thomas Berrod f891479456 manifest orientation 2019-07-12 16:16:50 +02:00
Thomas Berrod fcc5bcad86 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-12 15:47:48 +02:00
Thomas Berrod 9c4364f082 snack off newsletter 2019-07-12 15:47:26 +02:00
Sébastien GLATZ ee8de0330e Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-12 15:43:40 +02:00
Sébastien GLATZ 95d906066f Little fix 2019-07-12 15:43:35 +02:00
Sébastien GLATZ b42d5abbb1 Add style to Answer 2019-07-12 15:43:21 +02:00
Sébastien GLATZ 5f886f2a10 Add RootContainer to all Layouts 2019-07-12 15:42:46 +02:00
Thomas Berrod bfcf73ae74 linkedin bug fix 2019-07-12 15:34:13 +02:00
Thomas Berrod 769d07440d pwa install 2019-07-12 15:25:19 +02:00
Thomas Berrod 435e6ad725 newsletter btn fix 2019-07-12 15:25:03 +02:00
Thomas Berrod f569ff237e manifest + PWA compliance 2019-07-12 12:04:48 +02:00
Thomas Berrod b85a4c9085 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-12 09:44:10 +02:00
Thomas Berrod b3b953196e dot env added (must yarn install) 2019-07-12 09:41:34 +02:00
Sébastien GLATZ baa0cfa8c1 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
# Conflicts:
#	nextjs/pages/Login.js
2019-07-11 14:12:00 +02:00
Thomas Berrod 9b82a9cf59 .env 2019-07-11 14:08:02 +02:00
Sébastien GLATZ 39cd6cba2a fix .gitignore 2019-07-11 14:07:48 +02:00
Thomas Berrod 7b1aee8a44 gitignore 2019-07-11 14:07:43 +02:00
Sébastien GLATZ e04465a751 Add fg-loadcss 2019-07-11 14:07:24 +02:00
Sébastien GLATZ 09b586d94d Add style answer 2019-07-11 14:04:37 +02:00
Sébastien GLATZ 48ac5c7d2c Little fix 2019-07-11 14:04:20 +02:00
Sébastien GLATZ 43d9a05bd6 Add style for login and register 2019-07-11 14:03:55 +02:00
Sébastien GLATZ 68f44ab006 Add company list 2019-07-11 14:03:16 +02:00
Sébastien GLATZ 554c641c33 Add svg for answer 2019-07-11 14:02:49 +02:00
Sébastien GLATZ 633e89628c Add component SocialShare for offer detail 2019-07-11 14:01:59 +02:00
Sébastien GLATZ 5012b1e97a Update theme 2019-07-11 14:00:59 +02:00
Thomas Berrod 6d72c814d0 server url global 2019-07-11 11:48:08 +02:00
Thomas Berrod 57d1e641a5 ecosystem 2019-07-10 17:55:57 +02:00
Thomas Berrod 0b392222cf .env exclu 2019-07-10 17:45:43 +02:00
Thomas Berrod e05f5c2b8f mangling 2019-07-10 17:44:47 +02:00
Thomas Berrod 9a3bd880fb prod switch 2019-07-10 17:40:42 +02:00
Thomas Berrod 07b5e79d2b KeyboardArrowLeft uppercase 2019-07-09 17:37:09 +02:00
Thomas Berrod c1e3c17504 snack case fix 2019-07-09 17:31:26 +02:00
Thomas Berrod 354fefdae6 case sensitivness 2019-07-09 17:28:23 +02:00
Thomas Berrod ba4aba6a6d preprod directives 2019-07-09 15:36:45 +02:00
Thomas Berrod f392062ece variables globales 2019-07-09 14:17:33 +02:00
Thomas Berrod 927eb81017 fix login 2019-07-08 18:47:20 +02:00
Thomas Berrod ee4ef59ed3 fix forms login error message 2019-07-08 18:04:23 +02:00
Sébastien GLATZ 063fb19dbd Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-08 09:58:43 +02:00
Sébastien GLATZ 9169ee38ad Update detail offer 2019-07-08 09:58:37 +02:00
Sébastien GLATZ e68b61ce35 Little fix 2019-07-08 09:58:22 +02:00
Thomas Berrod 1f901b9a0a insight : Plyr 404 on .json to load poster image 2019-07-08 09:50:21 +02:00
Thomas Berrod 3abfff129c Icontext proptypes fix 2019-07-08 09:40:13 +02:00
Thomas Berrod 1267aa15b1 flush ttJWT when expired 2019-07-05 17:22:48 +02:00
Sébastien GLATZ 60e22554a8 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-05 15:33:16 +02:00
Sébastien GLATZ 72d98e057c Little fix 2019-07-05 15:33:10 +02:00
Sébastien GLATZ 0706fda67c Add offer list and offer detail 2019-07-05 15:32:37 +02:00
Thomas Berrod 1bdbd2f77d warning fixes 2019-07-05 15:31:37 +02:00
Thomas Berrod 4daa99a020 displayName fix 2019-07-05 09:47:45 +02:00
Sébastien GLATZ 89221a04ed Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-05 08:14:48 +02:00
Sébastien GLATZ 765075e99b Update home and navigation style + footer 2019-07-05 08:14:42 +02:00
Thomas Berrod 245f09b20f linkedin + facebook stalling 2019-07-04 17:20:43 +02:00
Thomas Berrod d2649fdc16 litlle bugs 2019-07-03 17:24:29 +02:00
Thomas Berrod 2c08e9e68b snack + newsletter 2019-07-03 17:10:14 +02:00
Sébastien GLATZ 5009409a51 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
# Conflicts:
#	nextjs/reducers/user.js
2019-07-03 16:43:27 +02:00
Sébastien GLATZ a8e4e739a2 Home video 2019-07-03 16:41:16 +02:00
Sébastien GLATZ e1579a9d1d Newsletter 2019-07-03 16:40:58 +02:00
Thomas Berrod 21510e7b71 register loop + menage 2019-07-03 14:44:35 +02:00
Sébastien GLATZ 59782cda43 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-07-03 08:24:28 +02:00
Sébastien GLATZ 6947ba6b33 Update parameters 2019-07-03 08:24:19 +02:00
Sébastien GLATZ 71ad5427cb Add style for home video 2019-07-03 08:23:44 +02:00
Sébastien GLATZ c14de8e119 Add style on navigation 2019-07-03 08:23:25 +02:00
Sébastien GLATZ 7e67bdcb45 Update theme colors 2019-07-03 08:23:04 +02:00
Thomas Berrod 5a0267e20f register forms + confirm email + verify email 2019-07-02 17:13:14 +02:00
Sébastien GLATZ aa3ef3456d Integration home page horizontal scroller and news 2019-06-28 15:30:24 +02:00
Sébastien GLATZ 03c01d842d Update general style 2019-06-28 15:28:48 +02:00
Sébastien GLATZ 502490ced1 Update layout height without footer 2019-06-28 15:27:29 +02:00
304 changed files with 90794 additions and 22453 deletions
-3
View File
@@ -1,3 +0,0 @@
nextjs/node_modules/
/node_modules/
/nextjs/node_modules/
+3
View File
@@ -0,0 +1,3 @@
{
"git.ignoreLimitWarning": true
}
+1
View File
@@ -0,0 +1 @@
/volume/
+50
View File
@@ -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)
+28
View File
@@ -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.
+17
View File
@@ -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:
+5
View File
@@ -0,0 +1,5 @@
{
"dependencies": {
"cypress": "^3.4.1"
}
}
+1217
View File
File diff suppressed because it is too large Load Diff
-25
View File
@@ -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
View File
@@ -1,4 +1,8 @@
/node_modules/
.next/
.gitignore
.env
ecosystem.config.js
yarn-error.log
robots.txt
/out/
yarn.lock
+18
View File
@@ -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
+43
View File
@@ -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
View File
@@ -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 lapplication 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
View File
+47 -27
View File
@@ -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
});
+94
View File
@@ -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
View File
@@ -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
});
+43
View File
@@ -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
});
+25
View File
@@ -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
View File
@@ -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
})
+18
View File
@@ -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);
+84
View File
@@ -0,0 +1,84 @@
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} 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,94 @@
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, 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://localhost/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}
</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>
);
}
+44 -14
View File
@@ -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);
+62
View File
@@ -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);
+39
View File
@@ -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
+113
View File
@@ -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);
+36
View File
@@ -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)
+47
View File
@@ -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
+51
View File
@@ -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);
+129
View File
@@ -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>
);
}
+29
View File
@@ -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
}
+18
View File
@@ -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
+87
View File
@@ -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: "",
};
+177
View File
@@ -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);
+138
View File
@@ -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
+106
View File
@@ -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);
+164 -9
View File
@@ -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 denvoi..." texteSecondaire="Veuillez rester sur la page pendant le chargement qui peut durer plusieurs minutes."/> : <div></div> }
<div className={classes.root}>
<Hidden xsUp>
&nbsp;
</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>
&nbsp;
</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>&nbsp;</Hidden>
<Hidden>&nbsp;</Hidden>
<Hidden>&nbsp;</Hidden>
<Hidden>&nbsp;</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>&nbsp;</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 denvoi..." 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>&nbsp;</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}
&nbsp; {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&amp;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 davancement 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>&nbsp;</Hidden>
// <Hidden>&nbsp;</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>&nbsp;</Hidden>
// <Card
// variant="outlined"
// style={{
// width: 420 + "px",
// textAlign:"center"
// }}>
// <CardContent>
// <AccountEtape3></AccountEtape3>
// </CardContent>
// </Card>
// <Hidden>&nbsp;</Hidden>
// <Hidden>&nbsp;</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))
+147
View File
@@ -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;
+849
View File
@@ -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>&nbsp;</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))
+263
View File
@@ -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 dinformations"]
,
["CONTACTED"
, "Demande dinformations"]
,
["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>
);
}
+150
View File
@@ -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)
+113 -88
View File
@@ -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>
);
}
}
+284 -7
View File
@@ -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;
+595 -192
View File
@@ -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="/indexTalent" >
<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="/indexTalent" >
<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="/indexTalent" >
<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="/indexTalent" >
<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="/indexTalent" >
<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))));
+103 -20
View File
@@ -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
+125 -83
View File
@@ -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>
);
}
}
+99 -55
View File
@@ -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>
}
}
+244 -37
View File
@@ -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 lenregistrement",
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>
);
+220 -88
View File
@@ -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,75 @@ const styles = theme => ({
display: 'flex',
flexDirection: 'column',
},
input50: {
width: '50%',
formText: {
padding: theme.spacing(0, 2),
paddingTop: theme.spacing(3),
fontSize: '0.9em',
fontWeight: '300',
},
checkboxError:{
color:'red'
}
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),
},
});
class Register extends React.Component {
@@ -38,14 +108,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 +136,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 +166,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 +191,54 @@ 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>
<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 +248,102 @@ 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`} >Lien vers 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>
<Snack name= 'snackWarning'
variant= 'warning'
message={errors.message}
/>
</div>
);
}
}
@@ -226,7 +351,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
}
};
}
+134 -54
View File
@@ -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 dimpression', 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))
+123
View File
@@ -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>
);
}
+62 -55
View File
@@ -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);
+46 -27
View File
@@ -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);
+51 -28
View File
@@ -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>
);
+3 -2
View File
@@ -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() {
-24
View File
@@ -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)
+277 -51
View File
@@ -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);
+10 -28
View File
@@ -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>
)
}
+184
View File
@@ -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))
+20 -18
View File
@@ -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)
+118 -48
View File
@@ -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)
+25 -97
View File
@@ -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)
+10
View File
@@ -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()
})
})
+1
View File
@@ -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"]}}
+1
View File
@@ -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}
+52
View File
@@ -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
Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

+46
View File
@@ -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)
})
})
+31
View File
@@ -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