Compare commits

...

77 Commits

Author SHA1 Message Date
llaniau 1276a73c21 Chgt proprs en state pour tel, etc 2021-01-05 17:46:13 +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
84 changed files with 5488 additions and 870 deletions
+27 -27
View File
@@ -1,13 +1,13 @@
import {
FETCH_ADS_REQUEST,
FETCH_ADS_SUCCESS,
FETCH_ADS_FAILURE,
FETCH_AD_REQUEST,
FETCH_AD_SUCCESS,
FETCH_AD_FAILURE,
FETCH_EMPHASIS_ADS_REQUEST,
FETCH_EMPHASIS_ADS_SUCCESS,
FETCH_EMPHASIS_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
@@ -28,52 +28,52 @@ export const togglePromotedFilterRequest = () => ({
//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 fetchEmphasisAdsRequest = (payload) => ({
type: FETCH_EMPHASIS_ADS_REQUEST,
export const fetchEmphasisJobsRequest = (payload) => ({
type: FETCH_EMPHASIS_JOBS_REQUEST,
payload
});
export const fetchEmphasisAdsSuccess = res => ({
type: FETCH_EMPHASIS_ADS_SUCCESS,
export const fetchEmphasisJobsSuccess = res => ({
type: FETCH_EMPHASIS_JOBS_SUCCESS,
res
});
export const fetchEmphasisAdsFailure = res => ({
type: FETCH_EMPHASIS_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
});
+9 -9
View File
@@ -2,9 +2,9 @@ import {
POST_AD_ANSWER_REQUEST,
POST_AD_ANSWER_FAILURE,
POST_AD_ANSWER_SUCCESS,
FETCH_ADS_ANSWER_REQUEST,
FETCH_ADS_ANSWER_SUCCESS,
FETCH_ADS_ANSWER_FAILURE,
FETCH_JOBS_ANSWER_REQUEST,
FETCH_JOBS_ANSWER_SUCCESS,
FETCH_JOBS_ANSWER_FAILURE,
FETCH_ANSWER_REQUEST,
FETCH_ANSWER_SUCCESS,
FETCH_ANSWER_FAILURE,
@@ -47,19 +47,19 @@ export const postMessageAnswerSuccess = res => ({
});
export const fetchAdsAnsweredRequest = payload => ({
type: FETCH_ADS_ANSWER_REQUEST,
export const fetchJobsAnsweredRequest = payload => ({
type: FETCH_JOBS_ANSWER_REQUEST,
payload
});
export const fetchAdsAnsweredSuccess = res => ({
type: FETCH_ADS_ANSWER_SUCCESS,
export const fetchJobsAnsweredSuccess = res => ({
type: FETCH_JOBS_ANSWER_SUCCESS,
res
});
export const fetchAdsAnsweredFailure = errors => ({
type: FETCH_ADS_ANSWER_FAILURE,
export const fetchJobsAnsweredFailure = errors => ({
type: FETCH_JOBS_ANSWER_FAILURE,
errors
});
+1 -17
View File
@@ -5,9 +5,6 @@ import {
UPLOAD_MEDIA_PRES_REQUEST,
UPLOAD_MEDIA_PRES_FAILURE,
UPLOAD_MEDIA_PRES_SUCCESS,
UPLOAD_MEDIA_CV_REQUEST,
UPLOAD_MEDIA_CV_FAILURE,
UPLOAD_MEDIA_CV_SUCCESS,
} from "../types";
@@ -41,19 +38,6 @@ import {
res
});
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
});
+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
});
+1 -1
View File
@@ -75,7 +75,7 @@ export default function ChatCard(props) {
className={classes.messageDate}
align="center"
>
Envoyée le {(new Date(props.message.c_time)).toLocaleDateString("fr-FR")} à {(new Date(props.message.c_time)).toLocaleTimeString("fr-FR")}
Envoyé le {(new Date(props.message.c_time)).toLocaleDateString("fr-FR")} à {(new Date(props.message.c_time)).toLocaleTimeString("fr-FR")}
</Typography>
</Fragment>
)
+4
View File
@@ -8,6 +8,8 @@ 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';
const variantIcon = {
assignment: AssignmentIcon,
@@ -15,6 +17,8 @@ const variantIcon = {
location_on: LocationOnIcon,
business_center: BusinessCenterIcon,
business: Business,
watch_later: WatchLater,
home: Home,
};
const styles = theme => ({
@@ -4,6 +4,8 @@ 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 Typography from '@material-ui/core/Typography';
import Business from '@material-ui/icons/Business';
@@ -12,6 +14,8 @@ const variantIcon = {
assignment: AssignmentIcon,
room: RoomIcon,
location_on: LocationOnIcon,
home: HomeOnIcon,
watch_later: WatchLater,
business_center: BusinessCenterIcon,
business: Business,
};
+8 -3
View File
@@ -5,19 +5,24 @@ const JobPosting = props => {
return (
<JobPostingJsonLd
datePosted="2020-01-06T03:37:40Z"
datePosted={props.job_date}
description={props.job_description}
hiringOrganization={{
name: props.job_brand,
sameAs: props.job_brand_link,
}}
jobLocation={{
addressLocality: props.job_location,
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="2020-01-06"
validThrough={props.job_date_fin}
applicantLocationRequirements="FR"
employmentType = {props.job_contract_type + ","+props.job_temps_type }
/>
+8 -4
View File
@@ -1,13 +1,13 @@
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="robots" content="noindex, nofollow"></meta>
<meta name="description" kenoindexy="description" content={props.seo_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" />
@@ -22,9 +22,13 @@ const OgHead = props => {
<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_title}/>
<meta name="twitter:description" content={props.seo_description}/>
<meta name="twitter:image" content={props.image}/>
<link rel="canonical" href={ props.seo_url} />
{/* <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>
)
+2 -4
View File
@@ -94,7 +94,7 @@ const useStyles = makeStyles(theme => ({
export default function SimpleCollapse(props) {
const classes = useStyles();
const [expanded, setExpanded] = React.useState(false);
const [expanded, setExpanded] = React.useState(true);
function handleExpandClick() {
setExpanded(!expanded);
@@ -111,12 +111,10 @@ export default function SimpleCollapse(props) {
</Collapse>
<CardActions disableSpacing classes={{ root: classes.rootCardAction }}>
<IconButton
onClick={handleExpandClick}
aria-expanded={expanded}
aria-label="Afficher plus"
aria-label="Afficher plus "
> <Typography className={classes.displayMore}>
{(!expanded) ? 'Afficher plus' : 'Afficher moins'}
</Typography>
+34 -26
View File
@@ -7,6 +7,7 @@ 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,
@@ -60,7 +61,7 @@ const styles = theme => ({
const { publicRuntimeConfig } = getConfig();
//https://xd.adobe.com/view/ba98331a-9145-4d67-7e27-25a36e519ef4-cca9/screen/a96779d7-bdb3-410a-8f19-e6987acb98ee/Candidature-Step-3
class Accountdetails extends Component {
class AccountEtape1 extends Component {
constructor(props) {
super(props);
@@ -112,7 +113,8 @@ class Accountdetails extends Component {
onBlur(e) {
console.log("blur")
this.setState({ [e.target.name]: e.target.value });
this.soumettre();
this.soumettre(e.target.name, "unitaire");
}
@@ -158,12 +160,16 @@ class Accountdetails extends Component {
onSubmit = (e) => {
e.preventDefault();
this.soumettre(e);
console.log("submit")
console.log(e.keyCode)
this.soumettre(e.target.name, "global")
}
soumettre(e){
const errors = this.validate(this.state);
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){
@@ -191,18 +197,19 @@ class Accountdetails extends Component {
}
}
validate = 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 (!data.firstname || data.firstname==="") errors.message += "Veuillez saisir votre prénom<br />";
if (!data.lastname || data.lastname==="") errors.message += " Veuillez saisir saisir votre nom<br />";
if (!data.phone || data.phone==="") errors.message += "Veuillez saisir un numéro de téléphone valide<br />";
if (!data.currentJob || data.currentJob==="") errors.message += "Veuillez saisir votre intitulé de poste actuel ou poste recherché<br />";
if ((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 />";
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;
@@ -361,7 +368,7 @@ class Accountdetails extends Component {
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.currentJob && this.state.currentJob !='null' ? this.state.currentJob : ''}
value={this.state.currentJob ? this.state.currentJob : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
@@ -373,7 +380,7 @@ class Accountdetails extends Component {
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.address1 && this.state.address1 !='null' ? this.state.address1 : ''}
value={this.state.address1 ? this.state.address1 : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
@@ -385,7 +392,7 @@ class Accountdetails extends Component {
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.address2 && this.state.address2 !='null' ? this.state.address2 : ''}
value={this.state.address2 ? this.state.address2 : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
@@ -397,7 +404,7 @@ class Accountdetails extends Component {
className={classes.textField}
classes={{ root: classes.textFieldSmall }}
variant="outlined"
value={this.state.zipCode && this.state.zipCode !='null' ? this.state.zipCode : ''}
value={this.state.zipCode ? this.state.zipCode : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
@@ -409,7 +416,7 @@ class Accountdetails extends Component {
className={classes.textField}
classes={{ root: classes.textFieldSmall }}
variant="outlined"
value={this.state.city && this.state.city !='null' ? this.state.city : ''}
value={this.state.city ? this.state.city : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
@@ -421,7 +428,7 @@ class Accountdetails extends Component {
className={classes.textField}
classes={{ root: classes.textFieldSmall }}
variant="outlined"
value={this.state.country && this.state.country !='null' ? this.state.country : ''}
value={this.state.country ? this.state.country : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
@@ -435,7 +442,7 @@ class Accountdetails extends Component {
classes={{ root: classes.rootTextfield }}
variant="outlined"
placeholder="http://www.linkedin.com/in/"
value={this.state.linkedin && this.state.linkedin !='null' ? this.state.linkedin : ''}
value={this.state.linkedin ? this.state.linkedin : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
@@ -449,7 +456,7 @@ class Accountdetails extends Component {
classes={{ root: classes.rootTextfield }}
variant="outlined"
placeholder="http://twitter.com/.."
value={this.state.twitter && this.state.twitter !='null' ? this.state.twitter : ''}
value={this.state.twitter ? this.state.twitter : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
@@ -462,14 +469,15 @@ class Accountdetails extends Component {
classes={{ root: classes.rootTextfield }}
variant="outlined"
placeholder="http://monsite.fr"
value={this.state.website && this.state.website !='null' ? this.state.website : ''}
value={this.state.website ? this.state.website : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<Button
type="submit"
variant="contained"
color="primary"
onClick={refresh}
className={classes.button}>
Enregistrer
</Button>
@@ -492,4 +500,4 @@ function mapStateToProps(state, ownProps) {
};
}
export default withStyles(styles)(connect(mapStateToProps, { updateUserRequest })(Accountdetails))
export default withStyles(styles)(connect(mapStateToProps, { updateUserRequest })(AccountEtape1));
+51 -6
View File
@@ -12,7 +12,7 @@ import {fetchCompanyRequest} from '../../actions/companies'
import {fetchCurrentUserRequest} from '../../actions/user'
import VideoVimeo from '../atoms/VideoVimeo'
import Router from 'next/router'
import Loader from '../templates/loader'
import LoaderVideo from '../templates/loaderVideo'
import Ar from "lodash/array"
import Snackbar from '@material-ui/core/Snackbar';
import { Alert, AlertTitle } from '@material-ui/lab';
@@ -71,6 +71,16 @@ const styles = theme => ({
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,
@@ -94,6 +104,9 @@ const styles = theme => ({
fontSize: '2.5em',
color: "#1689FB",
textAlign: "right"
},
buttons :{
display: "inline-table",
}
});
const Recorder = dynamic(() => import ('../organisms/Recorder'), {ssr: false})
@@ -109,7 +122,7 @@ class Etape2 extends React.Component {
componentDidMount() {
localStorage.setItem('loginRedirect', window.location)
localStorage.setItem('loginRedirect', window.location.pathname)
if (!!!localStorage.getItem('ttJWT')) {
Router.push("/Login")
@@ -135,7 +148,7 @@ class Etape2 extends React.Component {
//window.location.reload(false);
if (nextProps.media.status === 'success') {
const success = {};
success.message ="Vidéo mis à jour";
success.message ="Vidéo mise à jour";
this.setState({ success });
this.setActiveStep(1);
}
@@ -197,7 +210,7 @@ class Etape2 extends React.Component {
<section className={classes.container}>
<Fragment>
{this.AfficherSuccess()}
{ loading ? <Loader/> : <div></div> }
{ loading ? <LoaderVideo/> : <div></div> }
<div className={classes.root}>
<Hidden xsUp>
@@ -208,11 +221,43 @@ class Etape2 extends React.Component {
<Grid container
justify="center"
alignItems="center"
spacing={2}>
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>
@@ -253,7 +298,7 @@ class Etape2 extends React.Component {
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 réponse
J'<span className={classes.underlined}>importe</span> ma vidéo de présentation
</Typography>
<KeyboardArrowDownIcon className={classes.InputKeyboardArrowDownIcon}/>
+38 -14
View File
@@ -2,13 +2,13 @@ import React, { Fragment } from 'react';
import { connect } from "react-redux";
import { fetchCurrentUserRequest } from '../../actions/user'
import { fetchCompanyRequest } from '../../actions/companies'
import { uploadMediaCv } from '../../actions/media'
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 Loader from '../../components/templates/loader'
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';
@@ -47,7 +47,7 @@ const styles = theme => ({
backgroundColor: theme.palette.secondary.main,
padding: theme.spacing(3, 2),
margin: theme.spacing(1),
width: "400px",
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': {
@@ -69,7 +69,7 @@ class Etape3 extends React.Component {
};
componentDidMount() {
localStorage.setItem('loginRedirect', window.location)
localStorage.setItem('loginRedirect', window.location.pathname)
if(!!!localStorage.getItem('ttJWT'))
{
@@ -134,22 +134,44 @@ class Etape3 extends React.Component {
AfficherLienCv() {
console.log("afficher lien");
if (this.props.user.cv !="") {
if (this.state.cvLink !="") {
return (
<Fragment>
<Hidden>&nbsp;</Hidden>
<Hidden>&nbsp;</Hidden>
<Divider style={{width:400+"px"}}/>
<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>
<Card variant="outlined" style={{width:400+"px"}}>
<CardActions>
<Button size="small">Mon CV numérique</Button>
<Button size="small">MON CV</Button>
</CardActions>
<CardContent>
<Typography>
<a href={publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.postedContentCv + this.state.cvLink} target="_blank">Lien vers le cv téléchargé</a><br />
<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>
@@ -169,7 +191,7 @@ class Etape3 extends React.Component {
return (
<Fragment>
{ loading ?
<Loader /> :
<LoaderVideo /> :
<Fragment>
{this.AfficherSuccess()}
@@ -185,11 +207,13 @@ class Etape3 extends React.Component {
<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 au format PDF
J'<span className={classes.underlined}>importe</span> mon CV
</Typography>
<KeyboardArrowDownIcon className={ classes. InputKeyboardArrowDownIcon }/>
</Button>
</label>
<Hidden>&nbsp;</Hidden>
{this.AfficherLienCv()}
</Fragment>
@@ -208,7 +232,7 @@ Etape3.getInitialProps = function (context) {
context.store.dispatch(fetchCurrentUserRequest())
if(!!adId)
context.store.dispatch(fetchAdRequest(adId))
context.store.dispatch(fetchJobRequest(adId))
else if(!!companyId)
context.store.dispatch(fetchCompanyRequest(companyId))
@@ -222,7 +246,7 @@ function mapStateToProps(state) {
// console.log(state.media.message)
return {
user: state.user ,
cvLink : state.media.message,
cvLink : state.mediaCv.message,
loading: !!state.media.loading,
cv : true,
//errors: errorMessageSelector(state),
@@ -293,7 +293,7 @@ const AccountProfile = props => {
: {user.phone}<br/>
<LinkedInIcon className={classes.menuButton}/>
: {(user.linkedin && user.linkedin != '' && user.linkedin != 'null')
? <a href={user.linkedin} target="_blank">Lien sur mon linkendIn</a>
? <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')
@@ -321,13 +321,13 @@ const AccountProfile = props => {
<DuoIcon className={classes.menuButton}/>
: {(user.alias && user.alias != '' && user.alias != 'null')
? <a
href={publicRuntimeConfig.cvThequeUrl + "talent/" + user.alias}
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-href={publicRuntimeConfig.cvThequeUrl + "/talent/" + user.alias}
data-layout="button_count"
data-size="small">
@@ -335,7 +335,7 @@ const AccountProfile = props => {
:
<a
target="_blank"
href={"https://www.facebook.com/sharer/sharer.php?u=" + publicRuntimeConfig.cvThequeUrl + "talent/" + user.alias + "%2F&amp;src=sdkpreparse"}
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>
@@ -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))
+388 -52
View File
@@ -1,6 +1,6 @@
import React, { Component, Fragment } from 'react'
import React, { Component, Fragment, useState } from 'react'
import { withStyles } from '@material-ui/core/styles';
import { Button, Typography } from '@material-ui/core';
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'
@@ -10,6 +10,26 @@ 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: {
@@ -61,10 +81,7 @@ const styles = theme => ({
},
rootButton: {
textTransform: 'inherit',
border: '1px solid',
'&:hover': {
border: '1px solid',
},
},
button: {
textTransform: 'inherit',
@@ -74,34 +91,72 @@ const styles = theme => ({
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.important,
},
importButton: {
color: theme.palette.primary.main,
backgroundColor: theme.palette.secondary.main,
padding: theme.spacing(3, 2),
margin: theme.spacing(1),
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.14)',
'&:hover': {
backgroundColor: theme.palette.secondary.main,
},
InputKeyboardArrowRightIcon: {
fontSize: '2.5em',
color: theme.palette.secondary.main,
},
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"
}
});
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);
// This binding is necessary to make `this` work in the callback
this.onSubmit = this.onSubmit.bind(this);
const viewValue = this.props.value;
this.onSuggestionSelected = this.onSuggestionSelected.bind(this);
this.onChange = this.onChange.bind(this);
}
state = {
file: null,
firstname: '',
@@ -112,28 +167,48 @@ class Answer extends Component {
twitter: '',
website: '',
mediaId: null,
mediaUrl: null,
thumbnails:null,
heure: null,
companyId: null,
address:'',
errorMessage:'',
open: false,
loading: true,
openSnack: false,
cv:false,
};
handleChange = (e) => {
this.setState({ [e.target.name]: e.target.value })
}
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
firstname: nextProps.user.firstname,
lastname: nextProps.user.lastname,
phone: nextProps.user.phone,
currentJob: nextProps.user.currentJob,
linkedin: nextProps.user.linkedin,
twitter: nextProps.user.twitter,
website: nextProps.user.website,
firstname: this.state.firstname,
lastname: this.state.lastname,
phone: this.state.phone,
currentJob: this.state.currentJob,
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,
@@ -142,12 +217,171 @@ class Answer extends Component {
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
})
}
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('');
}
}
onSuggestionSelected = (suggestion) => {
console.log('Selected suggestion:', suggestion)
const address = suggestion.description;
this.setState({
value: address
});
geocodeByAddress(address)
.then(address => {
console.log('Selected ' + 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: '#ffffff', 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)
@@ -160,39 +394,66 @@ class Answer extends Component {
//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)
// )
this.props.postAdAnswerRequest(
{
adId: this.props.adId,
companyId: this.props.companyId,
mediaId: this.props.mediaId
mediaId: this.props.mediaId,
mediaUrl: this.props.mediaUrl,
thumbnails : this.props.thumbnails,
heure: this.props.heure
})
}
inputFilesystemChange = (e) => {
// inputFilesystemChange = (e) => {
console.log("inputFilesystemChange");
var file = e.target.files[0]
this.setState({ picture: file })
// 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)
// 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,
}
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 &&
{/* {!!user.pictureLoading && <Loader />} */}
{/* {!!!user.pictureLoading && !!!logoUrl &&
(<Fragment><input
type="file" accept="image/*" capture="filesystem"
className={classes.input}
@@ -212,7 +473,40 @@ class Answer extends Component {
<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"
/>
{/* <GooglePlaceAutocomplete
name="location"
label="Location"
onSuggestionSelected={this.onSuggestionSelected}
textFieldProps={{ onChange: (e) => this.onChange(e), value: this.state.value, placeholder: 'Chercher votre adresse'}}
types={['(regions)']}
renderTarget={() => (<div />)}
/> */}
<Button className={classes.remplacerButton} onClick={this.openDialog.bind(this)}>
Remplacer ma vidéo
</Button>
<Dialog open={this.state.open} onEnter={console.log("Hey.")}>
<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="lastname"
required
@@ -223,6 +517,9 @@ class Answer extends Component {
variant="outlined"
value={this.state.lastname}
onChange={this.handleChange}
error={!!_.isEmpty(this.state.lastname)}
helperText={!!_.isEmpty(this.state.lastname) && "Veuillez saisir votre nom"}
required
/>
<TextField
@@ -235,6 +532,8 @@ class Answer extends Component {
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
@@ -247,6 +546,7 @@ class Answer extends Component {
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
@@ -270,6 +570,29 @@ class Answer extends Component {
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"
@@ -306,9 +629,10 @@ class Answer extends Component {
value={this.state.website}
onChange={this.handleChange}
/>
</form>
<div id="F" className={classes.foot}>
<Button variant="contained" className={classes.button + ' cypButtonSendApplication'} onClick={this.onSubmit}>Postuler</Button>
<Button variant="contained" className={classes.button + ' cypButtonSendApplication'} onClick={this.onSubmit}>Envoyer ma candidature</Button>
</div>
</section>
)
@@ -316,13 +640,25 @@ class Answer extends Component {
}
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,
// loading: !!state.user.loading,
phone:ownProps.phone,
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 })(Answer))
export default withStyles(styles)(connect(mapStateToProps, { postAdAnswerRequest, updateUserRequest, updateUserPictureRequest, uploadMediaCv })(Answer))
+1 -1
View File
@@ -151,7 +151,7 @@ class CompanyRowComponent extends React.Component {
const nbOffre = (rowData.count_ads > 0) ? offre : 'Candidature spontanée';
return (
<Link href={`/Entreprise/${rowData.id}-${_.kebabCase(rowData.brand_name)}-${_.kebabCase(rowData.addresses.billing.city)}`} >
<Link href={`/Entreprise/${rowData.id}-${_.kebabCase(rowData.brand_name)}`} >
<Card className={classes.card + ' cypCardCompany'}>
<CardContent className={classes.content}>
<CardMedia
+26 -4
View File
@@ -5,10 +5,11 @@ 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: {
@@ -152,6 +153,11 @@ const styles = theme => ({
justifyContent: 'center',
padding: theme.spacing(6, 4),
},
version:{
marginTop: '15px',
fontSize: '0.7em',
fontWeight: '300',
}
});
@@ -215,6 +221,12 @@ function Footer(props) {
</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}>
@@ -243,6 +255,13 @@ function Footer(props) {
</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}>
@@ -255,11 +274,11 @@ function Footer(props) {
56 000 Vannes
</Typography>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
02.30.05.06.31
<a href="tel:+33230050631" >02.30.05.06.31 </a>
</Typography>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
{/* <Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
contact@talentstube.com
</Typography>
</Typography> */}
</section>
</div>
@@ -270,6 +289,9 @@ function Footer(props) {
<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>
);
@@ -1,7 +1,8 @@
import React from 'react';
const NextButton = ({ hasNext, onClick, style, className, text }) => hasNext ? (
<button type="button" onClick={onClick} style={style} className={className}>Suivant</button>
// <button type="button" onClick={onClick} style={style} className={className}>Suivant</button>
<div></div>
) :
null;
@@ -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;
@@ -1,8 +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>
) :
// <button type="button" onClick={onClick} style={style} className={className}>Précédent</button>
<div></div>
) :
null;
export default PreviousButton;
+101 -41
View File
@@ -40,6 +40,7 @@ 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: {
@@ -302,11 +303,11 @@ class Header extends React.Component {
left: false,
bottom: false,
right: false,
toggle: true
toggle: true,
};
componentDidMount() {
}
@@ -327,12 +328,26 @@ class Header extends React.Component {
}
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)}>
@@ -354,6 +369,7 @@ class Header extends React.Component {
<Divider />
<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 }}>
@@ -383,16 +399,27 @@ class Header extends React.Component {
</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}>
{/* <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> */}
<div className={classes.recruteurLinkGroup}>
<a href={publicRuntimeConfig.symphonyUrl } className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<SupervisorAccountIcon className={classes.icon} />
@@ -401,6 +428,7 @@ class Header extends React.Component {
</ListItem></a>
</div>
</div>
{/* FIN Menu recruteur*/}
</div>
</List>
@@ -415,9 +443,11 @@ class Header extends React.Component {
role="button"
onClick={this.toggleDrawer('right', false)}
onKeyDown={this.toggleDrawer('right', false)}
>{!!this.props.loading &&
>
{!!this.props.loading &&
(<Loader />
)}
)
}
{!!!this.props.loading && !!!this.props.fetched
&&
<div className={classes.fullList + ' ' + classes.darkFullList}>
@@ -440,7 +470,7 @@ class Header extends React.Component {
</ListItem></a>
</Link>
{/* TODO */}
<Link href="/Login?inscription=true" >
<Link href="/Inscription" >
<a className={classes.lightMenuItem + ' cypRegister'}><ListItem classes={{ primary: classes.ListItemText }} classes={{ root: classes.rootListItem }}>
<PersonAddIcon className={classes.icon} />
<ListItemText primary='Inscription'>
@@ -452,7 +482,7 @@ class Header extends React.Component {
<Divider light={true} />
<div className={classes.linkGroup}>
<a href={publicRuntimeConfig.symphonyUrl + "/faire-offre-emploi-video"} className={classes.lightMenuItem}><ListItem classes={{ primary: classes.ListItemText }} classes={{ root: classes.rootListItemIcon }}>
<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>
@@ -460,14 +490,16 @@ class Header extends React.Component {
</a>
</div>
</List>
</div>}
{!!!this.props.loading && !!this.props.fetched &&
</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}
@@ -480,29 +512,51 @@ class Header extends React.Component {
<Divider className={classes.darkDivider} />
{/* TODO:real links */}
<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>
{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");
@@ -538,13 +592,13 @@ class Header extends React.Component {
<List className={classes.desktopMenuList}>
<div>
<ActiveLink activeClassName={classes.active} href="/Offres" >
<a className={classes.desktopMenuItem}>
<ActiveLink activeClassName={classes.active} href="/Offres" >
<a className={classes.desktopMenuItem} >
<ListItemText primary="Offres d'emploi">
</ListItemText>
</a>
</ActiveLink>
<ActiveLink activeClassName={classes.active} href="/Entreprises" >
<ActiveLink activeClassName={classes.active} href="/Entreprises" >
<a className={classes.desktopMenuItem}>
<ListItemText primary='Nos entreprises'>
</ListItemText>
@@ -556,12 +610,18 @@ class Header extends React.Component {
</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="/Login?inscription=true" >
<Link href="/Inscription" >
<a className={classes.desktopMenuItem}>
<ListItem classes={{ root: classes.rootListItemDesktop }}>
<Button
@@ -588,7 +648,7 @@ class Header extends React.Component {
</Link>
</Fragment>
}
{!!!this.props.loading && !!this.props.fetched &&
{!!!this.props.loading && !!this.props.fetched &&
<IconButton
edge="end"
aria-label="Profile"
@@ -605,7 +665,7 @@ class Header extends React.Component {
</section>
<section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection3}>
<a href={publicRuntimeConfig.symphonyUrl + "/faire-offre-emploi-video"} className={classes.desktopMenuItem}>
<a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.desktopMenuItem}>
<ListItemText primary='Espace recruteurs'>
</ListItemText>
<ArrowForward className={classes.icon} />
+634
View File
@@ -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 Header extends React.Component {
state = {
top: false,
left: false,
bottom: false,
right: false,
toggle: true
};
redirectionrecruteur=(props) => {
console.log("redirection recruteur")
localStorage.removeItem("ttJWT");
//this.openDialog()
props.requestLogout();
window.location.href = "https://recruteur.talentstube.com/";
}
componentDidMount() {
}
toggleDrawer = (side, open) => () => {
this.setState({
[side]: open,
});
};
onRedirectAccount = e => {
urlEnv = (process.env.NODE_ENV !== 'production') ? '//localhost/app_dev.php' : process.env.SERVER_URL;
e.preventDefault();
var redirectAccountUrl = urlEnv + "/api/talent?bearer=" + localStorage.getItem("ttJWT");
window.open(redirectAccountUrl);
}
toggle = () => this.setState(state => ({ toggle: !state.toggle }))
chargerPage =(type)=> {
console.log(type);
//Router.replace(page);
sessionStorage.setItem(type+'_currentPage',1);
}
render() {
const { classes } = this.props;
const { publicRuntimeConfig } = getConfig();
return (
<div className={classes.root}>
<Drawer anchor="right" open={this.state.right} onClose={this.toggleDrawer('right', false)}>
<div
tabIndex={0}
role="button"
onClick={this.toggleDrawer('right', false)}
onKeyDown={this.toggleDrawer('right', false)}
>{!!this.props.loading &&
(<Loader />
)}
{!!!this.props.loading && !!!this.props.fetched
&&
<div className={classes.fullList + ' ' + classes.darkFullList}>
<List>
<Link href="/" >
<a className={classes.darkMenuItem + ' cypFrontPage'}><ListItem classes={{ root: classes.rootListItemIcon }}>
<img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-blanc.svg' className={classes.menuLogo} />
</ListItem></a>
</Link>
<Divider light={true} />
<div className={classes.linkGroup}>
<Link href="/Login" >
<a className={classes.lightMenuItem + ' cypConnexion'}><ListItem classes={{ root: classes.rootListItemIcon }} >
<PersonIcon className={classes.icon} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Connexion'>
</ListItemText>
</ListItem></a>
</Link>
{/* TODO */}
<Link href="/Inscription" >
<a className={classes.lightMenuItem + ' cypRegister'}><ListItem classes={{ primary: classes.ListItemText }} classes={{ root: classes.rootListItem }}>
<PersonAddIcon className={classes.icon} />
<ListItemText primary='Inscription'>
</ListItemText>
</ListItem></a>
</Link>
</div>
<Divider light={true} />
<div className={classes.linkGroup}>
<a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.lightMenuItem}><ListItem classes={{ primary: classes.ListItemText }} classes={{ root: classes.rootListItemIcon }}>
<WorkOutlineIcon className={classes.icon} />
<ListItemText primary='Connexion recruteurs'>
</ListItemText>
</ListItem>
</a>
</div>
</List>
</div>}
{!!!this.props.loading && !!this.props.fetched &&
<Fragment>
{this.props.user.picture ?
<img alt="talents-tube" src={publicRuntimeConfig.symphonyUrl +publicRuntimeConfig.postedContentUrl+ this.props.user.picture} className={classes.menuAvatar} />
:
<img alt="talents-tube" src='/static/images/default/account-avatar-default.svg' className={classes.menuAvatar} />
}
<ListItem classes={{ root: classes.rootListItem }} className={classes.ListItemUserConnected}>
<Typography gutterBottom component="h1" className={classes.menuUserName}>
{this.props.user.firstname + " " + this.props.user.lastname}
</Typography>
<Typography gutterBottom component="h3" className={classes.menuUserEmail} >
{this.props.user.email}
</Typography>
</ListItem>
<Divider className={classes.darkDivider} />
{this.props.user.type=="TALENT"
?
<div>
<Link href="/Candidatures" >
<a className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<FolderSharedIcon className={classes.icon} />
<ListItemText primary='Mes candidatures'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="/profileStep" >
<a className={classes.lightMenuItem}>
<ListItem classes={{ root: classes.rootListItemIcon }}>
<AccountCircleIcon className={classes.icon} />
<ListItemText primary='Mon compte'>
</ListItemText>
</ListItem>
</a>
</Link>
<Link href="/Parametres" >
<a className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<SettingsIcon className={classes.icon} />
<ListItemText primary='Paramètres de notification'>
</ListItemText>
</ListItem></a>
</Link>
</div>
:
this.redirectionrecruteur(this.props)
// <div>
// <a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.lightMenuItem}>
// <ListItem classes={{ root: classes.rootListItemIcon }}>
// <SettingsIcon className={classes.icon} />
// <ListItemText primary='Espace recruteur'>
// </ListItemText>
// </ListItem></a>
// </div>
}
<Link href="/" >
<a onClick={() => {
localStorage.removeItem("ttJWT");
return this.props.requestLogout();
}} className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<PowerSettingsNewIcon className={classes.icon} />
<ListItemText primary='Déconnexion'>
</ListItemText>
</ListItem></a>
</Link>
</Fragment>
}
</div>
</Drawer>
{isWidthUp('md', this.props.width) ?
(<AppBar position="static" className={classes.appBar}>
<Toolbar disableGutters={true} className={classes.toolbarDesktop}>
<section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection1}>
<Link href="/" >
<a className={classes.darkMenuItem}>
<ListItem classes={{ root: classes.rootListItemDesktop }}>
<img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-color.svg' className={classes.desktopMenuLogo} />
</ListItem>
</a>
</Link>
</section>
<section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection2}>
{/* <IconButton className={classes.menuButton} onClick={this.toggleDrawer('left', true)}
color="inherit" aria-label="Open drawer">
<MenuIcon />
</IconButton> */}
<List className={classes.desktopMenuList}>
<div>
<ActiveLink activeClassName={classes.active} href="/Offres" >
<a className={classes.desktopMenuItem} >
<ListItemText primary="Offres d'emploi">
</ListItemText>
</a>
</ActiveLink>
<ActiveLink activeClassName={classes.active} href="/Entreprises" >
<a className={classes.desktopMenuItem}>
<ListItemText primary='Nos entreprises'>
</ListItemText>
</a>
</ActiveLink>
<ActiveLink activeClassName={classes.active} href="/Help" >
<a className={classes.desktopMenuItem}>
<ListItemText primary='Comment ça marche ?'>
</ListItemText>
</a>
</ActiveLink>
<a className={classes.desktopMenuItem} target="_blank" href="https://blog.talentstube.com/">
<ListItemText primary='Blog'>
</ListItemText>
</a>
</div>
<div>
{!!!this.props.loading && !!!this.props.fetched &&
<Fragment>
<Link href="/Inscription" >
<a className={classes.desktopMenuItem}>
<ListItem classes={{ root: classes.rootListItemDesktop }}>
<Button
variant="outlined"
className={classes.button + ' ' + classes.desktopMenuButtonRegister}>
<PersonAddIcon className={classes.iconDesktop} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Inscription'></ListItemText>
</Button >
</ListItem>
</a>
</Link>
<Link href="/Login" >
<a className={classes.desktopMenuItem}>
<ListItem classes={{ root: classes.rootListItemDesktop }}>
<Button
variant="outlined"
className={classes.button + ' ' + classes.desktopMenuButtonLogin}>
<PersonIcon className={classes.iconDesktop} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Connexion'></ListItemText>
</Button >
</ListItem>
</a>
</Link>
</Fragment>
}
{!!!this.props.loading && !!this.props.fetched &&
<IconButton
edge="end"
aria-label="Profile"
aria-controls={'primary-search-account-menu'}
aria-haspopup="true"
onClick={this.toggleDrawer('right', true)}
className={classes.iconAccount + ' cypConnexionMenu'}
>
<AccountCircleOutlinedIcon />
</IconButton>
}
</div>
</List>
</section>
<section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection3}>
<a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.desktopMenuItem}>
<ListItemText primary='Espace recruteurs'>
</ListItemText>
<ArrowForward className={classes.icon} />
</a>
</section>
</Toolbar>
</AppBar>)
:
(
<AppBar position="static" className={classes.appBar}>
<Toolbar className={classes.toolbar}>
{/* <IconButton className={classes.menuButton} onClick={this.toggleDrawer('left', true)}
color="inherit" role="button">
<MenuIcon />
</IconButton> */}
<ButtonBase name='back'
focusRipple
className={classes.back}
focusVisibleClassName={classes.focusVisible}
onClick={() => Router.push("/Offres")}>
<ArrowLeft color="primary" classes={{ root: classes.icon }}></ArrowLeft>
</ButtonBase>
<div className={classes.grow} />
<Link href="/" >
<a><img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-color.svg' className={classes.menuLogo} /></a>
</Link>
<div className={classes.grow} />
<IconButton
edge="end"
aria-label="Profile"
aria-controls={'primary-search-account-menu'}
aria-haspopup="true"
onClick={this.toggleDrawer('right', true)}
className={classes.iconAccount + ' cypConnexionMenu'}
>
<AccountCircleOutlinedIcon />
</IconButton>
</Toolbar>
</AppBar>
)}
</div >
);
}
}
function mapStateToProps(state) {
return {
user: state.user,
fetched: !!state.user.fetched,
loading: !!state.user.loading
};
}
export default (connect(mapStateToProps, { fetchCurrentUserRequest, requestLogout })(withStyles(styles)(withWidth()(Header))));
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -17,7 +17,7 @@ const styles = theme => ({
card: {
display: 'flex',
minHeight: '21vh',
maxHeight: '32vh',
// maxHeight: '32vh',
borderRadius: '5px',
width: '100%',
cursor: 'pointer',
@@ -38,7 +38,7 @@ const styles = theme => ({
},
[theme.breakpoints.up('md')]: {
minHeight: '15vh',
maxHeight: '20vh',
// maxHeight: '20vh',
},
margin: '1vh 2vh 1vh 2vh',
[theme.breakpoints.up('sm')]: {
@@ -51,7 +51,7 @@ const styles = theme => ({
alignItems: 'flex-start',
padding: theme.spacing(2),
width: '75%',
minHeight: '200px',
// minHeight: '200px',
},
jobTitle: {
fontSize: '1.2em',
@@ -127,7 +127,7 @@ class OffreRowComponent extends React.Component {
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
return (
<Link href={`/Offre/${rowData.id}-${_.kebabCase(rowData.title)}-${_.kebabCase(rowData.location.gmap_address.name)}`} >
<Link href={`/Offre/${rowData.id}-${_.kebabCase(rowData.title)}`} >
<Card className={classes.card + ' cypCardOffre'} >
<CardContent className={classes.content}>
<CardMedia
@@ -156,7 +156,7 @@ class OffreRowComponent extends React.Component {
</Typography>
<div>
{rowData.is_promoted && (
<Chip label="Pourvue" className={classes.chip} />
<Chip label="Offre pourvue" className={classes.chip} />
)}
{!rowData.is_promoted && (
+193 -25
View File
@@ -7,6 +7,7 @@ import axios from 'axios'
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
@@ -17,8 +18,31 @@ const RTCRecorder = dynamic(() => import('RecordRTC'), {
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
@@ -40,37 +64,107 @@ const videoJsOptions = {
}
}
};
const styles = theme => ({
root: {
margin: theme.spacing(1),
maxWidth: '400px', [theme.breakpoints.down('md')]: {
maxWidth: `${100 - (theme.spacing(1))}vw`
const styles = theme => ({
primary: {
color: theme.palette.primary.main,
},
sendContainer: {
textAlign: 'center'
root: {
position: 'relative',
textAlign: 'center',
paddingTop: theme.spacing(10),
justifyContent: 'center',
},
button: {
color: '#FFFFFF',
padding: '9.6px 16px',
borderColor: '#25D89A',
border: '2px solid',
margin:'15px 8px 25px 8px',
textTransform: 'inherit',
marginLeft: theme.spacing(8),
marginRight: theme.spacing(8),
marginTop: theme.spacing(4),
marginBottom: theme.spacing(2),
padding: theme.spacing(1.2, 2),
//borderRadius: '3px',
[theme.breakpoints.up('sm')]: {
margin: 'auto',
},
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
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
@@ -81,10 +175,42 @@ class Recorder extends Component {
' 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.info('device is ready!');
this.player.record().start();
this.setState({canSend:false});
});
@@ -129,9 +255,44 @@ class Recorder extends Component {
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, titreBouton } = this.props;
let titreButtonLabel= "Envoyer";
let titreButtonLabel= "Choisir cette vidéo";
if (titreBouton) {
@@ -140,17 +301,24 @@ class Recorder extends Component {
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 className={classes.sendContainer}>
{ this.state.canSend && <Button type="submit" variant="outlined" color="primary"
{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}>
{titreButtonLabel}
</Button>}
</div>
<div id="controleNav">
</div>
</div>
);
}
+37 -11
View File
@@ -10,6 +10,7 @@ import InputAdornment from '@material-ui/core/InputAdornment';
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: {
@@ -111,6 +112,7 @@ class Register extends React.Component {
password: '',
checkNewsletter: false,
checkCGU: false,
adId : ''
},
errors: {
email:null,
@@ -120,7 +122,8 @@ class Register extends React.Component {
checkCGU:null
},
loading: false,
showPassword: false
showPassword: false,
passwordValid : false
}
validate = data => {
@@ -131,18 +134,28 @@ class Register extends React.Component {
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);
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.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 })
@@ -156,10 +169,12 @@ class Register extends React.Component {
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 } });
};
@@ -173,7 +188,7 @@ class Register extends React.Component {
};
render() {
const { classes } = this.props;
const { classes, erreurs } = this.props;
const { data, errors } = this.state;
return (
@@ -182,6 +197,7 @@ class Register extends React.Component {
<form className={classes.form}>
<TextField
className={classes.champ}
value={data.lastname}
onChange={this.onChange}
id="nom"
@@ -191,6 +207,7 @@ class Register extends React.Component {
variant="outlined"
required
error={!!errors.lastname}
helperText={!!errors.lastname && "Veuillez saisir votre nom."}
/>
<TextField
value={data.firstname}
@@ -202,6 +219,7 @@ class Register extends React.Component {
variant="outlined"
required
error={!!errors.firstname}
helperText={!!errors.firstname && "Veuillez saisir votre prénom."}
/>
<TextField
@@ -214,8 +232,9 @@ class Register extends React.Component {
type="email"
variant="outlined"
required
error={!!errors.email}
error={!!errors.email || !!erreurs}
autoComplete="username email"
helperText={!!errors.email ? "Saisissez une adresse e-mail valide." : !!erreurs && erreurs}
/>
@@ -230,6 +249,7 @@ class Register extends React.Component {
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">
@@ -273,19 +293,20 @@ class Register extends React.Component {
label="Je déclare avoir pris connaissance et accepte les termes et les CGU *"
required
/>
<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"
className={classes.conditionalText}
>Ou</Typography>
>Ou</Typography> */}
</form>
<SocialButtonsAuth linkedInAuth={this.props.linkedInAuth} facebookAuth={this.props.facebookAuth} />
{/* <SocialButtonsAuth linkedInAuth={this.props.linkedInAuth} facebookAuth={this.props.facebookAuth} /> */}
<div classes={classes.form}>
<Typography
@@ -300,7 +321,12 @@ class Register extends React.Component {
</Link>
</Typography>
</div>
<Snack name= 'snackWarning'
variant= 'warning'
message={errors.message}
/>
</div>
);
}
}
+71 -17
View File
@@ -5,6 +5,7 @@ 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: {
@@ -26,16 +27,52 @@ const useStyles = makeStyles(theme => ({
textAlign: 'center',
},
FacebookIcon: {
backgroundColor: theme.palette.social.facebook,
color: theme.palette.social.facebook,
'&:hover': {
backgroundColor: theme.palette.social.facebook,
color: '#fff',
}
},
TwitterIcon: {
backgroundColor: theme.palette.social.twitter,
color: theme.palette.social.twitter,
'&:hover': {
backgroundColor: theme.palette.social.twitter,
color: '#fff',
}
},
LinkedinIcon: {
backgroundColor: theme.palette.social.linkedin,
color: theme.palette.social.linkedin,
'&:hover': {
backgroundColor: theme.palette.social.linkedin,
color: '#fff',
}
},
MailIcon: {
backgroundColor: theme.palette.social.mail,
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'
},
}));
@@ -51,19 +88,36 @@ export default function SocialShare(props) {
return (
<div className={classes.root}>
<a href={"https://www.facebook.com/sharer/sharer.php?u=" + encodeURIComponent(props.url)}>
<Icon className={clsx(classes.icon, classes.FacebookIcon, 'fab fa-facebook-f')} color="secondary" />
</a>
<a href={"http://twitter.com/share?url=" + encodeURIComponent(props.url)}>
<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=Talent's Tube")}>
<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 Talent's Tube&body=Regardez cette offre : " + props.url} >
<Icon className={clsx(classes.icon, classes.MailIcon, 'fas fa-envelope')} color="secondary" />
</a>
<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=Talent's 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 Talent's 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=Talent's 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 Talent's 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>
);
}
+1 -1
View File
@@ -99,7 +99,7 @@ class Tile extends React.Component {
const logoName = (rowData.company) ? rowData.company.logo : rowData.logo
const logoUrl = publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.cachedMediaUrl + logoName
const router = (rowData.company) ? `/Offre/${rowData.id}-${_.kebabCase(rowData.title)}-${_.kebabCase(rowData.location.gmap_address.name)}` : `/Entreprise/${rowData.id}-${_.kebabCase(rowData.brand_name)}-${_.kebabCase(rowData.addresses.billing.city)}`
const router = (rowData.company) ? `/Offre/${rowData.id}-${_.kebabCase(rowData.title)}` : `/Entreprise/${rowData.id}-${_.kebabCase(rowData.brand_name)}}`
//rowData._embedded.company.brand_name
return (
+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() {
+57 -8
View File
@@ -1,4 +1,4 @@
import Griddle, { utils } from "griddle-react";
import Griddle, { utils, plugins } from "griddle-react";
import PropTypes from 'prop-types';
import React, { Component, Fragment } from 'react';
import { withStyles } from '@material-ui/core/styles';
@@ -7,6 +7,7 @@ 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';
@@ -80,18 +81,37 @@ class Grid extends Component {
recordCount: 0,
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,
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>);
// }
}
UNSAFE_componentWillReceiveProps(nextProps) {
@@ -106,10 +126,17 @@ class Grid extends Component {
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: this.state.currentPage,
offset: ((current-1)*(this.state.pageSize+1))+1,
limit: this.state.pageSize,
keyword: filterText,
isPromoted: nextProps.promoted
@@ -123,19 +150,34 @@ class Grid extends Component {
_onNext = () => {
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, 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 => {
_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, promoted } = this.state;
this.setState({ filterText });
@@ -148,11 +190,12 @@ class Grid extends Component {
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: {
@@ -203,7 +246,7 @@ class Grid extends Component {
fontSize: '0.9em',
fontWeight: '600',
fontFamily: 'Dosis',
display: 'none',
// display: 'none',
},
}
}
@@ -211,10 +254,12 @@ class Grid extends Component {
const { filterText, data, currentPage, pageSize, recordCount, loading } = this.state;
const NewLayout = ({ Table, Pagination, Filter }) => (
<div>
{/* <Filter /> */}
<Table />
<Pagination />
</div>
);
@@ -278,6 +323,7 @@ class Grid extends Component {
recordCount,
}}
useCustomPagerComponent="true"
plugins={plugins.localPlugin}
components={{
Layout: NewLayout,
Row: this.props.CustomRowComponent,
@@ -285,12 +331,15 @@ class Grid extends Component {
TableBody: CustomTableBody,
PreviousButton: GriddleCustomPreviousButton,
NextButton: GriddleCustomNextButton,
PageDropdown: GriddleCustomPageDropdown,
}}
events={{
onNext: this._onNext,
onPrevious: this._onPrevious,
onGetPage: this._onGetPage,
onFilter: this._onFilter
onFilter: this._onFilter,
onSetPage: this._onSetPage
}}
styleConfig={style}
/>
+10
View File
@@ -4,6 +4,7 @@ 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 { Hidden } from '@material-ui/core';
const styles = theme => ({
inner: {
@@ -54,6 +55,13 @@ const styles = theme => ({
position: 'absolute',
left: theme.spacing(1),
},
retour:{
fontFamily: 'Roboto',
color: '#1E2327',
fontSize: '0.8rem',
fontWeight: '500',
}
});
function LayoutBack(props) {
@@ -72,6 +80,8 @@ function LayoutBack(props) {
focusVisibleClassName={classes.focusVisible}
onClick={() => Router.back()}>
<ArrowLeft color="primary" classes={{ root: classes.icon }}></ArrowLeft>
{/* <Hidden mdUp className={classes.retour}></Hidden> */}
<Hidden smDown className={classes.retour}>Retour</Hidden>
</ButtonBase>
<Typography
component="h1"
@@ -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)
+23 -4
View File
@@ -10,6 +10,7 @@ import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
import Header from '../organisms/Header'
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: {
@@ -65,11 +66,21 @@ const styles = theme => ({
},
button: {
textTransform: 'inherit',
marginLeft: theme.spacing(8),
marginRight: theme.spacing(8),
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',
},
})
@@ -105,13 +116,21 @@ function LayoutCompany(props) {
<Hidden mdUp>
<div id="F" className={classes.foot}>
<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}`)}
// onClick={() => Router.push(`/Reponse?companyId=${companyId}`)}
>
Candidature spontanée</Button>
Candidature spontanée</a>
</div>
</Hidden>
+50 -8
View File
@@ -5,9 +5,11 @@ 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 Header from '../organisms/Header'
import Header from '../organisms/HeaderOffre'
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'
const styles = theme => ({
foot: {
@@ -21,6 +23,10 @@ const styles = theme => ({
backgroundColor: theme.palette.secondary.main,
boxShadow: '0px 0px 10px rgba(30, 35, 39, 0.10)',
},
lien:{
textDecoration:'none',
color:'#fff'
},
contentDefault: {
height: 'auto',
position: 'relative',
@@ -56,22 +62,35 @@ const styles = theme => ({
},
button: {
textTransform: 'inherit',
marginLeft: theme.spacing(8),
marginRight: theme.spacing(8),
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 LayoutOffre(props) {
const { classes, offreId, isProvided } = 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 (
<RootContainer>
{isWidthUp('sm', props.width) ?
{isWidthUp('xs', props.width) ?
(<Header />)
:
(<ButtonBase name='back'
@@ -91,13 +110,36 @@ function LayoutOffre(props) {
<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}}
onClick={() => Router.push(`/Reponse?adId=${offreId}`)}
>
Postuler</Button>
<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>
+2 -1
View File
@@ -6,6 +6,7 @@ const styles = theme => ({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
textAlign: 'center',
justifyContent: 'center',
fontFamily: 'Dosis',
fontWeight: '500',
@@ -19,7 +20,7 @@ class Loader extends React.Component {
render() {
const { classes } = this.props;
return (
<div className={classes.loader + ' ' + 'alert alert-info'}><CircularProgress color="primary" />Chargement...</div>
<div className={classes.loader + ' ' + 'alert alert-info'}><CircularProgress color="primary" />Chargement... </div>
)
}
@@ -0,0 +1,43 @@
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: 'Dosis',
fontWeight: '500',
fontSize: '1em',
padding: theme.spacing(6,0),
color: theme.palette.primary.main,
},
root: {
top:"200px",
width: '100%',
'& > * + *': {
marginTop: theme.spacing(2),
},
},
})
class LoaderVideo extends React.Component {
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<div className={classes.loader + ' ' + 'alert alert-info'}><CircularProgress color="primary" />Veuillez ne pas quitter la page.<br/> Le temps de chargement peut varier de quelques secondes à plusieurs minutes en fonction de la qualité de votre connexion internet.<br/></div>
<div >
<LinearProgress />
<LinearProgress color="secondary" />
</div>
</div>
)
}
}
export default withStyles(styles)(LoaderVideo)
+9 -5
View File
@@ -12,6 +12,7 @@ axios.interceptors.response.use(response => {
}, error => {
if (error.response.status === 401) {
localStorage.setItem('ttJWT', '');
console.log("REPONSE REDIRECT LOGIN")
Router.push("/Login");
}
return error;
@@ -67,17 +68,17 @@ export default {
},
},
ads: {
fetchAd: (id) => {
return axios.get(`api/ads/${id}`).then(res => res.data)
fetchJob: (id) => {
return axios.get(`api/jobs/${id}`).then(res => res.data)
},
//offset is the index position of the first element to start requesting at
// use 0|1 for isPromoted
fetchAds: ({ limit = null, order = "", keyword = "", offset = 1, status = 'PUBLISHED', isPromoted = false, isEmphasis = false }) => {
fetchJobs: ({ limit = null, order = "", keyword = "", offset = 1, status = 'PUBLISHED', isPromoted = false, isEmphasis = false }) => {
isPromoted = isPromoted !== null ? isPromoted * 1 : isPromoted;
isEmphasis = isEmphasis !== null ? isEmphasis * 1 : isEmphasis;
return axios.get('api/ads', { params: { offset, limit, order, keyword, status, isPromoted, isEmphasis } })
return axios.get('api/jobs', { params: { offset, limit, order, keyword, status, isPromoted, isEmphasis } })
.then(res => res.data)
}
@@ -96,7 +97,7 @@ export default {
postAnswer: (payload) => {
return axios.post("/api/answers", { adId: payload.adId, mediaId: payload.mediaId, companyId: payload.companyId }).then(res => res)
},
fetchAdsAnswered: ({ limit = null, order = "", keyword = "", offset = 1 }) => {
fetchJobsAnswered: ({ limit = null, order = "", keyword = "", offset = 1 }) => {
return axios.get(`api/answers`, { params: { offset, limit, order, keyword } }).then(res => res.data)
},
fetchAnswer: (payload) => {
@@ -128,6 +129,9 @@ export default {
withCredentials: true
}).then(res => res)
},
},
cv:{
uploadMediaCv: (payload) => {
return axios.post("/api/mediaCv", payload, {
headers: {
+16 -3
View File
@@ -40,10 +40,22 @@ module.exports = withPlugins(
}],
[{
publicRuntimeConfig: {
symphonyUrl: 'https://recruteur.talentstube.com',
// DEV
// symphonyUrl: 'http://localhost/',
// blogUrl: 'https://blog.talentstube.com',
// frontServerUrl: 'http://localhost:3000',
// cvThequeUrl: 'https://recruteur.talentstube.com',
// PROD
// symphonyUrl: 'https://recruteur.talentstube.com/',
// blogUrl: 'https://blog.talentstube.com',
// frontServerUrl: 'https://www.talentstube.com/',
// cvThequeUrl: 'https://recruteur.talentstube.com',
// PRE PROD
symphonyUrl: 'https://pp.talentstube.com/',
blogUrl: 'https://blog.talentstube.com',
frontServerUrl: 'https://www.talentstube.com',
cvThequeUrl: 'https://cvtheque.talentstube.com/',
frontServerUrl: 'https://pp.app.talentstube.com/',
cvThequeUrl: 'https://recruteur.talentstube.com',
version : 'V2.4.3',
adListDefaultUrl: '/statique/images/default/default_picture_company.svg',
cachedMediaUrl: '/media/cache/profile_thumb/uploads/img/',
postedContentUrl: '/uploads/img/',
@@ -52,6 +64,7 @@ module.exports = withPlugins(
"siteKey": "6LdyqLwUAAAAADKI5uC7d5W9VqVgzd8VEmMU2Yi-"
},
applicationServerPublicKey: 'BNFyiyPiLH97Dgc0m1vXluUNaCN6y3Hkgd4YcqS2lVkP8my3tq2D5gM5g7cY6R4VxC7GljSzkLRu+k+oO+2TtjU='
//applicationServerPublicKey: 'BG2lV673DvB67dzEwX9GKfds3sXaEdtZo2oWO1cO2xUdTJAFZ_rV_UrP1nHQz-F8LJNO9HxG0kmQRIb54JL1ZCA'
}
}]
],
+9
View File
@@ -11,6 +11,7 @@
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "^4.0.0-alpha.56",
"@ostai/next-css": "^1.0.2",
"autosuggest-highlight": "^3.1.1",
"axios": "^0.18.0",
"connect-mongo": "^2.0.1",
"cross-env": "^5.2.0",
@@ -26,6 +27,7 @@
"jss": "latest",
"lodash": "^4.17.11",
"mongodb": "^3.1.6",
"mui-places-autocomplete": "^2.0.0",
"nedb": "^1.8.0",
"next": "^9.1.1",
"next-auth": "^1.11.0",
@@ -47,13 +49,19 @@
"prop-types": "latest",
"react": "^16.9.0",
"react-ad-block-detect": "^1.0.1",
"react-autosuggest": "^10.0.2",
"react-dom": "^16.9.0",
"react-facebook-login": "^4.1.1",
"react-ga": "^2.5.7",
"react-google-recaptcha": "^2.0.1",
"react-html-parser": "^2.0.2",
"react-jss": "latest",
"react-moment": "^0.9.7",
"react-places-autocomplete": "^7.3.0",
"react-redux": "^7.0.3",
"react-redux-loading-bar": "^5.0.0",
"react-router-dom": "^5.2.0",
"react-sticky-box": "^0.9.3",
"react-swipeable-views": "^0.13.3",
"reactstrap": "^6.4.0",
"recordrtc": "^5.5.4",
@@ -67,6 +75,7 @@
"terser": "3.14",
"universal-cookie": "^3.0.4",
"validator": "^11.0.0",
"video-react": "^0.14.1",
"videojs-record": "^3.8.0",
"webrtc-adapter": "^7.2.3"
},
+1 -1
View File
@@ -188,7 +188,7 @@ class Candidature extends React.Component {
{this.props.user.firstname + " " + this.props.user.lastname}
</Typography>
<Typography gutterBottom className={classes.userTextDate}>
Envoyée le {(new Date(this.props.answer.c_time)).toLocaleDateString("fr-FR")}
Envoyé le {(new Date(this.props.answer.c_time)).toLocaleDateString("fr-FR")}
</Typography>
</div>
</section>
+44
View File
@@ -0,0 +1,44 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Layout from "../components/templates/Layout";
import AccountProfileCandidature from "../components/organisms/AccountProfileCandidature";
import Head from 'next/head'
// import AdBlockDetect from 'react-ad-block-detect';
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),
},
}));
export default function HorizontalNonLinearStepper() {
const classes = useStyles();
return (
<Layout>
<Head>
<title key="title">Profil Talents Tube</title>
<meta key="robots" name="robots" content="noindex, nofollow"></meta>
</Head>
<div >
<AccountProfileCandidature />
</div>
{/* <AdBlockDetect>
<p>AdBlocks a été détecté. Pour que Talents Tube puisse fonctionner correctement, veuillez désactiver Ad Blocks</p>
</AdBlockDetect> */}
</Layout>
);
}
+22 -3
View File
@@ -8,9 +8,10 @@ import { Typography } from '@material-ui/core';
import LayoutGrid from "../components/templates/LayoutGrid";
import Grid from "../components/templates/Grid"
import AnswerRow from "../components/organisms/AnswerRow"
import { fetchAdsAnsweredRequest } from '../actions/answer'
import { fetchJobsAnsweredRequest } from '../actions/answer'
import { AnswersSelector } from '../reducers/answers'
import Head from 'next/head'
import Link from 'next/link';
const styles = theme => ({
root: {
@@ -24,6 +25,13 @@ const styles = theme => ({
flexDirection: 'column',
padding: theme.spacing(0,3),
},
profil: {
display: 'flex',
flexDirection: 'column',
padding: theme.spacing(3,3),
textAlign: 'center',
backgroundColor: theme.palette.primary.main,
},
title: {
fontFamily: 'Dosis',
fontSize: '1.5em',
@@ -52,10 +60,11 @@ class Candidatures extends React.Component {
<Typography component="h1" align="center" className={classes.title} gutterBottom>
Mes candidatures
</Typography>
<div className={classes.container}>
<Grid CustomRowComponent={AnswerRow}
dataFetcher={this.props.fetchAdsAnsweredRequest}
dataFetcher={this.props.fetchJobsAnsweredRequest}
data={this.props.answers}
currentPage={this.props.currentPage}
recordCount={this.props.recordCount}
@@ -64,6 +73,16 @@ class Candidatures extends React.Component {
searchable={false}
/>
</div>
</LayoutGrid>
);
}
@@ -84,4 +103,4 @@ function mapStateToProps(state) {
};
}
export default withStyles(styles)(connect(mapStateToProps, {fetchAdsAnsweredRequest })(Candidatures))
export default withStyles(styles)(connect(mapStateToProps, {fetchJobsAnsweredRequest })(Candidatures))
+2 -2
View File
@@ -57,7 +57,7 @@ class Confidentialite extends Component {
</Head>
<div className={classes.container}>
<Typography className={classes.text} gutterBottom align="left">
Nous vous invitons à lire avec attention le présent document. Pour toute question concernant ce document et, dune manière générale, sur la collecte et le traitement de vos informations personnelles par la société talentstube.com, nhésitez pas à nous contacter via le formulaire présent sur la page contact : <a href="https://blog.talentstube.com/contact.html" className={classes.link} target="_blank">https://blog.talentstube.com/contact.html</a>
Nous vous invitons à lire avec attention le présent document. Pour toute question concernant ce document et, dune manière générale, sur la collecte et le traitement de vos informations personnelles par la société talentstube.com, nhésitez pas à nous contacter via le formulaire présent sur la page contact : <a href="https://blog.talentstube.com/contact" className={classes.link} target="_blank">https://blog.talentstube.com/contact</a>
</Typography>
<Typography className={classes.title} component="h2" gutterBottom align="left">
@@ -155,7 +155,7 @@ class Confidentialite extends Component {
`
Vous disposez d'un droit d'accès, de rectification, de suppression, dopposition et de portabilité des données. Nous disposons dun délai de 30 jours à compter de votre demande pour apporter une réponse.
Vous pouvez demander une limitation du traitement des données collectées. Lexercice de ces droits peut exercer ce droit auprès de TALENTS TUBE en adressant une requête soit par voie postale à l'adresse suivante : 3 Rue Louis de Broglie, Village By CA 56000 Vannes, soit par courrier électronique via le formulaire présent sur la page Contact `
}<a href="https://blog.talentstube.com/contact.html" className={classes.link} target="_blank">https://blog.talentstube.com/contact.html</a>{`. Cette requête devra être accompagnée d'une pièce d'identité revêtant la signature de l'Utilisateur et devra préciser l'adresse et le moyen par lesquelles une réponse pourra être envoyée..
}<a href="https://blog.talentstube.com/contact" className={classes.link} target="_blank">https://blog.talentstube.com/contact</a>{`. Cette requête devra être accompagnée d'une pièce d'identité revêtant la signature de l'Utilisateur et devra préciser l'adresse et le moyen par lesquelles une réponse pourra être envoyée..
`
}
</Typography>
+58 -10
View File
@@ -25,8 +25,8 @@ const styles = theme => ({
bottom: 0,
},
title: {
fontFamily: 'Dosis',
fontSize: '1.5em',
fontFamily: 'Roboto',
fontSize: '1.625em',
fontWeight: '600',
padding: theme.spacing(3, 0),
},
@@ -47,6 +47,24 @@ const styles = theme => ({
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.important,
},
iconButton:{
marginTop: "50px",
[theme.breakpoints.down('md')]: {
marginTop: "50px",
},
},
texteEtape:{
fontSize: '1em',
fontWeight: '300',
},
etape:{
fontSize: '1em',
fontWeight: '500',
color:'#1689FB',
}
})
@@ -69,7 +87,7 @@ class ConfirmAccount extends Component {
const { classes } = this.props
const { loading } = this.state
return (
<LayoutBack text="Validation" height="fixed">
<LayoutBack text="Inscription" height="fixed">
<Head>
<title key="title">Confirmation de compte</title>
<meta key="robots" name="robots" content="noindex, nofollow"></meta>
@@ -80,16 +98,45 @@ class ConfirmAccount extends Component {
)}
{!loading && (
<Fragment>
<img
alt="talents-tube"
src='/statique/images/inscription/validation-plateforme-recrutement-video.svg'
className={classes.iconButton}/>
<Typography gutterBottom align="center" className={classes.title}>
e-mail validé
Bienvenue sur Talents Tube
</Typography>
<Typography gutterBottom align="left" className={classes.text}>
Votre email a bien été validé.
<Typography gutterBottom align="center" className={classes.etape}>
Étape 1.
</Typography>
<Typography gutterBottom align="left" className={classes.text}>
Vous pouvez maintenant vous connecter.
<Typography gutterBottom align="center" className={classes.texteEtape}>
Découvrez les entreprises et les offres demploi en vidéo.
</Typography>
<section className={classes.bottomContainer}>
<Typography gutterBottom align="center" className={classes.etape}>
Étape 2.
</Typography>
<Typography gutterBottom align="center" className={classes.texteEtape}>
Postulez en vidéo.
</Typography>
<Typography gutterBottom align="center" className={classes.etape}>
Étape 3.
</Typography>
<Typography gutterBottom align="center" className={classes.texteEtape}>
Gérez vos candidatures depuis votre compte Talent.
</Typography>
<Typography gutterBottom align="center" className={classes.text}>
<Button
variant="contained"
className={classes.button}
classes={{ root: classes.rootButton }}
onClick={() => Router.push('/Login')}
>
Se connecter
</Button>
</Typography>
{/* <section className={classes.bottomContainer}>
<Button
variant="contained"
className={classes.button}
@@ -98,7 +145,7 @@ class ConfirmAccount extends Component {
>
Connexion
</Button>
</section>
</section> */}
</Fragment>
)}
</div>
@@ -118,6 +165,7 @@ function mapStateToProps(state, ownProps) {
ConfirmAccount.getInitialProps = function (context) {
const { token, email } = context.query
//localStorage.setItem('loginRedirect', url)
context.store.dispatch(requestConfirmationAccountRequest({ 'confirmationToken': token, 'email': email }))
return email;
}
+53 -12
View File
@@ -1,5 +1,5 @@
import React, { Fragment } from 'react'
import React, { Fragment,lazy, Suspense } from 'react'
import Router from 'next/router'
import { connect } from "react-redux"
import PropTypes from 'prop-types'
@@ -16,7 +16,8 @@ import { fetchCompanyRequest, clearCompany, countCompanyViewRequest } from '../a
import IconText from '../components/atoms/IconText'
import IconTextInline from '../components/atoms/IconTextInline'
import SimpleCollapse from '../components/atoms/SimpleCollapse'
import VideoVimeo from '../components/atoms/VideoVimeo'
const VideoVimeo = lazy(() => import('../components/atoms/VideoVimeo'));
//import VideoVimeo from '../components/atoms/VideoVimeo'
import SocialShare from '../components/organisms/SocialShare'
import Loader from '../components/templates/loader'
import _ from "lodash"
@@ -26,6 +27,7 @@ import Hidden from '@material-ui/core/Hidden';
import NoResult from '../components/atoms/NoResult';
import OgHead from '../components/atoms/OgHead';
const renderLoader = () => <p>Chargement</p>;
const styles = theme => ({
companyContainer: {
[theme.breakpoints.up('md')]: {
@@ -278,12 +280,26 @@ const styles = theme => ({
},
button: {
textTransform: 'inherit',
marginLeft: theme.spacing(4),
marginRight: theme.spacing(4),
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
padding: theme.spacing(1.2, 2),
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.important,
alignSelf: 'center',
textDecoration:'none',
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
},
voirOffre: {
textTransform: 'inherit',
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
padding: theme.spacing(1.2, 2),
color: '#BBBCBD',
backgroundColor: '#F3F3F4',
},
buttonContainer: {
alignItems: 'right',
},
chip: {
color: theme.palette.secondary.main,
@@ -328,6 +344,9 @@ const styles = theme => ({
borderBottomLeftRadius: '5px',
borderBottomRightRadius: '5px',
},
lien:{
textDecoration:'none'
},
});
const CustomTableBody = ({ rowIds, Row, style, className }) => (
@@ -337,13 +356,13 @@ const CustomTableBody = ({ rowIds, Row, style, className }) => (
);
const { publicRuntimeConfig } = getConfig()
class Entreprise extends React.Component {
state = {
loading: true,
};
componentDidMount() {
localStorage.setItem('loginRedirect', window.location.pathname)
this.props.countCompanyViewRequest(this.props.company.id);
}
@@ -384,11 +403,12 @@ class Entreprise extends React.Component {
const { loading } = this.state;
const socialShareUrl = typeof window !== 'undefined' ? window.location
: publicRuntimeConfig.frontServerUrl + `/Entreprise/${company.id}`;
const descriptionVille = company.addresses.billing.city ? company.addresses.billing.city : "";
const descriptionCompany = company.brand_name ? company.brand_name : "";
return (
<LayoutCompany backLink="/Entreprises" companyId={company.id}>
<OgHead seo_title={company.brand_name && company.brand_name}
seo_description={company.description}
<OgHead seo_title={company.brand_name && company.brand_name+" recrute des candidats en vidéo | Talents Tube"}
seo_description={"Découvrez l'entreprise "+descriptionCompany +" et ses offres en vidéo - "+descriptionVille+ ". Envoyez votre candidature spontanée en vidéo."}
seo_url={socialShareUrl}
image={imgUrl}
></OgHead>
@@ -414,17 +434,30 @@ class Entreprise extends React.Component {
:
(<Chip label={nbOffre} className={classes.chip + ' ' + classes.chipHeader} />)
}
{/* ville */}
</div>
</div>
<div className={classes.buttonContainer}>
<Link href="#discover" >
<Button
variant="contained"
className={classes.voirOffre + ' cypButtonApply'}
>Voir les offres</Button>
</Link>
<a href={`/Reponse?companyId=${company.id}`} className={classes.lien}>
<Button
variant="contained"
className={classes.button}
onClick={() => Router.push(`/Reponse?companyId=${company.id}`)}
>Candidature spontanée</Button>
</a>
</div>
</section>
</Hidden>
{company.presentation_video && <VideoVimeo videoId={Ar.last(_.split(company.presentation_video.cdn_url, '/'))} autoplay='1' />}
{company.presentation_video && <Suspense fallback={renderLoader()}><VideoVimeo videoId={Ar.last(_.split(company.presentation_video.cdn_url, '/'))} autoplay='1' /></Suspense>}
<div className={classes.container}>
<Hidden mdUp>
<section className={classes.headerContainer}>
@@ -498,11 +531,19 @@ class Entreprise extends React.Component {
</SimpleCollapse>
<div className={classes.shareContainer}>
<Button
{/* <Button
variant="contained"
className={classes.button}
onClick={() => Router.push(`/Reponse?companyId=${company.id}`)}
>Candidature spontanée</Button>
>Candidature spontanée</Button> */}
<a
href={`/Reponse?companyId=${company.id}`}
variant="contained"
className={classes.button}
classes={{ root: classes.rootButton }}
// onClick={() => Router.push(`/Reponse?companyId=${companyId}`)}
>Candidature spontanée</a>
<Typography className={classes.contentCondition}>
ou
</Typography>
@@ -543,7 +584,7 @@ class Entreprise extends React.Component {
Découvrir le <span className={classes.primary}>territoire</span>
</Typography>
<section className={classes.discoverTerritoryContentContainer}>
<VideoVimeo classesOverride={classes.videoVimeo} videoId={territoryVideoId} autoplay='0' />
<Suspense fallback={renderLoader()}><VideoVimeo classesOverride={classes.videoVimeo} videoId={territoryVideoId} autoplay='0' /></Suspense>
<Typography className={classes.territoryTitle}>
{(company.territories) ? company.territories[0].territory.brand_name : ''}
</Typography>
+7 -3
View File
@@ -63,7 +63,10 @@ const styles = theme => ({
});
class Entreprises extends React.Component {
componentDidMount() {
localStorage.setItem('loginRedirect', window.location.pathname)
console.log("Redirect"+window.location.pathname)
}
render() {
const { classes } = this.props;
const { publicRuntimeConfig } = getConfig();
@@ -94,8 +97,8 @@ class Entreprises extends React.Component {
content=""/>
</Head> */}
<OgHead seo_title="Entreprises qui recrutent Talents Tube"
seo_description="Les entreprises en vidéo."
<OgHead seo_title="Vidéos marque employeur d'entreprises qui recrutent | Talents Tube"
seo_description="Vidéos marque employeur d'entreprises qui recrutent, découvrez leurs offres d'emploi en vidéo. Postulez simplement en vidéo à l'offre de votre choix."
seo_url={socialShareUrl}
image={imgUrl}
seo_key="Recrutement, video"
@@ -112,6 +115,7 @@ class Entreprises extends React.Component {
currentPage={this.props.currentPage}
recordCount={this.props.recordCount}
loading={this.props.loading}
type="entreprises"
limit={12}
placeholder={"Rechercher une entreprise"}
/>
+1 -1
View File
@@ -156,7 +156,7 @@ function Help(props) {
<Typography
className={classes.text}
gutterBottom>
Suivez ce <a href="https://blog.talentstube.com/faire-cv-video" target="_blank" >lien</a>
Suivez ce <a href="https://blog.talentstube.com/cv-video" target="_blank" >lien</a>
</Typography>
+265
View File
@@ -0,0 +1,265 @@
import React, { Fragment } from 'react';
import PropTypes from "prop-types";
import Layout from '../components/templates/Layout';
import { TextField, Button, Typography } from '@material-ui/core';
import SwipeableViews from 'react-swipeable-views';
import AppBar from '@material-ui/core/AppBar';
import Link from '@material-ui/core/Link';
import { withStyles } from '@material-ui/core/styles';
import Loader from '../components/templates/loader'
import { connect } from "react-redux";
import Validator from "validator";
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import Router from 'next/router'
import Register from '../components/organisms/Register';
// import { requestLogin, requestOauthLogin, requestLoginFailure } from "../actions/auth";
import { makeStyles } from '@material-ui/core/styles';
import { amber, green } from '@material-ui/core/colors';
import _ from "lodash"
import Snack from '../components/atoms/snack'
import SocialButtonsAuth from '../components/atoms/SocialButtonsAuth';
import jssPluginPropsSort from 'jss-plugin-props-sort';
import Head from 'next/head'
import ReCAPTCHA from "react-google-recaptcha";
import getConfig from 'next/config'
const {publicRuntimeConfig} = getConfig()
function TabContainer({ children, dir }) {
return (
<Typography component="div" dir={dir} style={{ padding: 8 * 3 }}>
{children}
</Typography>
);
}
TabContainer.propTypes = {
children: PropTypes.node.isRequired,
dir: PropTypes.string.isRequired,
};
const styles = theme => ({
container: {
display: 'flex',
flexDirection: 'column',
},
AppBar: {
position: 'fixed',
top: theme.spacing(8),
},
tab: {
'& span.MuiTab-wrapper': {
fontSize: '1.1em',
fontWeight: '600',
textTransform: 'none',
}
},
tabContainer: {
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%'
},
form: {
display: 'flex',
flexDirection: 'column',
},
formText: {
padding: theme.spacing(0, 2),
paddingTop: theme.spacing(3),
fontSize: '0.9em',
fontWeight: '300',
},
formLink: {
paddingLeft: theme.spacing(1),
fontWeight: '500',
cursor: 'pointer',
},
forgetPasswordText: {
marginTop: theme.spacing(2),
},
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',
},
},
link: {
color: theme.palette.primary.dark,
fontWeight: 400,
fontSize: '0.9em',
},
input50: {
width: '50%',
},
button: {
textTransform: 'inherit',
marginLeft: theme.spacing(8),
marginRight: theme.spacing(8),
marginTop: theme.spacing(4),
marginBottom: theme.spacing(2),
padding: theme.spacing(1.2, 2),
borderRadius: '3px',
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.important,
[theme.breakpoints.up('sm')]: {
margin: 'auto',
},
},
buttonImportant: {
marginTop: theme.spacing(6),
},
});
const recaptchaRef = React.createRef();
class LoginPage extends React.Component {
state = {
data: {
email: "",
password: ""
},
errors: { message: "" },
loading: false,
tabIndex: 0,
openSnack: false,
success: 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
})
}
static getInitialProps({ query }) {
const { error, inscription } = query
let err = null;
if (!!error)
err = { message: error };
return { errors: err, openSnack: !!error, inscription };
}
handleClose = e =>
this.setState({
openSnack: false
});
componentDidMount() {
}
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);
// recaptchaRef.current.execute();
// this.setState({ errors });
// if (Object.keys(errors).length === 0) {
// this.setState({ loading: true });
// this.props.requestLogin(this.state.data)
// }
// };
submit = data => { this.props.login(data) }
validate = data => {
const errors = {};
if (!Validator.isEmail(data.email)) errors.email = "Invalid email";
if (!data.password) errors.password = "Can't be blank";
return errors;
};
// linkedInAuth = () => {
// this.props.requestOauthLogin();
// Router.push('/auth/linkedin')
// }
// facebookAuth = () => {
// this.props.requestOauthLogin();
// Router.push('/auth/facebook')
// }
render() {
const { classes } = this.props;
const { data,success, errors, loading, openSnack } = this.state;
return (
<Layout>
<Head>
<title key="title">Inscription</title>
<meta key="robots" name="robots" content="noindex, follow"></meta>
</Head>
<div className={classes.container}>
{/* {!!errors && (
<div className="alert alert-danger">{errors && errors.message}</div>
)} */}
{loading && (
<Loader />
)}
{!loading && (
<Fragment>
<Register linkedInAuth={this.linkedInAuth} facebookAuth={this.facebookAuth} erreurs={errors.message} />
</Fragment>
)}
</div>
{/* <Snack name={success ? 'snackSuccess' : 'snackWarning'}
variant={success ? 'success' : 'warning'}
message={success ? 'Inscription validée.' : errors.message}
openSnack={openSnack}
onClose={this.handleClose} /> */}
</Layout>
);
}
}
function mapStateToProps(state, ownProps) {
return {
loading: !!state.user.loading,
errors: state.user.errors || ownProps.errors
};
}
export default withStyles(styles)(connect(mapStateToProps, { })(LoginPage));
+37 -18
View File
@@ -12,7 +12,7 @@ import Validator from "validator";
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import Router from 'next/router'
import Register from '../components/organisms/Register';
// import Register from '../components/organisms/Register';
import { requestLogin, requestOauthLogin, requestLoginFailure } from "../actions/auth";
import { makeStyles } from '@material-ui/core/styles';
import { amber, green } from '@material-ui/core/colors';
@@ -23,6 +23,7 @@ import jssPluginPropsSort from 'jss-plugin-props-sort';
import Head from 'next/head'
import ReCAPTCHA from "react-google-recaptcha";
import getConfig from 'next/config'
import FacebookLogin from 'react-facebook-login';
const {publicRuntimeConfig} = getConfig()
function TabContainer({ children, dir }) {
@@ -149,7 +150,8 @@ class LoginPage extends React.Component {
errors: {},
loading: false,
tabIndex: 0,
openSnack: false
openSnack: false,
redirection:""
};
static getInitialProps({ query }) {
@@ -175,8 +177,11 @@ class LoginPage extends React.Component {
}
componentDidMount() {
console.log("redirect login");
console.log(localStorage.getItem('loginRedirect'));
this.setState({
tabIndex: (this.props.inscription) ? 1 : 0,
redirection : localStorage.getItem('loginRedirect')
})
}
@@ -226,11 +231,14 @@ class LoginPage extends React.Component {
handleClose = (event, reason) => {
this.setState({ openSnack: false });
}
responseFacebook = (response) => {
console.log(response);
}
render() {
const { classes } = this.props;
const { data, errors, loading, openSnack } = this.state;
return (
<Layout>
<Head>
@@ -246,7 +254,7 @@ class LoginPage extends React.Component {
)}
{!loading && (
<Fragment>
<AppBar className={classes.AppBar} color="default">
{/* <AppBar className={classes.AppBar} color="default">
<Tabs
value={this.state.tabIndex}
onChange={this.handleChange}
@@ -256,7 +264,7 @@ class LoginPage extends React.Component {
<Tab label="Connexion" className={classes.tab} />
<Tab label="Inscription" className={classes.tab} />
</Tabs>
</AppBar>
</AppBar> */}
<SwipeableViews
axis={'x'}
index={this.state.tabIndex}
@@ -276,7 +284,7 @@ class LoginPage extends React.Component {
onChange={this.onChange}
autoComplete="username"
variant="outlined"
error={this.state.errors && !!this.state.errors.email}
error={!!!_.isEmpty(this.state.errors)  || (this.state.errors && !!this.state.errors.email)}
className={'cypInputEmail'}
required
@@ -294,11 +302,19 @@ class LoginPage extends React.Component {
autoComplete="current-password"
variant="outlined"
className={'cypInputPassword'}
error={!!!_.isEmpty(this.state.errors)}
helperText={!!!_.isEmpty(this.state.errors) && this.state.errors.message}
required
/>
<Button type="submit" variant="contained" className={classes.button + ' ' + classes.buttonImportant + ' cypButtonConnexion'}>
Se connecter
</Button>
</Button>
{/* <FacebookLogin
appId="1800752833559014"
autoLoad={true}
fields="name,email,picture"
textButton ="Connexion Facebook"
callback={this.responseFacebook} /> */}
<ReCAPTCHA
id="component-outlined"
ref={recaptchaRef}
@@ -312,19 +328,21 @@ class LoginPage extends React.Component {
>
<Link href={"/ResetPassword"} className={classes.link}>
Mot de passe oublié ?
</Link>
</Link>
</Typography>
<Typography
{/* <Typography
paragraph={true}
align="center"
className={classes.conditionalText}
>Ou</Typography>
>Ou</Typography> */}
</form>
<SocialButtonsAuth linkedInAuth={this.linkedInAuth} facebookAuth={this.facebookAuth} />
{/* <SocialButtonsAuth linkedInAuth={this.linkedInAuth} facebookAuth={this.facebookAuth} /> */}
<div className={classes.form}>
<Typography
@@ -332,9 +350,9 @@ class LoginPage extends React.Component {
align="center"
className={classes.formText}
>Je ne possède pas de compte Talents Tube ?
<span onClick={() => this.handleChangeIndex(1)} className={classes.formLink}>
S'inscrire
</span>
<Link href="/Inscription">S'inscrire</Link>
</Typography>
</div>
@@ -348,21 +366,22 @@ class LoginPage extends React.Component {
</div>
</TabContainer>
<TabContainer dir={'x'}>
{/* <TabContainer dir={'x'}>
<Register linkedInAuth={this.linkedInAuth} facebookAuth={this.facebookAuth} />
</TabContainer>
</TabContainer> */}
</SwipeableViews>
</Fragment>
)}
</div>
<Snack variant="error" message={!!!_.isEmpty(this.state.errors) && this.state.errors.message}
openSnack={this.state.openSnack} onClose={this.handleClose} />
{/* <Snack variant="error" message={!!!_.isEmpty(this.state.errors) && this.state.errors.message}
openSnack={this.state.openSnack} onClose={this.handleClose} /> */}
</Layout>
);
}
}
function mapStateToProps(state, ownProps) {
return {
loading: !!state.user.loading,
errors: state.user.errors || ownProps.errors
+14 -9
View File
@@ -1,22 +1,26 @@
import React from 'react';
import React, { Fragment,lazy, Suspense } from 'react'
import { connect } from "react-redux";
import PropTypes from 'prop-types';
import getConfig from 'next/config'
import { withStyles } from '@material-ui/core/styles';
import LayoutOffre from "../components/templates/LayoutOffre";
import OffreDetail from "../components/organisms/OffreDetail";
import { fetchAdRequest, clearAd, countAdViewRequest } from '../actions/ads'
const OffreDetail = lazy(() => import('../components/organisms/OffreDetail'));
//import OffreDetail from "../components/organisms/OffreDetail";
import { fetchJobRequest, clearAd, countAdViewRequest } from '../actions/ads'
import _ from "lodash/string";
const renderLoader = () => <p>Chargement</p>;
const styles = theme => ({
});
const { publicRuntimeConfig } = getConfig()
class Offre extends React.Component {
componentDidMount() {
localStorage.setItem('loginRedirect', window.location.pathname)
localStorage.setItem('adId', this.props.offre.id)
this.props.countAdViewRequest(this.props.offre.id);
}
@@ -29,10 +33,11 @@ class Offre extends React.Component {
}
render() {
const { classes, offre } = this.props;
const socialShareUrl = typeof window !== 'undefined' ? window.location : publicRuntimeConfig.frontServerUrl + `/Offre/${offre.id}-${_.kebabCase(offre.title)}`;
return (
<LayoutOffre backLink="/Offres" offreId={offre.id} isProvided={offre.is_promoted}>
<OffreDetail offre={offre}/>
<LayoutOffre backLink="/Offres" offreId={offre.id} offre={offre} isProvided={offre.is_promoted}>
{/* <Suspense fallback={renderLoader()}><OffreDetail offre={offre}/></Suspense> */}
<Suspense fallback={renderLoader()}><OffreDetail offre={offre}/></Suspense>
</LayoutOffre>
);
}
@@ -42,7 +47,7 @@ class Offre extends React.Component {
Offre.getInitialProps = function (context) {
const { id } = context.query
context.store.dispatch(fetchAdRequest(id))
context.store.dispatch(fetchJobRequest(id))
return id;
}
@@ -57,4 +62,4 @@ Offre.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(connect(mapStateToProps, { fetchAdRequest, clearAd, countAdViewRequest})(Offre));
export default withStyles(styles)(connect(mapStateToProps, { fetchJobRequest, clearAd, countAdViewRequest})(Offre));
+23 -6
View File
@@ -9,7 +9,7 @@ import LayoutGrid from "../components/templates/LayoutGrid";
import Grid from "../components/templates/Grid"
import OffreRow from "../components/organisms/OffreRow"
import Typography from '@material-ui/core/Typography';
import { fetchAdsRequest, togglePromotedFilterRequest} from '../actions/ads'
import { fetchJobsRequest, togglePromotedFilterRequest} from '../actions/ads'
import { AdsSelector } from '../reducers/ads'
import { TextField } from '@material-ui/core';
import Head from 'next/head'
@@ -80,9 +80,24 @@ class Offres extends React.Component {
constructor(props) {
super(props);
}
voirOffre(){
this.props.togglePromotedFilterRequest()
sessionStorage.setItem('offres_currentPage',1);
}
static getInitialProps({ query }) {
const { init } = query
//this.props.promotedFilter =init
return { init };
}
componentDidMount() {
localStorage.setItem('loginRedirect', window.location.pathname)
console.log("Redirect"+window.location.pathname)
}
render() {
const { classes } = this.props;
const countColor = this.props.promotedFilter ? classes.provided : classes.primary;
const btnClass = this.props.promotedFilter ? classes.buttonDefault : classes.buttonProvided;
@@ -93,8 +108,8 @@ class Offres extends React.Component {
const imgUrl = DefaultUrl ;
return (
<LayoutGrid backLink="/">
<OgHead seo_title="Offres demploi en vidéo Talents Tube"
seo_description="Les offres d'emploi en vidéo."
<OgHead seo_title="Vidéos d'offres d'emploi, CDI, CDD, alternance et Stage | Talents Tube"
seo_description="Vidéos d'offres d'emploi, CDI, CDD, alternance, stage et apprentissage d'entreprises qui recrutent sur Talents Tube."
seo_url={socialShareUrl}
image={imgUrl}
seo_key="Recrutement, video"
@@ -107,18 +122,20 @@ class Offres extends React.Component {
</Typography>
<div className={classes.container}>
<Grid CustomRowComponent={OffreRow}
dataFetcher={this.props.fetchAdsRequest}
dataFetcher={this.props.fetchJobsRequest}
data={this.props.ads}
currentPage={this.props.currentPage}
recordCount={this.props.recordCount}
promoted={this.props.promotedFilter}
loading={this.props.loading}
type="offres"
placeholder={"Rechercher un job"}
/>
<Button
name="Rechercher un job"
variant="outlined"
onClick={() => this.props.togglePromotedFilterRequest()}
onClick={() => this.voirOffre()
}
className={classes.button + ' ' + btnClass}>
{this.props.promotedFilter? 'Voir les offres en cours' : 'Voir les offres pourvues'}
</Button>
@@ -148,4 +165,4 @@ function mapStateToProps(state) {
};
}
export default withStyles(styles)(connect(mapStateToProps, { fetchAdsRequest, togglePromotedFilterRequest })(Offres))
export default withStyles(styles)(connect(mapStateToProps, { fetchJobsRequest, togglePromotedFilterRequest })(Offres))
+82
View File
@@ -0,0 +1,82 @@
import React, { Component, Fragment,lazy, Suspense } from 'react';
import { withStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography'
import LayoutBackUrl from '../components/templates/LayoutBackUrl';
import Router from 'next/router';
import Head from 'next/head'
// const VideoVimeo = lazy(() => import('../components/atoms/VideoVimeo'));
import VideoVimeo from '../components/atoms/VideoVimeo';
import queryString from 'query-string';
const renderLoader = () => <p>Chargement</p>;
const styles = theme => ({
player: {
background:'#1E2327',
height: '100%'
},
container: {
display: 'flex',
flexDirection: 'column',
position: 'relative',
height: '100%',
padding: '0 10px',
},
bottomContainer: {
display: 'flex',
flexDirection: 'column',
alignSelf: 'center',
justifyContent: 'center',
position: 'absolute',
bottom: 0,
},
title: {
fontFamily: 'Dosis',
fontSize: '1.5em',
fontWeight: '600',
padding: theme.spacing(3, 0),
},
text: {
fontSize: '1em',
fontWeight: '300',
padding: theme.spacing(1, 0),
whiteSpace: 'pre-line',
},
video: {
width:"100%",
height:"100%",
[theme.breakpoints.up('md')]: {
paddingBottom: '35%', /* 16:9 */
},
}
})
class Player extends Component {
render() {
const { classes } = this.props
const params = queryString.parse(location.search);
console.log(params.id);
console.log(params.type);
console.log(params.videoId);
let url = params.id;
return (
<LayoutBackUrl text="Player" url={url} >
<VideoVimeo classes={{ video: classes.video }} videoId={params.videoId} options="" autoplay='1' />
</LayoutBackUrl>
)
}
}
Player.getInitialProps = function (context) {
let { id, videoId,type } = context.query;
let {res} = context;
return {};
}
export default withStyles(styles)(Player);
+201 -96
View File
@@ -5,11 +5,11 @@ import PropTypes from 'prop-types';
import Stepper from '@material-ui/core/Stepper';
import Step from '@material-ui/core/Step';
import StepLabel from '@material-ui/core/StepLabel';
import { fetchAdRequest } from '../actions/ads'
import { fetchJobRequest } from '../actions/ads'
import { fetchCompanyRequest } from '../actions/companies'
import { fetchCurrentUserRequest } from '../actions/user'
import { uploadMedia } from '../actions/media'
import Loader from './../components/templates/loader'
import LoaderVideo from './../components/templates/loaderVideo'
import Answer from '../components/organisms/Answer'
import LayoutBack from '../components/templates/LayoutBack'
import { withStyles } from '@material-ui/core/styles'
@@ -36,9 +36,9 @@ const styles = theme => ({
},
rootStepperContainer: {
padding: theme.spacing(2, 12),
width: '25vw',
width: '50vw',
[theme.breakpoints.up('md')]: {
width: '7vw',
width: '25vw',
alignItems: 'center',
},
'& .MuiStep-horizontal, & .MuiStepLabel-iconContainer': {
@@ -48,11 +48,30 @@ const styles = theme => ({
},
},
'& .Mui-disabled .MuiStepConnector-line': {
borderColor: theme.palette.answer.main + '!important',
borderColor: 'd2d3d3 !important',
},
'& .Mui-disabled .MuiStepIcon-root': {
color: theme.palette.answer.main + '!important',
},
'& .MuiStepIcon-root': {
color: '#1689FB !important',
},
'& .MuiTypography-root ': {
color: '#1e2327 !important',
},
},
stepContainer:{
width:'600px',
alignItems: 'center',
textAlign: 'center',
align: 'center',
},
stepLabel:{
// width:'150px',
// display:'inline',
// alignItems: 'center',
// align: 'center',
},
rootStepperDefault: {
'& .MuiStepConnector-line': {
@@ -75,15 +94,29 @@ const styles = theme => ({
flexDirection: 'column',
padding: theme.spacing(0, 1.5),
},
titreContainer: {
backgroundColor: '#fff',
borderRadius: '5px',
maxWidth:'600px',
boxShadow: '0px 6px 16px rgba(30, 35, 39, 0.15)',
display: 'flex',
padding: '25px',
margin: '40px 0 20px 0',
alignItems: 'center',
justifyContent: 'flex-start',
},
logoContainer: {
display: 'flex',
alignItems: 'center',
width: 60,
height: 60,
width: 75,
height: 75,
backgroundColor: 'white',
boxShadow: '0px 6px 15px rgba(30, 35, 39, 0.10)',
border: 'solid 5px white',
borderRadius: '6px',
marginLeft:'30px',
},
recorderContainer: {
//display: 'flex',
@@ -107,11 +140,11 @@ const styles = theme => ({
objectFit: 'contain',
},
title: {
fontSize: '1em',
fontSize: '1.25em',
fontWeight: '500',
},
companyName: {
fontSize: '0.9em',
fontSize: '1em',
fontWeight: '300',
},
textContainer: {
@@ -147,6 +180,12 @@ const styles = theme => ({
fontSize: '1.15em',
paddingLeft: theme.spacing(2),
},
textButtonReponse: {
fontWeight: '700',
fontSize: '1.15em',
paddingLeft: theme.spacing(2),
color:'#1e2327',
},
iconHelpButton: {
fontSize: '1.5em',
fontWeight: '500',
@@ -167,6 +206,7 @@ const styles = theme => ({
},
captureButton: {
width:400,
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.main,
padding: theme.spacing(5, 2),
@@ -177,6 +217,7 @@ const styles = theme => ({
},
},
importButton: {
width:400,
color: theme.palette.primary.main,
backgroundColor: theme.palette.secondary.main,
padding: theme.spacing(3, 2),
@@ -198,9 +239,13 @@ const styles = theme => ({
fontSize: '2.5em',
color: theme.palette.primary.main,
},
InputKeyboardArrowDownIconNoir: {
fontSize: '2.5em',
color: '#1e2327',
},
});
const steps = ["", ""]
const steps = ["Réaliser une vidéo de réponse", "Renseigner mes informations"]
const Recorder = dynamic(() => import('../components/organisms/Recorder'), {
ssr: false
@@ -214,14 +259,19 @@ class Reponse extends React.Component {
data:{},
openSnack: false,
errors: {},
openStudio : false
};
componentDidMount() {
localStorage.setItem('loginRedirect', window.location)
console.log('loginRedirect reponse');
console.log(window.location.pathname+ window.location.search);
//localStorage.setItem('loginRedirect', window.location.pathname+ window.location.search)
if(!!!localStorage.getItem('ttJWT'))
{
Router.push("/Login")
console.log("REPONSE REDIRECT LOGIN")
Router.push("/Inscription")
}
else
this.setState({loading: false})
@@ -265,6 +315,16 @@ class Reponse extends React.Component {
this.setState({ openSnack: false });
}
realise =() =>{
console.log("realise");
this.setState({ openStudio: true});
}
retour =() =>{
console.log("retour");
this.setState({ openStudio: false});
}
render() {
const { loading, activeStep } = this.state;
const { classes, menu, offre, company } = this.props;
@@ -286,29 +346,31 @@ class Reponse extends React.Component {
</Head>
{/* https://codesandbox.io/s/ii0us */}
{ loading ?
<Loader /> :
<LoaderVideo /> :
<Fragment>
<section className={classes.headerContainer}>
{ !!offre.company && (
<Fragment>
<div className={classes.logoContainer}>
<Avatar className={classes.logo} classes={{ img: classes.MuiAvatarImg }} src={logoUrl} alt="companylogo"/>
</div>
<div className={classes.infoContainer}>
<Typography gutterBottom variant="h5" component="h1" className={classes.title}>
{!!offre.title? offre.title: ''}
</Typography>
<Typography gutterBottom variant="subtitle1" className={classes.companyName}>
{!!offre.company.brand_name? offre.company.brand_name: ''}
</Typography>
{/* ville */}
</div>
</Fragment>)
<div className={classes.titreContainer}>
<div className={classes.logoContainer}>
<Avatar className={classes.logo} classes={{ img: classes.MuiAvatarImg }} src={logoUrl} alt="companylogo"/>
</div>
<div className={classes.infoContainer}>
<Typography gutterBottom variant="h5" component="h1" className={classes.title}>
{!!offre.title? offre.title: ''}
</Typography>
<Typography gutterBottom variant="subtitle1" className={classes.companyName}>
{!!offre.company.brand_name? offre.company.brand_name: ''}
</Typography>
{/* ville */}
</div>
</div>
)
}
{ !!company.brand_name && (<Fragment><div className={classes.logoContainer}>
<Avatar className={classes.logo} classes={{ img: classes.MuiAvatarImg }} src={logoCompanyUrl} alt="companylogo"/>
{/* <Avatar className={classes.logo} classes={{ img: classes.MuiAvatarImg }} src={logoCompanyUrl} alt="companylogo"/> */}
</div>
<div className={classes.infoContainer}>
<Typography gutterBottom variant="h5" component="h1" className={classes.title}>
@@ -322,92 +384,133 @@ class Reponse extends React.Component {
}
</section>
<Stepper activeStep={activeStep} classes={{ root: rootStepper }} className={classes.rootStepperContainer}>
<section className={classes.headerContainer}>
<Stepper activeStep={activeStep} classes={{ root: rootStepper }} className={classes.rootStepperContainer} alternativeLabel>
{steps.map((label, index) => {
return (
<Step key={label} >
<StepLabel>{label}</StepLabel>
<Step className={classes.stepContainer} key={index} >
<StepLabel className={classes.stepLabel}>{label}</StepLabel>
</Step>
);
})}
</Stepper>
</section>
{loading ? ( <Loader />)
: activeStep === 0 ?
(
<div className={classes.root}>
<div className={classes.textContainer}>
<Typography gutterBottom align="center">
Vous allez postuler en <span>vidéo</span> !
</Typography>
<Typography gutterBottom align="center">
C'est <span>simple</span>,<span> rapide</span> et <span>plus humain</span>
</Typography>
</div>
<div className={ classes.helpContainer}>
<Button component="span" className={classes.helpButton} classes={{ root: classes.rootButton }} onClick={() => Router.push(`/Conseils`)}>
<Typography align="center" className={classes.textButton}>
Par <span className={classes.underlined}>ici</span> pour quelques conseils !
</Typography>
<KeyboardArrowRightIcon className={ classes.HelpKeyboardArrowRightIcon }/>
</Button>
</div>
{ /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 réponse
{this.state.openStudio == false &&
<div>
{/* <div className={classes.textContainer}>
<Typography gutterBottom align="center">
Vous allez postuler en <span>vidéo</span> !
</Typography>
<KeyboardArrowRightIcon className={ classes.InputKeyboardArrowRightIcon }/>
<Typography gutterBottom align="center">
C'est <span>simple</span>,<span> rapide</span> et <span>plus humain</span>
</Typography>
</div> */}
{/* <div className={ classes.helpContainer}>
<Button component="span" className={classes.helpButton} classes={{ root: classes.rootButton }} onClick={() => Router.push(`/Conseils`)}>
<Typography align="center" className={classes.textButton}>
Par <span className={classes.underlined}>ici</span> pour quelques conseils !
</Typography>
<KeyboardArrowRightIcon className={ classes.HelpKeyboardArrowRightIcon }/>
</Button>
</label>
</Fragment>
</div> */}
</div>
}
{/* Soit on affiche le module Web RTC soit on affiche un module de camrecorder */}
{ /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='/statique/images/capture.svg' className={classes.iconButton} />
<Typography align="left" className={classes.textButton}>
Je <span className={classes.underlined}>réalise</span> ma vidéo de réponse
</Typography>
<KeyboardArrowRightIcon className={ classes.InputKeyboardArrowRightIcon }/>
</Button>
</label>
</Fragment>
):
(
<div className={classes.recorderContainer}>
<Recorder uploader={this.props.uploadMedia} />
</div>
<Fragment>
{this.state.openStudio == false ?
<Button component="span" className={classes.captureButton} classes={{ root: classes.rootButton }} onClick={this.realise}>
<img alt="talents-tube" src='/statique/images/capture.svg' className={classes.iconButton} />
<Typography align="left" className={classes.textButton}>
Je <span className={classes.underlined}>réalise</span> ma vidéo de réponse
</Typography>
<KeyboardArrowRightIcon className={ classes.InputKeyboardArrowRightIcon }/>
</Button>
:
<div className={classes.recorderContainer}>
<Button onClick={this.retour}>Retour au menu</Button>
<Recorder uploader={this.props.uploadMedia} />
</div>
}
</Fragment>
// <div className={classes.recorderContainer}>
// <Recorder uploader={this.props.uploadMedia} />
// </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='/static/images/import.svg' className={classes.iconButton} />
<Typography align="left" className={classes.textButton}>
J'<span className={classes.underlined}>importe</span> ma vidéo de réponse
</Typography>
<KeyboardArrowDownIcon className={ classes. InputKeyboardArrowDownIcon }/>
</Button>
</label>
{this.state.openStudio == false ?
<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 réponse
</Typography>
<KeyboardArrowDownIcon className={ classes. InputKeyboardArrowDownIcon }/>
</Button>
</label>
</div>
<div>
<Button component="span" className={classes.importButton} classes={{ root: classes.rootButton }} onClick={() => Router.push(`/Conseils`)}>
<img alt="talents-tube" src='/statique/images/comment-faire-une-video-reponse.svg' className={classes.iconButton} />
<Typography align="left" className={classes.textButtonReponse}>
Comment faire ma vidéo de réponse
</Typography>
<KeyboardArrowRightIcon className={ classes. InputKeyboardArrowDownIconNoir }/>
</Button>
</div>
</div>
:
<div></div>
}
</div>
) :
(
<Answer mediaId={!!this.props.media && this.props.media.id}
companyId={!!offre.company ? offre.company.id : !!company.brand_name ? company.id : null}
adId={offre.id}>
adId={offre.id}
>
</Answer>
)}
<Snack variant="error" message={!!!_.isEmpty(this.state.errors) && this.state.errors.message }
@@ -426,10 +529,10 @@ Reponse.getInitialProps = function (context) {
const { adId, companyId } = context.query
const {res} = context
//TODO :really needed ?
context.store.dispatch(fetchCurrentUserRequest())
context.store.dispatch(fetchCurrentUserRequest())
if(!!adId)
context.store.dispatch(fetchAdRequest(adId))
context.store.dispatch(fetchJobRequest(adId))
else if(!!companyId)
context.store.dispatch(fetchCompanyRequest(companyId))
@@ -437,7 +540,9 @@ Reponse.getInitialProps = function (context) {
}
function mapStateToProps(state) {
console.log("attente")
console.log(state.media)
return {
loading: !!state.answer.loading || !!state.media.loading,
media: state.media,
@@ -452,4 +557,4 @@ Reponse.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(connect(mapStateToProps, { fetchCurrentUserRequest, fetchAdRequest, fetchCompanyRequest, uploadMedia })(Reponse));
export default withStyles(styles)(connect(mapStateToProps, { fetchCurrentUserRequest, fetchJobRequest, fetchCompanyRequest, uploadMedia })(Reponse));
+97 -18
View File
@@ -5,8 +5,15 @@ import Typography from '@material-ui/core/Typography'
import Button from '@material-ui/core/Button';
import Router from 'next/router';
import Head from 'next/head'
import { TextField } from '@material-ui/core';
const styles = theme => ({
root: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'flex-start',
margin: theme.spacing(1),
},
container: {
display: 'flex',
flexDirection: 'column',
@@ -24,33 +31,74 @@ const styles = theme => ({
width: '100%',
},
title: {
fontFamily: 'Dosis',
fontSize: '1.5em',
fontFamily: 'Roboto',
fontSize: '1.625em',
fontWeight: '600',
padding: theme.spacing(3, 0),
},
text: {
fontFamily: 'Roboto',
width:"400px",
fontSize: '1em',
fontWeight: '300',
padding: theme.spacing(1, 0),
},
textSpam:{
fontFamily: 'Roboto',
width:"400px",
fontSize: "1em",
fontWeight: "500",
padding: theme.spacing(1, 0),
},
email: {
fontWeight: '500',
},
bottomText: {
fontWeight: '500',
},
iconButton:{
marginTop: "50px",
[theme.breakpoints.down('md')]: {
marginTop: "50px",
},
},
textContainer: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
notUnderline:{
textDecoration :'none'
},
rootButton: {
'&:hover': {
backgroundColor: theme.palette.primary.important + '!important',
},
},
button: {
textTransform: 'inherit',
marginLeft: theme.spacing(8),
marginRight: theme.spacing(8),
marginTop: theme.spacing(4),
marginBottom: theme.spacing(2),
marginRight: 'auto',
marginLeft: 'auto',
padding: theme.spacing(1.2, 1),
padding: theme.spacing(1.2, 2),
borderRadius: '3px',
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.important,
[theme.breakpoints.up('sm')]: {
margin: 'auto',
},
},
buttonImportant: {
marginTop: theme.spacing(6),
},
champEmail:{
width:'400px'
}
});
class VerifyEmail extends Component {
@@ -62,18 +110,49 @@ class VerifyEmail extends Component {
<title key="title">Vérification d'email</title>
<meta key="robots" name="robots" content="noindex, nofollow"></meta>
</Head>
<div className={classes.container}>
<Typography gutterBottom align="center" className={classes.title}>
Consultez vos e-mails
</Typography>
<Typography gutterBottom align="left" className={classes.text}>
Un e-mail a été envoyé à l'adresse <span className={classes.email}>{email}</span>
</Typography>
<Typography gutterBottom align="left" className={classes.text}>
Cliquez sur le lien dans l'e-mail que nous vous avons envoyé pour activer votre compte.
</Typography>
<div className={classes.root}>
<div className={classes.textContainer}>
<img
alt="talents-tube"
src='/statique/images/inscription/inscription-plateforme-recrutement-video.svg'
className={classes.iconButton}/>
<Typography gutterBottom align="center" className={classes.title}>
Consultez vos e-mails
</Typography>
<Typography gutterBottom align="left" className={classes.text}>
Cliquez sur le lien dans lemail que nous vous avons envoyé pour activer votre compte Talent. Vous pourrez ensuite vous connecter.
</Typography>
<TextField
value={email}
className={classes.champEmail}
id="emailVerif"
name="emailVerif"
label="Email"
margin="normal"
variant="outlined"
InputProps={{
readOnly: true,
}}
/>
<Typography align="center" className={classes.textSpam}>
Vous n'avez pas reçu l'email ? Pensez à consulter vos spams
</Typography>
<a
href={`/Login`}
variant="contained"
className={classes.notUnderline}
>
<Button variant="contained" className={classes.button + ' ' + classes.buttonImportant + ' cypButtonConnexion'}>
Se connecter
</Button>
</a>
</div>
<section className={classes.bottomContainer}>
<Typography gutterBottom align="center" className={classes.bottomText}>
{/* <Typography gutterBottom align="center" className={classes.bottomText}>
Cliquez sur suivant pour continuer votre candidature
</Typography>
<Button
@@ -83,7 +162,7 @@ class VerifyEmail extends Component {
onClick={() => Router.push('/Login')}
>
Suivant
</Button>
</Button> */}
</section>
</div>
</Layout>
+3 -3
View File
@@ -18,7 +18,7 @@ class MyDocument extends Document {
const { pageContext } = this.props;
return (
<html lang="en" dir="ltr">
<html lang="fr" dir="ltr">
<Head>
<meta name="google-site-verification" content="CQsVLRoDEzxN5TT4zoTIPy_v4JWGPQgg29OLNx8EkXw" />
<meta charSet="utf-8" />
@@ -32,9 +32,9 @@ class MyDocument extends Document {
{/* PWA primary color */}
<meta name="theme-color" content={theme.palette.primary.main} />
<link href="https://fonts.googleapis.com/css?family=Dosis:200,300,400,500,600,700,800|Roboto:100,100i,300,300i,400,400i,500,500i,700,700i,900,900i&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Dosis:600|Roboto:200,300,400,500,700,900&display=swap" rel="stylesheet">
</link>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDYV8IJGtIoWLfXJQQvIuDQ88n2aEuRgpg&libraries=places"></script>
<script type="text/javascript" src="/static/js/pwaInstaller.js" ></script>
{/* Global Site Tag (gtag.js) - Google Analytics */}
{/* <script
+19 -17
View File
@@ -1,6 +1,6 @@
/* eslint-disable jsx-a11y/anchor-is-valid */
import React, {Fragment} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Layout from "../components/templates/Layout"
@@ -8,19 +8,21 @@ import { Typography } from '@material-ui/core';
import Button from '@material-ui/core/Button';
import Router from 'next/router'
import { connect } from 'react-redux'
import { fetchEmphasisAdsRequest } from "../actions/ads";
//const fetchEmphasisJobsRequest = lazy(() => import('../actions/ads'));
import { fetchEmphasisJobsRequest } from "../actions/ads";
//const fetchEmphasisCompaniesRequest = lazy(() => import('../actions/companies'));
import { fetchEmphasisCompaniesRequest } from "../actions/companies";
import Loader from './../components/templates/loader'
import { isEmpty } from "lodash"
import NoResult from './../components/atoms/NoResult';
import Head from 'next/head'
// import Head from 'next/head'
import dynamic from 'next/dynamic'
import OgHead from '../components/atoms/OgHead';
import getConfig from 'next/config'
const VideoSlider = dynamic(() => import('../components/organisms/ShortVideoHooker'), {
ssr: false
});
// const VideoSlider = dynamic(() => import('../components/organisms/ShortVideoHooker'), {
// ssr: false
// });
const HorizontalScroller = dynamic(() => import('../components/organisms/HorizontalScroller'), {
ssr: false
});
@@ -140,17 +142,17 @@ const styles = theme => ({
class Index extends React.Component {
state = {
emphasisAds: [],
emphasisJobs: [],
emphasisCompanies: []
}
componentDidMount() {
localStorage.setItem("loginRedirect", "/")
this.props.fetchEmphasisAdsRequest({ isEmphasis: 1 })
this.props.fetchEmphasisJobsRequest({ isEmphasis: 1 })
this.props.fetchEmphasisCompaniesRequest({ isEmphasis: 1 })
}
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
emphasisAds: nextProps.emphasisAds,
emphasisJobs: nextProps.emphasisJobs,
emphasisCompanies: nextProps.emphasisCompanies
})
}
@@ -163,8 +165,8 @@ class Index extends React.Component {
const imgUrl = DefaultUrl
return (
<Layout>
<OgHead seo_title="Entreprises qui recrutent Talents Tube"
seo_description="Les entreprises en vidéo."
<OgHead seo_title="Espace candidat - Plateforme de recrutement en vidéo | Talents Tube"
seo_description="Talents Tube est la première plateforme réservée aux offres d'emploi vidéo, vidéo marque employeur et aux CV vidéos. Découvrez une nouvelle méthode de recrutement."
seo_url={socialShareUrl}
image={imgUrl}
seo_key="Recrutement, video"
@@ -172,7 +174,7 @@ class Index extends React.Component {
></OgHead>
<div className={classes.container}>
<VideoSlider />
{/* <VideoSlider /> */}
<section className={classes.scrollerSection + ' ' + classes.scrollerSectionOffer}>
<div
@@ -189,11 +191,11 @@ class Index extends React.Component {
</Typography>
</div>
{this.state.emphasisAds.loading ?
{this.state.emphasisJobs.loading ?
(<Loader />)
: !isEmpty(this.state.emphasisAds.data) ? (
: !isEmpty(this.state.emphasisJobs.data) ? (
<HorizontalScroller
data={this.state.emphasisAds.data}
data={this.state.emphasisJobs.data}
className={classes.HorizontalScroller}
type="offre"
>
@@ -263,7 +265,7 @@ class Index extends React.Component {
function mapStateToProps(state) {
return {
emphasisAds: state.emphasisAds,
emphasisJobs: state.emphasisJobs,
emphasisCompanies: state.emphasisCompanies
};
}
@@ -272,4 +274,4 @@ Index.propTypes = {
classes: PropTypes.object.isRequired,
};
export default (connect(mapStateToProps, { fetchEmphasisAdsRequest, fetchEmphasisCompaniesRequest })(withStyles(styles)(Index)));
export default (connect(mapStateToProps, { fetchEmphasisJobsRequest, fetchEmphasisCompaniesRequest })(withStyles(styles)(Index)));
+67 -32
View File
@@ -1,44 +1,79 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import {makeStyles} from '@material-ui/core/styles';
import Layout from "../components/templates/Layout";
import AccountProfile from "../components/organisms/AccountProfile";
import { Typography } from '@material-ui/core';
import Head from 'next/head'
// import AdBlockDetect from 'react-ad-block-detect';
import AdBlockDetect from 'react-ad-block-detect';
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),
root: {
width: '100%'
},
button: {
marginRight: theme.spacing(1)
},
completed: {
display: 'inline-block'
},
instructions: {
marginTop: theme.spacing(1),
marginBottom: theme.spacing(1)
},
information: {
display: 'flex',
flexDirection: 'column',
backgroundColor: theme.palette.primary.main,
color: "#fff",
fontWeight: '700',
fontSize: '1.15em',
fontFamily: 'Roboto',
[
theme
.breakpoints
.up('md')
]: {
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-start',
justifyContent: 'space-around',
backgroundColor: theme.palette.primary.main,
padding: theme.spacing(2, 2)
},
'& a': {
textDecoration: 'none'
},
texteBlanc: {
color: "#fff",
},
},
}));
export default function HorizontalNonLinearStepper() {
const classes = useStyles();
const classes = useStyles();
return (
<Layout>
<Head>
<title key="title">Profile Talents Tube</title>
<meta key="robots" name="robots" content="noindex, nofollow"></meta>
</Head>
<div >
<AccountProfile />
</div>
{/* <AdBlockDetect>
<p>AdBlocks a été détecté. Pour que Talents Tube puisse fonctionner correctement, veuillez désactiver Ad Blocks</p>
</AdBlockDetect> */}
</Layout>
);
return (
<Layout>
<Head>
<title key="title">Profil Talents Tube</title>
<meta key="robots" name="robots" content="noindex, nofollow"></meta>
</Head>
<div >
<AdBlockDetect >
<div className={classes.information}>
<p>AdBlocks a été détecté. Pour que Talents Tube puisse fonctionner
correctement, veuillez désactiver Ad Blocks</p>
</div>
</AdBlockDetect>
</div>
<div >
<AccountProfile/>
</div>
</Layout>
);
}
+164
View File
@@ -0,0 +1,164 @@
import React from 'react';
import TextField from '@material-ui/core/TextField';
import Autocomplete from '@material-ui/lab/Autocomplete';
import LocationOnIcon from '@material-ui/icons/LocationOn';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import parse from 'autosuggest-highlight/parse';
import throttle from 'lodash/throttle';
function loadScript(src, position, id) {
if (!position) {
return;
}
const script = document.createElement('script');
script.setAttribute('async', '');
script.setAttribute('id', id);
script.src = src;
position.appendChild(script);
}
const autocompleteService = { current: null };
const useStyles = makeStyles((theme) => ({
icon: {
color: theme.palette.text.secondary,
marginRight: theme.spacing(2),
},
}));
export default function GoogleMaps() {
const classes = useStyles();
const [value, setValue] = React.useState(null);
const [inputValue, setInputValue] = React.useState('');
const [options, setOptions] = React.useState([]);
const loaded = React.useRef(false);
if (typeof window !== 'undefined' && !loaded.current) {
if (!document.querySelector('#google-maps')) {
loadScript(
'https://maps.googleapis.com/maps/api/js?key=AIzaSyDYV8IJGtIoWLfXJQQvIuDQ88n2aEuRgpg&libraries=places',
document.querySelector('head'),
'google-maps',
);
}
loaded.current = true;
}
const fetch = React.useMemo(
() =>
throttle((request, callback) => {
autocompleteService.current.getPlacePredictions(request, callback);
}, 200),
[],
);
React.useEffect(() => {
let active = true;
if (!autocompleteService.current && window.google) {
autocompleteService.current = new window.google.maps.places.AutocompleteService();
// console.log('autocompleteService.current');
// console.log(autocompleteService.current);
}
if (!autocompleteService.current) {
return undefined;
}
if (inputValue === '') {
setOptions(value ? [value] : []);
return undefined;
}
fetch({ input: inputValue }, (results) => {
if (active) {
let newOptions = [];
if (value) {
newOptions = [value];
}
if (results) {
newOptions = [...newOptions, ...results];
}
setOptions(newOptions);
}
});
return () => {
active = false;
};
}, [value, inputValue, fetch]);
return (
<Autocomplete
id="google-map-demo"
style={{ width: 300 }}
getOptionLabel={(option) => (typeof option === 'string' ? option : option.description)}
filterOptions={(x) => x}
options={options}
autoComplete
includeInputInList
filterSelectedOptions
value={value}
onChange={(event, newValue) => {
setOptions(newValue ? [newValue, ...options] : options);
setValue(newValue);
console.log("newValue");
// console.log(newValue);
console.log(newValue.description)
let geocoder = new google.maps.Geocoder();
let addresses = {};
geocoder.geocode({ 'address': newValue.description }, function(results, status) {
results.map((index, value) => [
console.log(index.geometry.location.lat()+" "+index.geometry.location.lng())
]);
});
}}
onInputChange={(event, newInputValue) => {
setInputValue(newInputValue);
console.log('newInputValue');
console.log(newInputValue);
}}
renderInput={(params) => (
<TextField {...params} label="Tapez une adresse" variant="outlined" fullWidth />
)}
renderOption={(option) => {
// console.log('option');
// console.log(option);
const matches = option.structured_formatting.main_text_matched_substrings;
const parts = parse(
option.structured_formatting.main_text,
matches.map((match) => [match.offset, match.offset + match.length]),
);
return (
<Grid container alignItems="center">
<Grid item>
<LocationOnIcon className={classes.icon} />
</Grid>
<Grid item xs>
{parts.map((part, index) => (
<span key={index} style={{ fontWeight: part.highlight ? 700 : 400 }}>
{part.text}
</span>
))}
<Typography variant="body2" color="textSecondary">
{option.structured_formatting.secondary_text}
</Typography>
</Grid>
</Grid>
);
}}
/>
);
}
+92
View File
@@ -0,0 +1,92 @@
// server.autosuggest.js
import React from 'react';
import Autosuggest from 'react-autosuggest';
// import './autosuggest.css';
class ServerAutoSuggest extends React.Component {
constructor() {
super();
//Define state for value and suggestion collection
this.state = {
value: '',
suggestions: []
};
}
// Filter logic
getSuggestions = async (value) => {
const inputValue = value.trim().toLowerCase();
let response = await fetch("http://www.omdbapi.com/?s=" + inputValue + "&apikey=a591bb53");
let data = await response.json()
return data;
};
// Trigger suggestions
getSuggestionValue = suggestion => suggestion.Title;
// Render Each Option
renderSuggestion = suggestion => (
<span className="sugg-option">
<span className="icon-wrap"><img src={suggestion.Poster} /></span>
<span className="name">
{suggestion.Title}
</span>
</span>
);
// OnChange event handler
onChange = (event, { newValue }) => {
this.setState({
value: newValue
});
};
// Suggestion rerender when user types
onSuggestionsFetchRequested = ({ value }) => {
this.getSuggestions(value)
.then(data => {
if (data.Error) {
this.setState({
suggestions: []
});
} else {
this.setState({
suggestions: data.Search
});
}
})
};
// Triggered on clear
onSuggestionsClearRequested = () => {
this.setState({
suggestions: []
});
};
render() {
const { value, suggestions } = this.state;
// Option props
const inputProps = {
placeholder: 'Type movie name',
value,
onChange: this.onChange
};
// Adding AutoSuggest component
return (
<Autosuggest
suggestions={suggestions}
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
getSuggestionValue={this.getSuggestionValue}
renderSuggestion={this.renderSuggestion}
inputProps={inputProps}
/>
);
}
}
export default ServerAutoSuggest;
+342
View File
@@ -0,0 +1,342 @@
/* eslint-disable jsx-a11y/anchor-is-valid */
import React, {Fragment} from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Layout from "../components/templates/Layout"
import { Typography } from '@material-ui/core';
import Button from '@material-ui/core/Button';
import Router from 'next/router'
import { connect } from 'react-redux'
import Loader from './../components/templates/loader'
import { isEmpty } from "lodash"
import NoResult from './../components/atoms/NoResult';
import Head from 'next/head'
import dynamic from 'next/dynamic'
import OgHead from '../components/atoms/OgHead';
import getConfig from 'next/config'
import Autosuggest from 'react-autosuggest';
// const VideoSlider = dynamic(() => import('../components/organisms/ShortVideoHooker'), {
// ssr: false
// });
const HorizontalScroller = dynamic(() => import('../components/organisms/HorizontalScroller'), {
ssr: false
});
const TileCompany = dynamic(() => import('../components/organisms/TileCompany'), {
ssr: false
});
const TileOffre = dynamic(() => import('../components/organisms/TileOffre'), {
ssr: false
});
const Footer = dynamic(() => import('../components/organisms/Footer'), {
ssr: false
});
const { publicRuntimeConfig } = getConfig();
const styles = theme => ({
root: {
position: 'relative',
textAlign: 'center',
paddingTop: theme.spacing(20),
justifyContent: 'center',
},
primary: {
color: theme.palette.primary.main,
},
container: {
display: 'flex',
flexDirection: 'column',
},
scrollerSection: {
display: 'flex',
flexDirection: 'column',
paddingBottom: theme.spacing(6),
'&>div': {
paddingBottom: theme.spacing(3),
},
[theme.breakpoints.up('md')]: {
padding: theme.spacing(2, 10),
paddingBottom: theme.spacing(9),
},
[theme.breakpoints.up('lg')]: {
padding: theme.spacing(2, 30),
paddingBottom: theme.spacing(9),
},
[theme.breakpoints.up('xl')]: {
padding: theme.spacing(2, 55),
},
},
scrollerSectionOffer: {
backgroundColor: theme.palette.secondary.main,
},
scrollerSectionCompany: {
backgroundColor: theme.palette.background.grey,
},
card: {
margin: theme.spacing(1),
width: '96%',
height: '100%',
maxWidth: '640px',
maxheight: '360px',
},
HorizontalScroller: {
marginTop: theme.spacing(1),
marginBottom: theme.spacing(4),
},
paper: {
margin: theme.spacing(1),
width: '96%',
height: '100%',
},
media: {
},
svg: {
width: 100,
height: 100,
},
polygon: {
fill: theme.palette.common.white,
stroke: theme.palette.divider,
strokeWidth: 4,
},
img: {
maxWidth: '100%',
},
titleContainer: {
marginTop: theme.spacing(4),
marginBottom: theme.spacing(3),
},
beforeTitle: {
fontSize: '0.8em',
fontWeight: '300',
textAlign: 'center',
textTransform: 'uppercase',
color: theme.palette.secondary.text,
},
title: {
fontFamily: 'Dosis',
fontSize: '1.5em',
fontWeight: '600',
textAlign: 'center',
},
white: {
color: theme.palette.common.white
},
button: {
textTransform: 'inherit',
margin: theme.spacing(0, 8),
padding: theme.spacing(1.2, 2),
[theme.breakpoints.up('sm')]: {
margin: 'auto',
},
},
});
class Index extends React.Component {
constructor() {
super();
//Define state for value and suggestion collection
this.state = {
value: '',
suggestions: [],
valueMetier: '',
suggestionsMetier: [],
};
}
componentDidMount() {
localStorage.setItem("loginRedirect", "/")
}
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
})
}
// Filter logic
getSuggestions = async (value) => {
const inputValue = value.trim().toLowerCase();
let response = await fetch(publicRuntimeConfig.symphonyUrl+"/api/getCompetences?q=" + inputValue );
// let response = await fetch("http://www.omdbapi.com/?s=" + inputValue + "&apikey=a591bb53");
let data = await response.json()
return data;
};
// Trigger suggestions
getSuggestionValue = suggestion => suggestion.libelle;
// Render Each Option
renderSuggestion = suggestion => (
<span className="sugg-option">
<span className="name">
{suggestion.libelle} ({suggestion.code})
</span>
</span>
);
// OnChange event handler
onChange = (event, { newValue }) => {
this.setState({
value: newValue
});
};
// Suggestion rerender when user types
onSuggestionsFetchRequested = ({ value }) => {
this.getSuggestions(value)
.then(data => {
if (data.Error) {
this.setState({
suggestions: []
});
} else {
this.setState({
suggestions: data
});
}
})
};
// Triggered on clear
onSuggestionsClearRequested = () => {
this.setState({
suggestions: []
});
};
// METIER
// Filter logic
getSuggestionsMetier = async (valueMetier) => {
const inputValue = valueMetier.trim().toLowerCase();
let response = await fetch(publicRuntimeConfig.symphonyUrl+"api/getAppelationsLibelle?q=" + inputValue );
// let response = await fetch("http://www.omdbapi.com/?s=" + inputValue + "&apikey=a591bb53");
let data = await response.json()
return data;
};
// Trigger suggestions
getSuggestionMetierValue = suggestion => suggestion.libelle;
// Render Each Option
renderSuggestionMetier = suggestion => (
<span className="sugg-option">
<span className="name">
{suggestion.libelle} ({suggestion.code})
</span>
</span>
);
// OnChange event handler
onChangeMetier = (event, { newValue }) => {
this.setState({
valueMetier: newValue
});
};
// Suggestion rerender when user types
onSuggestionsMetierFetchRequested = ({ value }) => {
this.getSuggestionsMetier(value)
.then(data => {
if (data.Error) {
this.setState({
suggestionsMetier: []
});
} else {
this.setState({
suggestionsMetier: data
});
}
})
};
// Triggered on clear
onSuggestionsMetierClearRequested = () => {
this.setState({
suggestionsMetier: []
});
};
render() {
const { classes } = this.props;
const { value, suggestions, valueMetier, suggestionsMetier } = this.state;
// Option props
const inputProps = {
placeholder: 'Saisir une compétence',
value,
onChange: this.onChange
};
const inputPropsMetier = {
placeholder: 'Saisir un métier',
value:valueMetier,
onChange: this.onChangeMetier
};
const socialShareUrl = typeof window !== 'undefined' ? window.location
: publicRuntimeConfig.frontServerUrl ;
const DefaultUrl = publicRuntimeConfig.symphonyUrl + "/img/default_picture_svg"
const imgUrl = DefaultUrl
return (
<Layout>
<OgHead seo_title="Talents Tube - Plateforme de recrutement en vidéo"
seo_description="Talents Tube est la première plateforme réservée aux offres d'emploi vidéo, vidéo marque employeur et aux CV vidéos. Découvrez une nouvelle méthode de recrutement."
seo_url={socialShareUrl}
image={imgUrl}
seo_key="Recrutement, video"
></OgHead>
<div className={classes.container}>
{/* <VideoSlider /> */}
<section className={classes.scrollerSection + ' ' + classes.scrollerSectionOffer}>
<Autosuggest
suggestions={suggestions}
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
getSuggestionValue={this.getSuggestionValue}
renderSuggestion={this.renderSuggestion}
inputProps={inputProps}
/>
<Autosuggest
suggestions={suggestionsMetier}
onSuggestionsFetchRequested={this.onSuggestionsMetierFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsMetierClearRequested}
getSuggestionValue={this.getSuggestionMetierValue}
renderSuggestion={this.renderSuggestionMetier}
inputProps={inputPropsMetier}
/>
</section>
<Footer />
</div>
</Layout>
);
}
}
function mapStateToProps(state) {
return {
};
}
Index.propTypes = {
classes: PropTypes.object.isRequired,
};
export default (connect(mapStateToProps, { })(withStyles(styles)(Index)));
@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="61.875" height="67.637" viewBox="0 0 61.875 67.637">
<g id="capture" transform="translate(-3.819 12.637)">
<path id="Tracé_267" data-name="Tracé 267" d="M249.806,254.569H236.819A3.831,3.831,0,0,1,233,250.75v-9.931A3.831,3.831,0,0,1,236.819,237h12.986a3.831,3.831,0,0,1,3.819,3.819v9.931A3.831,3.831,0,0,1,249.806,254.569Z" transform="translate(-206.646 -214.465)" fill="#25d89a"/>
<path id="Tracé_268" data-name="Tracé 268" d="M235.875,281.75,229,288.625l-48.125-6.875L174,274.875,180.875,268h55Z" transform="translate(-170.181 -233.625)" fill="#d0e7fe"/>
<rect id="Rectangle_315" data-name="Rectangle 315" width="55" height="13.75" transform="translate(3.819 41.25)" fill="#fff"/>
<circle id="Ellipse_117" data-name="Ellipse 117" cx="6.875" cy="6.875" r="6.875" transform="translate(29.792 6.875)" fill="#25d89a"/>
<text id="_" data-name="?" transform="matrix(0.921, 0.391, -0.391, 0.921, 45.851, 8.063)" fill="#ff5a5f" font-size="11" font-family="Roboto-Black, Roboto" font-weight="800"><tspan x="-2.801" y="0">?</tspan></text>
<text id="_2" data-name="?" transform="translate(39.881 3.168) rotate(-20)" fill="#ff5a5f" font-size="16" font-family="Roboto-Black, Roboto" font-weight="800"><tspan x="-4.074" y="0">?</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
<g id="Groupe_8166" data-name="Groupe 8166" transform="translate(-928 -199.541)">
<circle id="Ellipse_130" data-name="Ellipse 130" cx="50" cy="50" r="50" transform="translate(928 199.541)" fill="#1689fb"/>
<g id="XMLID_1840_" transform="translate(951.228 222.333)">
<g id="XMLID_1021_" transform="translate(0)">
<path id="XMLID_1068_" d="M51.417,65.633a1.045,1.045,0,0,0-.432-1.413,16.381,16.381,0,0,0-18.064,1.8l-1.688-1.688,2.756-2.756A1.045,1.045,0,0,0,32.512,60.1l-2.756,2.756-6.725-6.725a14.6,14.6,0,0,0,1.186-15.582,1.045,1.045,0,1,0-1.845.98,12.44,12.44,0,0,1-.836,13.107L17.1,50.208a2.563,2.563,0,0,0-4.219.93L.16,85.851a2.568,2.568,0,0,0,2.4,3.449,2.592,2.592,0,0,0,.893-.16L38.162,76.415a2.563,2.563,0,0,0,.93-4.219L34.407,67.51A14.289,14.289,0,0,1,50,66.065a1.045,1.045,0,0,0,1.413-.432ZM16.637,82.081,7.219,72.663l2.609-7.119L23.755,79.471Zm-5.1,1.871L5.348,77.767l1.079-2.942,8.048,8.048Zm-8.8,3.227a.474.474,0,0,1-.609-.608l2.434-6.641L9.37,84.744ZM37.743,74.111a.462.462,0,0,1-.3.343l-6.421,2.354-5.941-5.941A1.045,1.045,0,1,0,23.6,72.344L28.86,77.6l-2.942,1.079-15.3-15.3L11.7,60.44,16.956,65.7a1.044,1.044,0,1,0,1.477-1.477l-5.941-5.941,2.354-6.421a.462.462,0,0,1,.343-.3.5.5,0,0,1,.108-.012.454.454,0,0,1,.329.14L37.615,73.673a.462.462,0,0,1,.128.438Z" transform="translate(0 -35.82)" fill="#fff"/>
<path id="XMLID_1441_" d="M292.642,16.779a1.044,1.044,0,0,0,1.045-1.045,1.588,1.588,0,0,1,1.587-1.586,3.68,3.68,0,0,0,3.675-3.675,1.045,1.045,0,0,0-2.089,0,1.588,1.588,0,0,1-1.586,1.586,3.68,3.68,0,0,0-3.676,3.675A1.045,1.045,0,0,0,292.642,16.779Z" transform="translate(-261.139 -8.443)" fill="#fff"/>
<path id="XMLID_1462_" d="M381.363,109.1a3.8,3.8,0,0,0,3.8-3.8,1.709,1.709,0,0,1,1.707-1.707,1.045,1.045,0,0,0,0-2.089,3.8,3.8,0,0,0-3.8,3.8,1.709,1.709,0,0,1-1.707,1.707,1.045,1.045,0,1,0,0,2.089Z" transform="translate(-340.594 -90.91)" fill="#fff"/>
<path id="XMLID_1489_" d="M448,164.827a3.342,3.342,0,1,0,3.342-3.342A3.346,3.346,0,0,0,448,164.827Zm3.342-1.253a1.253,1.253,0,1,1-1.253,1.253A1.255,1.255,0,0,1,451.345,163.574Z" transform="translate(-401.207 -144.617)" fill="#fff"/>
<path id="XMLID_1502_" d="M286.452,112.539a3.342,3.342,0,1,0-3.342-3.342A3.346,3.346,0,0,0,286.452,112.539Zm0-4.6A1.253,1.253,0,1,1,285.2,109.2,1.255,1.255,0,0,1,286.452,107.943Z" transform="translate(-253.538 -94.797)" fill="#fff"/>
<path id="XMLID_1619_" d="M99.344,6.685A3.342,3.342,0,1,0,96,3.342,3.346,3.346,0,0,0,99.344,6.685Zm0-4.6a1.253,1.253,0,1,1-1.253,1.253A1.255,1.255,0,0,1,99.344,2.089Z" transform="translate(-85.974)" fill="#fff"/>
<path id="XMLID_1620_" d="M437.216,348.435a1.045,1.045,0,1,0-1.477,1.477l.985.985a1.045,1.045,0,1,0,1.477-1.477Z" transform="translate(-389.951 -311.766)" fill="#fff"/>
<path id="XMLID_1659_" d="M484.356,395.575a1.045,1.045,0,1,0-1.477,1.477l.985.985a1.045,1.045,0,0,0,1.477-1.477Z" transform="translate(-432.167 -353.982)" fill="#fff"/>
<path id="XMLID_1690_" d="M483.864,348.435l-.985.985a1.044,1.044,0,1,0,1.477,1.477l.985-.985a1.045,1.045,0,0,0-1.477-1.477Z" transform="translate(-432.167 -311.766)" fill="#fff"/>
<path id="XMLID_1712_" d="M436.724,395.575l-.985.985a1.045,1.045,0,0,0,1.477,1.477l.985-.985a1.045,1.045,0,1,0-1.477-1.477Z" transform="translate(-389.951 -353.982)" fill="#fff"/>
<path id="XMLID_1715_" d="M483.618,3.074a1.041,1.041,0,0,0,.739-.306l.985-.985A1.045,1.045,0,0,0,483.864.306l-.985.985a1.045,1.045,0,0,0,.739,1.783Z" transform="translate(-432.167 0)" fill="#fff"/>
<path id="XMLID_1747_" d="M436.477,50.213a1.041,1.041,0,0,0,.739-.306l.985-.985a1.045,1.045,0,1,0-1.477-1.477l-.985.985a1.045,1.045,0,0,0,.739,1.783Z" transform="translate(-389.95 -42.215)" fill="#fff"/>
<path id="XMLID_1750_" d="M484.356,47.446a1.045,1.045,0,1,0-1.477,1.477l.985.985a1.045,1.045,0,0,0,1.477-1.477Z" transform="translate(-432.167 -42.216)" fill="#fff"/>
<path id="XMLID_1751_" d="M436.723,2.768A1.045,1.045,0,0,0,438.2,1.291l-.985-.985a1.045,1.045,0,0,0-1.477,1.477Z" transform="translate(-389.95 0)" fill="#fff"/>
<path id="XMLID_1755_" d="M192.266,300.78a1.045,1.045,0,1,0,.738.306A1.052,1.052,0,0,0,192.266,300.78Z" transform="translate(-171.247 -269.363)" fill="#fff"/>
<path id="XMLID_1756_" d="M338,193.993l-.757.757a1.045,1.045,0,1,0,1.477,1.477l.757-.757A1.045,1.045,0,0,0,338,193.993Z" transform="translate(-301.745 -173.456)" fill="#fff"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
<g id="Groupe_8166" data-name="Groupe 8166" transform="translate(-928 -199.541)">
<circle id="Ellipse_130" data-name="Ellipse 130" cx="50" cy="50" r="50" transform="translate(928 199.541)" fill="#1689fb"/>
<g id="XMLID_1840_" transform="translate(951.228 222.333)">
<g id="XMLID_1021_" transform="translate(0)">
<path id="XMLID_1068_" d="M51.417,65.633a1.045,1.045,0,0,0-.432-1.413,16.381,16.381,0,0,0-18.064,1.8l-1.688-1.688,2.756-2.756A1.045,1.045,0,0,0,32.512,60.1l-2.756,2.756-6.725-6.725a14.6,14.6,0,0,0,1.186-15.582,1.045,1.045,0,1,0-1.845.98,12.44,12.44,0,0,1-.836,13.107L17.1,50.208a2.563,2.563,0,0,0-4.219.93L.16,85.851a2.568,2.568,0,0,0,2.4,3.449,2.592,2.592,0,0,0,.893-.16L38.162,76.415a2.563,2.563,0,0,0,.93-4.219L34.407,67.51A14.289,14.289,0,0,1,50,66.065a1.045,1.045,0,0,0,1.413-.432ZM16.637,82.081,7.219,72.663l2.609-7.119L23.755,79.471Zm-5.1,1.871L5.348,77.767l1.079-2.942,8.048,8.048Zm-8.8,3.227a.474.474,0,0,1-.609-.608l2.434-6.641L9.37,84.744ZM37.743,74.111a.462.462,0,0,1-.3.343l-6.421,2.354-5.941-5.941A1.045,1.045,0,1,0,23.6,72.344L28.86,77.6l-2.942,1.079-15.3-15.3L11.7,60.44,16.956,65.7a1.044,1.044,0,1,0,1.477-1.477l-5.941-5.941,2.354-6.421a.462.462,0,0,1,.343-.3.5.5,0,0,1,.108-.012.454.454,0,0,1,.329.14L37.615,73.673a.462.462,0,0,1,.128.438Z" transform="translate(0 -35.82)" fill="#fff"/>
<path id="XMLID_1441_" d="M292.642,16.779a1.044,1.044,0,0,0,1.045-1.045,1.588,1.588,0,0,1,1.587-1.586,3.68,3.68,0,0,0,3.675-3.675,1.045,1.045,0,0,0-2.089,0,1.588,1.588,0,0,1-1.586,1.586,3.68,3.68,0,0,0-3.676,3.675A1.045,1.045,0,0,0,292.642,16.779Z" transform="translate(-261.139 -8.443)" fill="#fff"/>
<path id="XMLID_1462_" d="M381.363,109.1a3.8,3.8,0,0,0,3.8-3.8,1.709,1.709,0,0,1,1.707-1.707,1.045,1.045,0,0,0,0-2.089,3.8,3.8,0,0,0-3.8,3.8,1.709,1.709,0,0,1-1.707,1.707,1.045,1.045,0,1,0,0,2.089Z" transform="translate(-340.594 -90.91)" fill="#fff"/>
<path id="XMLID_1489_" d="M448,164.827a3.342,3.342,0,1,0,3.342-3.342A3.346,3.346,0,0,0,448,164.827Zm3.342-1.253a1.253,1.253,0,1,1-1.253,1.253A1.255,1.255,0,0,1,451.345,163.574Z" transform="translate(-401.207 -144.617)" fill="#fff"/>
<path id="XMLID_1502_" d="M286.452,112.539a3.342,3.342,0,1,0-3.342-3.342A3.346,3.346,0,0,0,286.452,112.539Zm0-4.6A1.253,1.253,0,1,1,285.2,109.2,1.255,1.255,0,0,1,286.452,107.943Z" transform="translate(-253.538 -94.797)" fill="#fff"/>
<path id="XMLID_1619_" d="M99.344,6.685A3.342,3.342,0,1,0,96,3.342,3.346,3.346,0,0,0,99.344,6.685Zm0-4.6a1.253,1.253,0,1,1-1.253,1.253A1.255,1.255,0,0,1,99.344,2.089Z" transform="translate(-85.974)" fill="#fff"/>
<path id="XMLID_1620_" d="M437.216,348.435a1.045,1.045,0,1,0-1.477,1.477l.985.985a1.045,1.045,0,1,0,1.477-1.477Z" transform="translate(-389.951 -311.766)" fill="#fff"/>
<path id="XMLID_1659_" d="M484.356,395.575a1.045,1.045,0,1,0-1.477,1.477l.985.985a1.045,1.045,0,0,0,1.477-1.477Z" transform="translate(-432.167 -353.982)" fill="#fff"/>
<path id="XMLID_1690_" d="M483.864,348.435l-.985.985a1.044,1.044,0,1,0,1.477,1.477l.985-.985a1.045,1.045,0,0,0-1.477-1.477Z" transform="translate(-432.167 -311.766)" fill="#fff"/>
<path id="XMLID_1712_" d="M436.724,395.575l-.985.985a1.045,1.045,0,0,0,1.477,1.477l.985-.985a1.045,1.045,0,1,0-1.477-1.477Z" transform="translate(-389.951 -353.982)" fill="#fff"/>
<path id="XMLID_1715_" d="M483.618,3.074a1.041,1.041,0,0,0,.739-.306l.985-.985A1.045,1.045,0,0,0,483.864.306l-.985.985a1.045,1.045,0,0,0,.739,1.783Z" transform="translate(-432.167 0)" fill="#fff"/>
<path id="XMLID_1747_" d="M436.477,50.213a1.041,1.041,0,0,0,.739-.306l.985-.985a1.045,1.045,0,1,0-1.477-1.477l-.985.985a1.045,1.045,0,0,0,.739,1.783Z" transform="translate(-389.95 -42.215)" fill="#fff"/>
<path id="XMLID_1750_" d="M484.356,47.446a1.045,1.045,0,1,0-1.477,1.477l.985.985a1.045,1.045,0,0,0,1.477-1.477Z" transform="translate(-432.167 -42.216)" fill="#fff"/>
<path id="XMLID_1751_" d="M436.723,2.768A1.045,1.045,0,0,0,438.2,1.291l-.985-.985a1.045,1.045,0,0,0-1.477,1.477Z" transform="translate(-389.95 0)" fill="#fff"/>
<path id="XMLID_1755_" d="M192.266,300.78a1.045,1.045,0,1,0,.738.306A1.052,1.052,0,0,0,192.266,300.78Z" transform="translate(-171.247 -269.363)" fill="#fff"/>
<path id="XMLID_1756_" d="M338,193.993l-.757.757a1.045,1.045,0,1,0,1.477,1.477l.757-.757A1.045,1.045,0,0,0,338,193.993Z" transform="translate(-301.745 -173.456)" fill="#fff"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

@@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
<g id="Groupe_8216" data-name="Groupe 8216" transform="translate(-907 -178)">
<g id="Groupe_8166" data-name="Groupe 8166" transform="translate(-21 -21.541)">
<circle id="Ellipse_130" data-name="Ellipse 130" cx="50" cy="50" r="50" transform="translate(928 199.541)" fill="#1689fb"/>
<g id="Groupe_8190" data-name="Groupe 8190" transform="translate(950.061 230.494)">
<g id="_001-mail" data-name="001-mail" transform="translate(0 0)">
<g id="Groupe_8165" data-name="Groupe 8165">
<path id="Tracé_428" data-name="Tracé 428" d="M50.345,76H4.851A4.858,4.858,0,0,0,0,80.851v29.107a4.859,4.859,0,0,0,4.851,4.851H50.345a4.857,4.857,0,0,0,4.851-4.851V80.851A4.856,4.856,0,0,0,50.345,76Zm-.679,3.234L31.028,97.773a4.851,4.851,0,0,1-6.864,0L5.531,79.234ZM3.234,109.3V81.512l13.976,13.9Zm2.3,2.275L19.5,97.694l2.378,2.366a8.085,8.085,0,0,0,11.431,0l2.381-2.369,13.97,13.881ZM51.962,109.3,37.986,95.413l13.976-13.9Z" transform="translate(0 -76)" fill="#fff"/>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
<g id="Groupe_8222" data-name="Groupe 8222" transform="translate(-905 -178)">
<g id="Groupe_8166" data-name="Groupe 8166" transform="translate(-23 -21.541)">
<circle id="Ellipse_130" data-name="Ellipse 130" cx="50" cy="50" r="50" transform="translate(928 199.541)" fill="#1689fb"/>
<g id="_001-like" data-name="001-like" transform="translate(948.325 227.541)">
<path id="Tracé_429" data-name="Tracé 429" d="M52.8,33.254a6.076,6.076,0,0,0,1.422-4.061,6.239,6.239,0,0,0-1.33-3.519,5.467,5.467,0,0,0-1.3-6.291C49.963,17.9,47.2,17.235,43.376,17.42a32.1,32.1,0,0,0-5.033.644h-.01c-.511.092-1.054.2-1.606.327-.041-.655.072-2.281,1.279-5.943,1.432-4.357,1.35-7.692-.266-9.922A6.5,6.5,0,0,0,32.533,0a2.569,2.569,0,0,0-1.974.9c-1.135,1.32-1,3.754-.859,4.879-1.35,3.621-5.135,12.5-8.336,14.965a1.1,1.1,0,0,0-.164.143,10.988,10.988,0,0,0-2,3.007,4.221,4.221,0,0,0-2.025-.511H10.93a4.258,4.258,0,0,0-4.255,4.255V44.26a4.258,4.258,0,0,0,4.255,4.255h6.24a4.246,4.246,0,0,0,2.455-.777l2.4.286a102.986,102.986,0,0,0,13.635.747c1.217.092,2.363.143,3.427.143a22.95,22.95,0,0,0,4.756-.43c3.13-.665,5.268-1.995,6.352-3.948a6.261,6.261,0,0,0,.7-3.918,6.524,6.524,0,0,0,2.322-5.309A6.91,6.91,0,0,0,52.8,33.254ZM10.93,45.753A1.5,1.5,0,0,1,9.437,44.26V27.628a1.5,1.5,0,0,1,1.493-1.493h6.24a1.5,1.5,0,0,1,1.493,1.493V44.25a1.5,1.5,0,0,1-1.493,1.493H10.93Zm39.248-13.7a1.375,1.375,0,0,0-.184,1.667,4.256,4.256,0,0,1,.471,1.708,4.093,4.093,0,0,1-1.923,3.539,1.394,1.394,0,0,0-.471,1.575,3.612,3.612,0,0,1-.276,2.639c-.685,1.227-2.209,2.107-4.521,2.6a26.947,26.947,0,0,1-7.457.225h-.143a100.965,100.965,0,0,1-13.3-.726h-.01l-1.033-.123a4.334,4.334,0,0,0,.092-.9V27.628a4.327,4.327,0,0,0-.194-1.268,8.549,8.549,0,0,1,1.9-3.508C27.726,19.21,32.216,6.925,32.41,6.393a1.3,1.3,0,0,0,.061-.685A6.392,6.392,0,0,1,32.6,2.741a3.67,3.67,0,0,1,2.885,1.381c1.043,1.442,1,4.02-.123,7.436-1.718,5.206-1.862,7.948-.5,9.155a2.229,2.229,0,0,0,2.23.4c.624-.143,1.217-.266,1.78-.358l.133-.031c3.14-.685,8.766-1.1,10.72.675a2.943,2.943,0,0,1,.348,3.733,1.368,1.368,0,0,0,.245,1.78A3.875,3.875,0,0,1,51.456,29.3,3.8,3.8,0,0,1,50.178,32.057Z" transform="translate(-1 -4)" fill="#fff"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

@@ -0,0 +1,39 @@
<svg id="web-rtc-active" xmlns="http://www.w3.org/2000/svg" width="550" height="310" viewBox="0 0 550 310">
<g id="web-rtc-record">
<rect id="captures__2020-12-08_à_14.00.50" data-name="captures_ 2020-12-08 à 14.00.50" width="550" height="310" fill="#4b4f52"/>
<g id="Groupe_8235" data-name="Groupe 8235" transform="translate(-121 -1)">
<g id="Groupe_8239" data-name="Groupe 8239" transform="translate(-226 7)">
<g id="Groupe_8236" data-name="Groupe 8236" transform="translate(-20 20)">
<circle id="Ellipse_146" data-name="Ellipse 146" cx="14" cy="14" r="14" transform="translate(407 48)" fill="#25d89a"/>
<text id="_1" data-name="1" transform="translate(421 67)" fill="#fff" font-size="15" font-family="Roboto-Bold, Roboto" font-weight="700"><tspan x="-4.303" y="0">1</tspan></text>
</g>
<text id="Autoriser_la_caméra_et_le_micro" data-name="Autoriser la caméra et le micro" transform="translate(427 88)" fill="#fff" font-size="14" font-family="Roboto-Bold, Roboto" font-weight="700"><tspan x="0" y="0">Autoriser la caméra et le micro</tspan></text>
<text id="Choisir_votre_meilleure_prise" data-name="Choisir votre meilleure prise" transform="translate(427 204)" fill="#fff" font-size="14" font-family="Roboto-Bold, Roboto" font-weight="700"><tspan x="0" y="0">Choisir votre meilleure prise</tspan></text>
<text id="Démarrer_l_enregistrement" data-name="Démarrer lenregistrement" transform="translate(427 146)" fill="#fff" font-size="14" font-family="Roboto-Bold, Roboto" font-weight="700"><tspan x="0" y="0">Démarrer lenregistrement</tspan></text>
<g id="Groupe_8237" data-name="Groupe 8237" transform="translate(-20 78)">
<circle id="Ellipse_146-2" data-name="Ellipse 146" cx="14" cy="14" r="14" transform="translate(407 48)" fill="#25d89a"/>
<text id="_2" data-name="2" transform="translate(421 67)" fill="#fff" font-size="15" font-family="Roboto-Bold, Roboto" font-weight="700"><tspan x="-4.303" y="0">2</tspan></text>
</g>
<g id="Groupe_8238" data-name="Groupe 8238" transform="translate(-20 136)">
<circle id="Ellipse_146-3" data-name="Ellipse 146" cx="14" cy="14" r="14" transform="translate(407 48)" fill="#25d89a"/>
<text id="_3" data-name="3" transform="translate(421 67)" fill="#fff" font-size="15" font-family="Roboto-Bold, Roboto" font-weight="700"><tspan x="-4.303" y="0">3</tspan></text>
</g>
</g>
<g id="Groupe_8240" data-name="Groupe 8240" transform="translate(-36)">
<rect id="Rectangle_442" data-name="Rectangle 442" width="187" height="187" rx="9" transform="translate(480 53)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" stroke-dasharray="9" opacity="0.593"/>
<circle id="Ellipse_145" data-name="Ellipse 145" cx="7" cy="7" r="7" transform="translate(642 65)" fill="#fd6161"/>
<g id="_001-woman" data-name="001-woman" transform="translate(449.002 56.984)">
<path id="Tracé_448" data-name="Tracé 448" d="M175.073,136.325v12.8a2.607,2.607,0,0,1-2.608,2.608H77.285a2.607,2.607,0,0,1-2.608-2.608v-12.8a24.317,24.317,0,0,1,14.264-22.143c-3.433-2.731,1.856-10.366-1.95-18.264-5.3-10.984-3.064-14.173,3.69-24.316,3.67-5.509,3.137-13.027,3.137-19.644l6.381-7.925c0-18-2.164-27.367,15.839-27.367L134.023,17.9c18,0,21.388-.527,21.388,17.476,0,14.957-.157,17.695,1.646,23.643,2.544,8.41-4.236,15.545-1.646,24.1,4.072,13.454,4.5,10.7-6.6,19.537l11.994,11.525A24.317,24.317,0,0,1,175.073,136.325Z" transform="translate(-0.049 16.831)" fill="#ffdfba"/>
<path id="Tracé_449" data-name="Tracé 449" d="M178.4,363.976v12.8a2.608,2.608,0,0,1-2.608,2.608H80.609A2.608,2.608,0,0,1,78,376.773v-12.8a24.308,24.308,0,0,1,24.307-24.307,13.489,13.489,0,0,0,5.6-1.209l.081.176,18.613,14.41a2.608,2.608,0,0,0,3.193,0l18.613-14.41.081-.176a13.489,13.489,0,0,0,5.6,1.209A24.308,24.308,0,0,1,178.4,363.976Z" transform="translate(-3.373 -210.82)" fill="#44a0fb"/>
<path id="Tracé_450" data-name="Tracé 450" d="M195.073,122.56a2.609,2.609,0,0,1,2.468,2.6v15.609a32.27,32.27,0,1,1-64.54,0V125.39a2.6,2.6,0,0,1,2.831-2.6,67.467,67.467,0,0,0,43.98-11.245A2.6,2.6,0,0,1,183.773,113C185.382,118.932,189.77,122.258,195.073,122.56Z" transform="translate(-40.445 -57.57)" fill="#ffebd2"/>
<path id="Tracé_451" data-name="Tracé 451" d="M163.653,111.4l-2.888,2.3a24.246,24.246,0,0,0-10.043-2.164,13.485,13.485,0,0,1-13.5-13.475V95.833l-.049-.121A32.274,32.274,0,0,0,157.1,65.887V50.278a2.609,2.609,0,0,0-2.468-2.6c-5.27-.3-9.681-3.59-11.3-9.558a2.6,2.6,0,0,0-3.961-1.455,67.47,67.47,0,0,1-43.98,11.245,2.6,2.6,0,0,0-2.831,2.6V65.887a32.274,32.274,0,0,0,19.933,29.825l-.049.121v2.226a13.485,13.485,0,0,1-13.5,13.475A24.246,24.246,0,0,0,88.9,113.7l-2.888-2.3a34.486,34.486,0,0,1-7.223-46.088A33.526,33.526,0,0,0,84.412,46.72V32.6A32.6,32.6,0,0,1,117.008,0h15.646a32.6,32.6,0,0,1,32.6,32.6V46.72a33.545,33.545,0,0,0,5.626,18.593A34.486,34.486,0,0,1,163.653,111.4Z" transform="translate(-0.005 17.315)" fill="#42434d"/>
<path id="Tracé_452" data-name="Tracé 452" d="M218.381,299.1a32.358,32.358,0,0,1-25.51,0,20.2,20.2,0,0,0,.368-5.352l.049-.121a32.336,32.336,0,0,0,24.675,0l.049.121A20.194,20.194,0,0,0,218.381,299.1Z" transform="translate(-80.8 -180.603)" fill="#ffd6a6"/>
<path id="Tracé_453" data-name="Tracé 453" d="M147.376,3.508a3.4,3.4,0,0,1-1.834,6.418q-1.537-.146-3.113-.147H126.784a32.6,32.6,0,0,0-32.6,32.6v3.966c0,2.342-1.63,2.266-1.63,4.163,0,17.218.07,16.128-.183,16.871-2.557,7.523-5.628,8.611-8.119,16.843A34.457,34.457,0,0,0,82.968,97.8a3.4,3.4,0,0,1-6.545,1.6,34.472,34.472,0,0,1,2.36-34.086A33.526,33.526,0,0,0,84.409,46.72V32.6A32.6,32.6,0,0,1,117,0h15.646a32.458,32.458,0,0,1,14.726,3.508Z" transform="translate(-0.002 17.315)" fill="#4d4e59"/>
<path id="Tracé_454" data-name="Tracé 454" d="M159.085,186.545c4.87,3.26,1.158,10.8-4.371,8.859A32.065,32.065,0,0,1,133,164.927V149.545a2.605,2.605,0,0,1,2.833-2.6c1.249.113,2.621.2,4.1.248a4.968,4.968,0,0,1,4.8,4.974v7.543a32.156,32.156,0,0,0,14.349,26.833Z" transform="translate(-40.445 -81.725)" fill="#fff3e4"/>
<path id="Tracé_455" data-name="Tracé 455" d="M113.365,342.8a2.074,2.074,0,0,1-1.227,3.716A24.3,24.3,0,0,0,87.78,370.821v8.56H80.609A2.608,2.608,0,0,1,78,376.773v-12.8a24.308,24.308,0,0,1,24.307-24.307,13.489,13.489,0,0,0,5.6-1.209l.081.176Z" transform="translate(-3.373 -210.82)" fill="#8ac4fd"/>
<path id="Tracé_456" data-name="Tracé 456" d="M275.835,342.8a2.074,2.074,0,0,0,1.227,3.716,24.3,24.3,0,0,1,24.359,24.307v8.56h7.171a2.608,2.608,0,0,0,2.608-2.608v-12.8a24.308,24.308,0,0,0-24.307-24.307,13.49,13.49,0,0,1-5.6-1.209l-.081.176Z" transform="translate(-136.176 -210.82)" fill="#1689fb"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.7 KiB

+6 -6
View File
@@ -1,26 +1,26 @@
import { createSelector } from "reselect";
import {
FETCH_AD_REQUEST,
FETCH_AD_SUCCESS,
FETCH_AD_FAILURE,
FETCH_JOB_REQUEST,
FETCH_JOB_SUCCESS,
FETCH_JOB_FAILURE,
CLEAR_AD
} from "../types";
export function ad(state = {
}, action = {}) {
switch (action.type) {
case FETCH_AD_REQUEST:
case FETCH_JOB_REQUEST:
return {
...state,
loading:true
};
case FETCH_AD_SUCCESS:
case FETCH_JOB_SUCCESS:
return {
...state,
...action.res,
loading: false
};
case FETCH_AD_FAILURE:
case FETCH_JOB_FAILURE:
return {
...state,
errors: action.error,
+6 -6
View File
@@ -1,8 +1,8 @@
import { createSelector } from "reselect";
import {
FETCH_ADS_SUCCESS,
FETCH_ADS_FAILURE,
FETCH_ADS_REQUEST,
FETCH_JOBS_SUCCESS,
FETCH_JOBS_FAILURE,
FETCH_JOBS_REQUEST,
TOGGLE_PROMOTED_FILTER_ADS,
} from "../types";
@@ -10,18 +10,18 @@ export function ads(state = {
}, action = {}) {
switch (action.type) {
case FETCH_ADS_REQUEST:
case FETCH_JOBS_REQUEST:
return {
...state,
loading:true
};
case FETCH_ADS_SUCCESS:
case FETCH_JOBS_SUCCESS:
return {
...state,
...action.res,
loading:false
};
case FETCH_ADS_FAILURE:
case FETCH_JOBS_FAILURE:
return {
...state,
errors: action.error,
+6 -6
View File
@@ -1,25 +1,25 @@
import { createSelector } from "reselect";
import {
FETCH_ADS_ANSWER_REQUEST,
FETCH_ADS_ANSWER_SUCCESS,
FETCH_ADS_ANSWER_FAILURE,
FETCH_JOBS_ANSWER_REQUEST,
FETCH_JOBS_ANSWER_SUCCESS,
FETCH_JOBS_ANSWER_FAILURE,
} from "../types";
export function answers(state = {
}, action = {}) {
switch (action.type) {
case FETCH_ADS_ANSWER_REQUEST:
case FETCH_JOBS_ANSWER_REQUEST:
return {
...state,
loading: true
};
case FETCH_ADS_ANSWER_SUCCESS:
case FETCH_JOBS_ANSWER_SUCCESS:
return {
...state,
...action.res,
loading: false
};
case FETCH_ADS_ANSWER_FAILURE:
case FETCH_JOBS_ANSWER_FAILURE:
return {
...state,
errors: action.error,
@@ -1,27 +1,27 @@
import { createSelector } from "reselect";
import {
FETCH_EMPHASIS_ADS_SUCCESS,
FETCH_EMPHASIS_ADS_FAILURE,
FETCH_EMPHASIS_ADS_REQUEST,
FETCH_EMPHASIS_JOBS_SUCCESS,
FETCH_EMPHASIS_JOBS_FAILURE,
FETCH_EMPHASIS_JOBS_REQUEST,
} from "../types";
export function emphasisAds(state = {
export function emphasisJobs(state = {
}, action = {}) {
switch (action.type) {
case FETCH_EMPHASIS_ADS_REQUEST:
case FETCH_EMPHASIS_JOBS_REQUEST:
return {
...state,
loading:true
};
case FETCH_EMPHASIS_ADS_SUCCESS:
case FETCH_EMPHASIS_JOBS_SUCCESS:
return {
...action.res,
loading:false
};
case FETCH_EMPHASIS_ADS_FAILURE:
case FETCH_EMPHASIS_JOBS_FAILURE:
return {
...state,
errors: action.error,
@@ -34,8 +34,8 @@ export function emphasisAds(state = {
}
export const emphasisAdsHashSelector = state => state.emphasisAds.data;
export const emphasisJobsHashSelector = state => state.emphasisJobs.data;
export const emphasisAdsSelector = createSelector(emphasisAdsHashSelector, hash =>
export const emphasisJobsSelector = createSelector(emphasisJobsHashSelector, hash =>
Object.values(hash)
);
+1 -20
View File
@@ -5,9 +5,6 @@ import {
UPLOAD_MEDIA_PRES_REQUEST,
UPLOAD_MEDIA_PRES_FAILURE,
UPLOAD_MEDIA_PRES_SUCCESS,
UPLOAD_MEDIA_CV_REQUEST,
UPLOAD_MEDIA_CV_FAILURE,
UPLOAD_MEDIA_CV_SUCCESS,
} from "../types";
export function media(state = {
@@ -47,23 +44,7 @@ export function media(state = {
errors: action.errors,
loading: false
};
case UPLOAD_MEDIA_CV_REQUEST:
return {
...state,
loading: true
};
case UPLOAD_MEDIA_CV_SUCCESS:
return {
...state,
...action.res.data,
loading: false
};
case UPLOAD_MEDIA_CV_FAILURE:
return {
...state,
errors: action.errors,
loading: false
};
default:
return state;
}
+43
View File
@@ -0,0 +1,43 @@
import {
UPLOAD_MEDIA_CV_REQUEST,
UPLOAD_MEDIA_CV_FAILURE,
UPLOAD_MEDIA_CV_SUCCESS,
} from "../types";
export function mediaCv(state = {
}, action = {}) {
switch (action.type) {
case UPLOAD_MEDIA_CV_REQUEST:
return {
...state,
loading: true
};
case UPLOAD_MEDIA_CV_SUCCESS:
return {
...state,
...action.res.data,
loading: false
};
case UPLOAD_MEDIA_CV_FAILURE:
return {
...state,
errors: action.errors,
loading: false
};
default:
return state;
}
}
export const mediaCvErrorsSelector = state => {return !!state.mediaCv.errors ?state.mediaCv.errors.response.data:null};
export const errorMessageSelector = (state) => {
let err = mediaCvErrorsSelector(state)
if (!!!err)
return null;
switch(err.code)
{
case 500:
return {message: "Le téléversement de votre video à échoué."}
}
}
+9 -4
View File
@@ -3,13 +3,14 @@ import { combineReducers } from "redux";
import { user } from "./reducers/user";
import { ad } from "./reducers/ad";
import { ads } from "./reducers/ads";
import { emphasisAds } from "./reducers/emphasisAds";
import { emphasisJobs } from "./reducers/emphasisJobs";
import { company } from "./reducers/company";
import { companies } from "./reducers/companies";
import { emphasisCompanies } from "./reducers/emphasisCompanies";
import { answer } from "./reducers/answer";
import { answers } from "./reducers/answers";
import { media } from "./reducers/media";
import { mediaCv } from "./reducers/mediaCv";
export const exampleInitialState = {
user: {
@@ -24,8 +25,8 @@ export const exampleInitialState = {
ad: {
},
emphasisAds: {
emphasisJobs: {
},
companies: {
data: {}
@@ -41,6 +42,9 @@ export const exampleInitialState = {
},
media:{
},
mediaCv:{
},
answers:{
data: {}
@@ -50,12 +54,13 @@ export const exampleInitialState = {
export default combineReducers({
user,
ads,
emphasisAds,
emphasisJobs,
ad,
companies,
company,
emphasisCompanies,
answer,
media,
mediaCv,
answers
});
+10 -10
View File
@@ -9,18 +9,18 @@ import {
requestRegisterSaga, requestLogoutSaga, requestNewsletterSubscribitionSaga,
requestUpdateUserRequestSaga, requestUserSubscriptionToPushSaga
} from './sagas/userSaga.js'
import { requestAdsSaga, requestAdSaga, requestEmphasisAdsSaga, countAdViewRequestSaga } from './sagas/offreSaga.js'
import { requestAdsSaga, requestAdSaga, requestEmphasisJobsSaga, countAdViewRequestSaga } from './sagas/offreSaga.js'
import { requestCompaniesSaga, requestCompanySaga, requestEmphasisCompaniesSaga, countCompanyViewRequestSaga } from './sagas/companySaga.js'
import { postAnswerMessageSaga, postAdAnswerRequestSaga, uploadMediaSaga, uploadMediaPresSaga, uploadMediaCvSaga, fetchAdsAnsweredRequestSaga, fetchAnswerRequestSaga, fetchAnswerMessagesRequestSaga } from './sagas/answerSaga.js'
import { postAnswerMessageSaga, postAdAnswerRequestSaga, uploadMediaSaga, uploadMediaPresSaga, uploadMediaCvSaga, fetchJobsAnsweredRequestSaga, fetchAnswerRequestSaga, fetchAnswerMessagesRequestSaga } from './sagas/answerSaga.js'
import {
REQUEST_LOGIN,
REQUEST_LOGOUT,
REQUEST_REGISTER,
FETCH_CURRENT_USER_REQUEST,
FETCH_ADS_REQUEST,
FETCH_AD_REQUEST,
FETCH_EMPHASIS_ADS_REQUEST,
FETCH_JOBS_REQUEST,
FETCH_JOB_REQUEST,
FETCH_EMPHASIS_JOBS_REQUEST,
FETCH_EMPHASIS_COMPANIES_REQUEST,
FETCH_COMPANIES_REQUEST,
FETCH_COMPANY_REQUEST,
@@ -32,7 +32,7 @@ import {
UPLOAD_MEDIA_PRES_REQUEST,
UPLOAD_MEDIA_CV_REQUEST,
UPDATE_USER_REQUEST,
FETCH_ADS_ANSWER_REQUEST,
FETCH_JOBS_ANSWER_REQUEST,
FETCH_ANSWER_REQUEST,
VERIFY_USER_REQUEST,
RESET_PASSWORD_REQUEST,
@@ -57,9 +57,9 @@ function* rootSaga() {
takeLatest(FETCH_CURRENT_USER_REQUEST, requestUserSaga),
takeLatest(UPDATE_USER_REQUEST, requestUpdateUserSaga),
takeLatest(SUBSCRIBE_NEWSLETTER_REQUEST, requestNewsletterSubscribitionSaga),
takeLatest(FETCH_ADS_REQUEST, requestAdsSaga),
takeLatest(FETCH_AD_REQUEST, requestAdSaga),
takeLatest(FETCH_EMPHASIS_ADS_REQUEST, requestEmphasisAdsSaga),
takeLatest(FETCH_JOBS_REQUEST, requestAdsSaga),
takeLatest(FETCH_JOB_REQUEST, requestAdSaga),
takeLatest(FETCH_EMPHASIS_JOBS_REQUEST, requestEmphasisJobsSaga),
takeLatest(FETCH_EMPHASIS_COMPANIES_REQUEST, requestEmphasisCompaniesSaga),
takeLatest(FETCH_COMPANIES_REQUEST, requestCompaniesSaga),
takeLatest(FETCH_COMPANY_REQUEST, requestCompanySaga),
@@ -69,7 +69,7 @@ function* rootSaga() {
takeLatest(UPLOAD_MEDIA_REQUEST, uploadMediaSaga),
takeLatest(UPLOAD_MEDIA_PRES_REQUEST, uploadMediaPresSaga),
takeLatest(UPLOAD_MEDIA_CV_REQUEST, uploadMediaCvSaga),
takeLatest(FETCH_ADS_ANSWER_REQUEST, fetchAdsAnsweredRequestSaga),
takeLatest(FETCH_JOBS_ANSWER_REQUEST, fetchJobsAnsweredRequestSaga),
takeLatest(FETCH_ANSWER_REQUEST, fetchAnswerRequestSaga),
takeLatest(VERIFY_USER_REQUEST, verifyUserSaga),
takeLatest(RESET_PASSWORD_REQUEST, requestResetPasswordSaga),
+29 -16
View File
@@ -8,8 +8,8 @@ import _ from "lodash";
import {
postAdAnswerRequestSuccess,
postAdAnswerRequestFailure,
fetchAdsAnsweredSuccess,
fetchAdsAnsweredFailure,
fetchJobsAnsweredSuccess,
fetchJobsAnsweredFailure,
fetchAnswerSuccess,
fetchAnswerFailure,
postMessageAnswerSuccess,
@@ -26,9 +26,13 @@ import {
uploadMediaFailure,
uploadMediaPresSuccess,
uploadMediaPresFailure,
} from "../actions/media";
import {
uploadMediaCvSuccess,
uploadMediaCvFailure
} from "../actions/media";
} from "../actions/mediaCv";
import AuthRouter from "../pages/AuthRouter";
export function* postAdAnswerRequestSaga(action) {
@@ -38,7 +42,7 @@ export function* postAdAnswerRequestSaga(action) {
if (!!res.data) {
yield put(postAdAnswerRequestSuccess(res));
Router.push("/Candidatures");
Router.push("/CandidatureValidation");
}
else
yield put(postAdAnswerRequestFailure(res));
@@ -46,8 +50,10 @@ export function* postAdAnswerRequestSaga(action) {
} catch (err) {
if (_.includes(err, "401")) {
console.error("401")
console.error(window.location)
localStorage.setItem('loginRedirect', window.location)
console.error(window.location.pathname)
console.log("ERREUR 401")
localStorage.setItem('loginRedirect', window.location.pathname)
console.log("ERREUR 401")
Router.push("/Login");
}
yield put(postAdAnswerRequestFailure(err.response));
@@ -67,7 +73,8 @@ export function* uploadMediaSaga(action) {
} catch (err) {
if (_.includes(err, "401") || err.response.status === 401) {
localStorage.setItem('loginRedirect', window.location)
localStorage.setItem('loginRedirect', window.location.pathname)
console.log("ERREUR 401")
Router.push("/Login");
}
yield put(uploadMediaFailure(err.response));
@@ -87,7 +94,8 @@ export function* uploadMediaPresSaga(action) {
} catch (err) {
if (_.includes(err, "401") || err.response.status === 401) {
localStorage.setItem('loginRedirect', window.location)
localStorage.setItem('loginRedirect', window.location.pathname)
console.log("ERREUR 401")
Router.push("/Login");
}
yield put(uploadMediaPresFailure(err.response));
@@ -97,7 +105,7 @@ export function* uploadMediaPresSaga(action) {
export function* uploadMediaCvSaga(action) {
try {
const res = yield call(api.medias.uploadMediaCv, action.payload);
const res = yield call(api.cv.uploadMediaCv, action.payload);
if (!!res.data)
yield put(uploadMediaCvSuccess(res));
@@ -107,29 +115,31 @@ export function* uploadMediaCvSaga(action) {
} catch (err) {
if (_.includes(err, "401") || err.response.status === 401) {
localStorage.setItem('loginRedirect', window.location)
localStorage.setItem('loginRedirect', window.location.pathname)
console.log("ERREUR 401")
Router.push("/Login");
}
yield put(uploadMediaCvFailure(err.response));
}
}
export function* fetchAdsAnsweredRequestSaga(action) {
export function* fetchJobsAnsweredRequestSaga(action) {
try {
const res = yield call(api.answers.fetchAdsAnswered, action.payload);
const res = yield call(api.answers.fetchJobsAnswered, action.payload);
if (!!res.data)
yield put(fetchAdsAnsweredSuccess(res));
yield put(fetchJobsAnsweredSuccess(res));
else
yield put(fetchAdsAnsweredFailure(res));
yield put(fetchJobsAnsweredFailure(res));
} catch (err) {
if (_.includes(err, "401") || err.response.status === 401) {
localStorage.setItem('loginRedirect', "/Candidatures")
console.log("ERREUR 401")
Router.push("/Login");
}
yield put(fetchAdsAnsweredFailure(err.response));
yield put(fetchJobsAnsweredFailure(err.response));
}
}
// {
@@ -149,6 +159,7 @@ export function* fetchAnswerRequestSaga(action) {
if (_.includes(err, "401") || err.response.status === 401) {
localStorage.setItem('loginRedirect', "/Candidatures")
console.log("ERREUR 401")
Router.push("/Login");
}
yield put(fetchAnswerFailure(err.response));
@@ -171,7 +182,8 @@ export function* postAnswerMessageSaga(action) {
} catch (err) {
if (_.includes(err, "401")) {
localStorage.setItem('loginRedirect', window.location)
localStorage.setItem('loginRedirect', window.location.pathname)
console.log("ERREUR 401")
Router.push("/Login");
}
yield put(postMessageAnswerFailure(err.response));
@@ -191,6 +203,7 @@ export function* fetchAnswerMessagesRequestSaga(action) {
} catch (err) {
if (_.includes(err, "401")) {
localStorage.setItem('loginRedirect', "/Candidatures")
console.log("ERREUR 401")
Router.push("/Login");
}
yield put(fetchAnswerMessagesFailure(err.response));
+16 -16
View File
@@ -1,8 +1,8 @@
import { call, put } from "redux-saga/effects";
import { fetchAdsSuccess, fetchAdsFailure,
fetchAdSuccess, fetchAdFailure,
fetchEmphasisAdsSuccess,fetchEmphasisAdsFailure
import { fetchJobsSuccess, fetchJobsFailure,
fetchJobSuccess, fetchJobFailure,
fetchEmphasisJobsSuccess,fetchEmphasisJobsFailure
} from "../actions/ads";
@@ -18,44 +18,44 @@ export function* countAdViewRequestSaga(action) {
export function* requestAdsSaga(action) {
try {
const res = yield call(api.ads.fetchAds, action.payload);
const res = yield call(api.ads.fetchJobs, action.payload);
if (!!res.data)
yield put(fetchAdsSuccess(res));
yield put(fetchJobsSuccess(res));
else
yield put(fetchAdsFailure(res));
yield put(fetchJobsFailure(res));
} catch (err) {
yield put(fetchAdsFailure(err.response));
yield put(fetchJobsFailure(err.response));
}
}
export function* requestAdSaga(action) {
try {
const res = yield call(api.ads.fetchAd, action.payload);
const res = yield call(api.ads.fetchJob, action.payload);
if (!!res)
yield put(fetchAdSuccess(res));
yield put(fetchJobSuccess(res));
else
yield put(fetchAdFailure(res));
yield put(fetchJobFailure(res));
} catch (err) {
yield put(fetchAdFailure(err.response));
yield put(fetchJobFailure(err.response));
}
}
export function* requestEmphasisAdsSaga(action) {
export function* requestEmphasisJobsSaga(action) {
try {
const res = yield call(api.ads.fetchAds, action.payload);
const res = yield call(api.ads.fetchJobs, action.payload);
if (!!res.data)
yield put(fetchEmphasisAdsSuccess(res));
yield put(fetchEmphasisJobsSuccess(res));
else
yield put(fetchEmphasisAdsFailure(res));
yield put(fetchEmphasisJobsFailure(res));
} catch (err) {
yield put(fetchEmphasisAdsFailure(err.response));
yield put(fetchEmphasisJobsFailure(err.response));
}
}
+23 -11
View File
@@ -23,7 +23,7 @@ import _ from "lodash";
export function* requestLoginSaga(action) {
try {
const res = yield call(api.user.login, action.data);
if (!!res.token) {
localStorage.setItem('ttJWT', res.token)
@@ -36,13 +36,19 @@ export function* requestLoginSaga(action) {
if (!!!url)
url = "/"
Router.push(url);
localStorage.setItem('loginRedirect', '/');
} else
throw new Error("Mauvais identifiants.")
// <Redirect to={url}/>
//localStorage.setItem('loginRedirect', '/');
} else{
throw new Error("Aucun compte n'est associé à cette adresse email. Vérifiez l'e-mail..")
console.log("requestLoginSaga!!!!!!!!!!!!!! Mauvais identifiants.")
}
} catch (error) {
setAuthorizationHeader();
yield put(requestLoginFailure({ message: "Mauvais identifiants." }));
console.log("requestLoginSaga!!!!!!!!!!!!!! Mauvais identifiants.")
yield put(requestLoginFailure({ message: "Email ou mot de passe incorrect" }));
}
}
@@ -112,7 +118,7 @@ export function* requestNewsletterSubscribitionSaga(action) {
} else
console.error(res.data.message);
if (_.startsWith(res.data.message, 'Unsuccessful: 400 MJ18')) {
throw new Error("Existe déjà.")
throw new Error("Cet utilisateur existe déjà.")
}
} catch (err) {
console.error(err.message)
@@ -124,19 +130,24 @@ export function* requestRegisterSaga(action) {
try {
//console.log('function* requestRegisterSaga')
const res = yield call(api.user.register, action.payload);
console.log("requestRegisterSaga");
console.log(res);
console.log(action);
if (res.data.status === 'success') {
yield put(registerUserSuccess(res));
yield put(sendConfirmationEmailRequest(res));
Router.push(`/VerifyEmail/${action.payload.email}`);
} else
throw new Error("L'inscription à échouée. Merci de contacter contact@talentstube.com")
} else{
throw new Error("Il existe déjà un compte Talent associé à cet e-mail ")
}
} catch (err) {
console.error(err)
yield put(registerUserFailure(err));
yield put(registerUserFailure({ err: err, message: err.message }));
}
}
@@ -260,7 +271,8 @@ export function* requestUpdateUserRequestSaga(action) {
} catch (err) {
if (_.includes(err, "401") || (!!err.response && err.response.status === 401)) {
localStorage.setItem('loginRedirect', window.location)
localStorage.setItem('loginRedirect', window.location.pathname)
console.log("ERREUR 401")
Router.push("/Login");
}
yield put(updateUserPictureFailure(err.response));
+110 -9
View File
@@ -17,6 +17,9 @@ const FacebookStrategy = require('passport-facebook').Strategy
const LinkedInStrategy = require('passport-linkedin-oauth2').Strategy
const bodyParser = require('body-parser');
const clePubliqueMailJet = "355697fac93fca865660734b4fdffaeb"
const clePriveMailJet = "ddecf75321ca89c09e561857b13534c8"
passport.use(new FacebookStrategy({
clientID: process.env.NODE_ENV === 'production' ? process.env.TT_FACEBOOK_ID : process.env.FACEBOOK_ID,
clientSecret: process.env.NODE_ENV === 'production' ? process.env.TT_FACEBOOK_SECRET : process.env.FACEBOOK_SECRET,
@@ -163,6 +166,12 @@ app.prepare()
app.render(req, res, actualPage, queryParams)
})
server.get('/Player', (req, res) => {
const actualPage = '/Player'
const queryParams = { id: req.query.id, videoId:req.query.videoId, type:req.query.type }
app.render(req, res, actualPage, queryParams)
})
server.get('/VerifyEmail/:email', (req, res) => {
const actualPage = '/VerifyEmail'
const queryParams = { email: req.params.email }
@@ -175,6 +184,25 @@ app.prepare()
app.render(req, res, actualPage, queryParams)
})
// server.post('/NewsletterSubscription', jsonParser, (req, res) => {
// let email = req.body.email;
// if (!!!email) {
// res.status(404).json({ success: false, message: 'Mauvais paramètre.' });
// }
// var mailjet = require('node-mailjet')
// .connect(process.env.MJ_APIKEY_PUBLIC, process.env.MJ_APIKEY_PRIVATE)
// let error = null;
// let mailjetResponse = mailjet.post('contact')
// .request({ Email: email })
// .then(rep => res.json({ success: true }), rep => res.json({ success: false, message: rep.message }))
// .catch((err) => {
// });
// })
server.post('/NewsletterSubscription', jsonParser, (req, res) => {
let email = req.body.email;
@@ -182,16 +210,86 @@ app.prepare()
if (!!!email) {
res.status(404).json({ success: false, message: 'Mauvais paramètre.' });
}
// var mailjet = require ('node-mailjet')
// .connect(process.env.MJ_APIKEY_PUBLIC, process.env.MJ_APIKEY_PRIVATE)
// mailjet.post('contact')
// .request({Email: email})
// .catch((err)=>console.log(err));
// res.json({success:true});
// })
var mailjet = require('node-mailjet')
.connect(process.env.MJ_APIKEY_PUBLIC, process.env.MJ_APIKEY_PRIVATE)
.connect(clePubliqueMailJet, clePriveMailJet)
let error = null;
let mailjetResponse = mailjet.post('contact')
.request({ Email: email })
.then(rep => res.json({ success: true }), rep => res.json({ success: false, message: rep.message }))
.catch((err) => {
});
console.log("envoi du contact a mailjet")
let mailjetResponse = mailjet
.post('contact')
.action("managemanycontacts")
.request({
"Contacts":[
{
"Email":email,
"IsExcludedFromCampaigns":"false",
"Properties":"object"
}
],
"ContactsLists":[
{
"Action":"addforce",
"ListID":"2400791"
},
]
})
.then(rep => res.json({ success: true }), rep => {
console.log("success")
res.json({ success: false, message: rep.message })
})
.catch((err) => console.log("erreur"));
console.log("Fin envoi du contact a mailjet")
// US technique 444
// var mailjet2 = require('node-mailjet')
// .connect('805b8adce80bc6aa9422ddff20bb4171', 'f3bce955f21bc9456d65245c50e8c512')
// console.log("envoi du mail avec mailjet laniau2")
// let request = mailjet2.post("send", {'version': 'v3.1'})
// .request({
// "Messages":[
// {
// "From": {
// "Email": "l.laniau@talentstube.com",
// "Name": "Laurent"
// },
// "To": [
// {
// "Email": "l.laniau@talentstube.com",
// "Name": "Laurent"
// }
// ],
// "TemplateID": 2087555,
// "TemplateLanguage": true,
// "Variables": {
// "prénom": "\"]]</title><!--[if !mso]><!-- --><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><!--<![endif]--><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><style type=\"text/css",
// "lien": '<p style="display:inline-block;background:#36eda4;color:#ffffff;font-family:Arial,sans-serif;font-size:13px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;border-radius:3px"><span style="font-size:11px;text-align:center;background-color:#36eda4;color:#ffffff;font-family:Arial"><b>&nbsp; &nbsp; &nbsp; &nbsp;<a href="www.talentstube.com">Activer mon compte</a> &nbsp; &nbsp; &nbsp;</b></span></p>'
// },
// "Subject": "Test [[data:prénom:'Corentin']]",
// "TextPart": "My first Mailjet email",
// "HTMLPart": "<h3>Dear passenger 1, welcome to <a href='https://www.mailjet.com/'>Mailjet</a>!</h3><br />May the delivery force be with you!",
// "CustomID": "AppGettingStartedTest"
// }
// ]
// })
// request
// .then((result) => {
// console.log(result.body)
// })
// .catch((err) => {
// console.log(err.statusCode)
// })
// mailer.sendTransactionnelEmail();
// console.log("Fin envoi du mail a mailjet")
})
server.post('/sendConfirmationEmail', jsonParser, (req, res) => {
@@ -200,9 +298,12 @@ app.prepare()
const email = req.body.email
const nom = req.body.lastname
const prenom = req.body.firstname
//const url = req.body.adId
//console.log("Envoi d'email "+url)
//TODO Ajouter le contexte de l'annonce
//Envoyer URL
const tokenUrl = `${process.env.FRONT_SERVER}/ConfirmAccount/${token}/${email}`
console.log("tokenUrl "+tokenUrl)
mailer.sendConfirmationEmail(nom, prenom, tokenUrl, email);
res.json({ status: 'success' });
+139 -18
View File
@@ -1,5 +1,8 @@
const nodemailer = require("nodemailer");
const nodemailer = require("nodemailer");
const mailFrom = "noreply@talentstube.io"
const clePubliqueMailJet = "355697fac93fca865660734b4fdffaeb"
const clePriveMailJet = "ddecf75321ca89c09e561857b13534c8"
function setup() {
return nodemailer.createTransport({
@@ -11,33 +14,151 @@ function setup() {
}
});
}
exports.sendTransactionnelEmail = function () {
// US technique 444
var mailjet2 = require('node-mailjet')
.connect('805b8adce80bc6aa9422ddff20bb4171', 'f3bce955f21bc9456d65245c50e8c512')
console.log("envoi du mail avec mailjet laniau2")
let request = mailjet2.post("send", {'version': 'v3.1'})
.request({
"Messages":[
{
"From": {
"Email": "l.laniau@talentstube.com",
"Name": "Laurent"
},
"To": [
{
"Email": "l.laniau@talentstube.com",
"Name": "Laurent"
}
],
"TemplateID": 2087555,
"TemplateLanguage": true,
"Variables": {
"prénom": "\"]]</title><!--[if !mso]><!-- --><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><!--<![endif]--><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><style type=\"text/css",
"lien": '<p style="display:inline-block;background:#36eda4;color:#ffffff;font-family:Arial,sans-serif;font-size:13px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;border-radius:3px"><span style="font-size:11px;text-align:center;background-color:#36eda4;color:#ffffff;font-family:Arial"><b>&nbsp; &nbsp; &nbsp; &nbsp;<a href="www.talentstube.com">Activer mon compte</a> &nbsp; &nbsp; &nbsp;</b></span></p>'
},
"Subject": "Test [[data:prénom:'ggg']]",
"TextPart": "",
"HTMLPart": "",
"CustomID": "AppGettingStartedTest"
}
]
})
request
.then((result) => {
console.log(result.body)
})
.catch((err) => {
console.log(err.statusCode)
})
}
exports.sendConfirmationEmail = function (nom, prenom, tokenUrl, mail) {
const tranport = setup();
const email = {
from: process.env.EMAIL_FROM,
to: process.env.NODE_ENV === 'production'? mail : 'l.laniau@talentstube.com',
subject: `Bienvenue ${mail} 🔑`,
text: `
Bonjour ${prenom} ${nom},
// const tranport = setup();
// const email = {
// from: process.env.EMAIL_FROM,
// to: process.env.NODE_ENV === 'production'? mail : 'l.laniau@talentstube.com',
// subject: `Bienvenue ${mail} `,
// text: `
// Bonjour ${prenom} ${nom},
Veuillez cliquer sur le lien ci-dessous pour activer votre compte Talents Tube.
// Veuillez cliquer sur le lien ci-dessous pour activer votre compte Talents Tube.
${tokenUrl}
// ${tokenUrl}
*Ce lien ne peut être utilisé quune seule fois pour valider votre compte.
// *Ce lien ne peut être utilisé quune seule fois pour valider votre compte.
Si vous nêtes pas à lorigine de linscription sur Talents Tube, veuillez contacter le support Talents Tube.
// Si vous n’êtes pas à lorigine de linscription sur Talents Tube, veuillez contacter le support Talents Tube.
Merci de votre compréhension.
// Merci de votre compréhension.
Talents Tube
// Talents Tube
`
// };
// var mailjet2 = require('node-mailjet')
// .connect('805b8adce80bc6aa9422ddff20bb4171', 'f3bce955f21bc9456d65245c50e8c512')
// console.log("envoi du mail avec mailjet laniau2")
// let request = mailjet2.post("send", {'version': 'v3.1'})
// .request({
// "Messages":[
// {
// "From": {
// "Email": "l.laniau@talentstube.com",
// "Name": "Laurent"
// },
// "To": [
// {
// "Email": "l.laniau@talentstube.com",
// "Name": "Laurent"
// }
// ],
// "TemplateID": 2087555,
// "TemplateLanguage": true,
// "Variables": {
// "prénom": "\"]]</title><!--[if !mso]><!-- --><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><!--<![endif]--><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><style type=\"text/css",
// "lien": '<p style="display:inline-block;background:#36eda4;color:#ffffff;font-family:Arial,sans-serif;font-size:13px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;border-radius:3px"><span style="font-size:11px;text-align:center;background-color:#36eda4;color:#ffffff;font-family:Arial"><b>&nbsp; &nbsp; &nbsp; &nbsp;<a href="www.talentstube.com">Activer mon compte</a> &nbsp; &nbsp; &nbsp;</b></span></p>'
// },
// "Subject": "Test [[data:prénom:'ggg']]",
// "TextPart": "My first Mailjet email",
// "HTMLPart": "<h3>Dear passenger 1, welcome to <a href='https://www.mailjet.com/'>Mailjet</a>!</h3><br />May the delivery force be with you!",
// "CustomID": "AppGettingStartedTest"
// }
// ]
// })
// request
// .then((result) => {
// console.log(result.body)
// })
// .catch((err) => {
// console.log(err.statusCode)
// })
var mailjet2 = require('node-mailjet')
.connect(clePubliqueMailJet, clePriveMailJet)
console.log("envoi du mail avec mailjet "+mailFrom)
let request = mailjet2.post("send", {'version': 'v3.1'})
.request({
"Messages":[
{
"From": {
"Email": mailFrom,
"Name": "Talents Tube"
},
"To": [
{
"Email": mail,
"Name": prenom
}
],
"TemplateID": 2115317,
"TemplateLanguage": true,
"Variables": {
"nom": nom,
"prenom": prenom,
// "tokenUrl": "<a href='"+tokenUrl+"'>Activer le compte</a>"
"tokenUrl": tokenUrl
},
"Subject": "Bienvenue sur Talents Tube",
"TextPart": "",
"HTMLPart": "",
"CustomID": "AppGettingStartedTest"
}
]
})
request
.then((result) => {
console.log(result.body)
})
.catch((err) => {
console.log(err.statusCode)
})
// ,
// html: `
// `
};
tranport.sendMail(email);
// tranport.sendMail(email);
}
+12 -12
View File
@@ -58,9 +58,9 @@ export const POST_AD_ANSWER_REQUEST = "POST_AD_ANSWER_REQUEST";
export const POST_AD_ANSWER_SUCCESS = "POST_AD_ANSWER_SUCCESS";
export const POST_AD_ANSWER_FAILURE = "POST_AD_ANSWER_FAILURE";
export const FETCH_ADS_ANSWER_REQUEST = "FETCH_ADS_ANSWER_REQUEST";
export const FETCH_ADS_ANSWER_SUCCESS = "FETCH_ADS_ANSWER_SUCCESS";
export const FETCH_ADS_ANSWER_FAILURE = "FETCH_ADS_ANSWER_FAILURE";
export const FETCH_JOBS_ANSWER_REQUEST = "FETCH_JOBS_ANSWER_REQUEST";
export const FETCH_JOBS_ANSWER_SUCCESS = "FETCH_JOBS_ANSWER_SUCCESS";
export const FETCH_JOBS_ANSWER_FAILURE = "FETCH_JOBS_ANSWER_FAILURE";
export const FETCH_ANSWER_REQUEST = "FETCH_ANSWER_REQUEST";
export const FETCH_ANSWER_SUCCESS = "FETCH_ANSWER_SUCCESS";
@@ -76,17 +76,17 @@ export const FETCH_ANSWER_MESAGES_FAILURE = "FETCH_ANSWER_MESAGES_FAILURE";
export const FETCH_ANSWER_MESAGES_SUCCESS = "FETCH_ANSWER_MESAGES_SUCCESS";
//ADS
export const FETCH_ADS_REQUEST = "FETCH_ADS_REQUEST";
export const FETCH_ADS_SUCCESS = "FETCH_ADS_SUCCESS";
export const FETCH_ADS_FAILURE = "FETCH_ADS_FAILURE";
export const FETCH_JOBS_REQUEST = "FETCH_JOBS_REQUEST";
export const FETCH_JOBS_SUCCESS = "FETCH_JOBS_SUCCESS";
export const FETCH_JOBS_FAILURE = "FETCH_JOBS_FAILURE";
export const FETCH_AD_REQUEST = "FETCH_AD_REQUEST";
export const FETCH_AD_SUCCESS = "FETCH_AD_SUCCESS";
export const FETCH_AD_FAILURE = "FETCH_AD_FAILURE";
export const FETCH_JOB_REQUEST = "FETCH_JOB_REQUEST";
export const FETCH_JOB_SUCCESS = "FETCH_JOB_SUCCESS";
export const FETCH_JOB_FAILURE = "FETCH_JOB_FAILURE";
export const FETCH_EMPHASIS_ADS_REQUEST = "FETCH_EMPHASIS_ADS_REQUEST";
export const FETCH_EMPHASIS_ADS_SUCCESS = "FETCH_EMPHASIS_ADS_SUCCESS";
export const FETCH_EMPHASIS_ADS_FAILURE = "FETCH_EMPHASIS_ADS_FAILURE";
export const FETCH_EMPHASIS_JOBS_REQUEST = "FETCH_EMPHASIS_JOBS_REQUEST";
export const FETCH_EMPHASIS_JOBS_SUCCESS = "FETCH_EMPHASIS_JOBS_SUCCESS";
export const FETCH_EMPHASIS_JOBS_FAILURE = "FETCH_EMPHASIS_JOBS_FAILURE";
export const CLEAR_AD = "CLEAR_AD";
export const COUNT_AD_VIEW = "COUNT_AD_VIEW";
+180
View File
@@ -0,0 +1,180 @@
import React from 'react';
import PropTypes from 'prop-types';
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 List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import { ListItemText } from '@material-ui/core';
import { Spring, animated } from 'react-spring'
const styles = theme => ({
root: {
width: '100%',
'& a':{
textDecoration:'none'
}
},
grow: {
flexGrow: 1,
},
bar: {
},
menuButton: {
marginLeft: -12,
marginRight: 20,
[theme.breakpoints.up('sm')]: {
display: 'none',
},
[theme.breakpoints.down('md')]: {
display: 'block',
},
},
menuLogo: {
marginLeft: 20,
marginRight: 40,
cursor: 'pointer'
},
title: {
display: 'none',
[theme.breakpoints.up('sm')]: {
display: 'block',
},
[theme.breakpoints.down('md')]: {
display: 'none',
},
marginRight: 15,
cursor: 'pointer'
},
sectionDesktop: {
display: 'none',
[theme.breakpoints.up('md')]: {
display: 'flex',
},
},
sectionMobile: {
display: 'flex',
[theme.breakpoints.up('md')]: {
display: 'none',
},
},
fullList: {
width: 'auto',
cursor: 'pointer'
},
});
class HeaderOffre extends React.Component {
state = {
top: false,
left: false,
bottom: false,
right: false,
toggle: true
};
toggleDrawer = (side, open) => () => {
this.setState({
[side]: open,
});
};
toggle = () => this.setState(state => ({ toggle: !state.toggle }))
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<Drawer anchor="top" open={this.state.top} onClose={this.toggleDrawer('top', false)}>
<div
tabIndex={0}
role="button"
onClick={this.toggleDrawer('top', false)}
onKeyDown={this.toggleDrawer('top', false)}
>
<div className={classes.fullList}>
<List>
<Link href="/" prefetch >
<a><ListItem>
<ListItemIcon>
<HomeIcon />
</ListItemIcon>
<ListItemText primary='Accueil'>
</ListItemText>
</ListItem></a>
</Link>
<Divider />
<Link href="/contact" prefetch >
<a><ListItem>
<ListItemIcon>
<SendIcon />
</ListItemIcon>
<ListItemText primary='contact'>
</ListItemText>
</ListItem></a>
</Link>
</List>
</div>
</div>
</Drawer>
<AppBar position="static" className={classes.appBar}>
<Toolbar>
<IconButton className={classes.menuButton} onClick={this.toggleDrawer('top', true)}
color="inherit" aria-label="Open drawer">
<MenuIcon />
</IconButton>
<Link href="/" prefetch>
<a><div onClick={this.toggle}>
<Spring native from={{ x: 0 }} to={{ x: this.state.toggle ? 1 : 0 }} config={{ duration: 1000 }}>
{({ x }) => (
<animated.div
style={{
opacity: x.interpolate({ output: [1, 1] }),
transform: x
.interpolate({
range: [0, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 1],
output: [1, 0.97, 0.9, 1.1, 0.9, 1.1, 1.03, 1]
})
.interpolate(x => `scale(${x})`)
}}>
<img alt="e-declic" src='https://www.e-declic.com/files/e-declic/img/logo.png' className={classes.menuLogo} />
</animated.div>
)}
</Spring>
</div></a>
</Link>
<Link href="/contact" prefetch >
<a><Typography className={classes.title} variant="h5" color="inherit" noWrap>
Contact
</Typography></a>
</Link>
</Toolbar>
</AppBar>
</div >
);
}
}
HeaderOffre.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(HeaderOffre)
+1 -1
View File
@@ -16,7 +16,7 @@ function setup() {
const tranport = setup();
const email = {
from: process.env.EMAIL_FROM,
to: "thomas.berrod@e-declic.com",
to: "l.laniau@talentstube.com",
subject: "PWA feedback 💌⚡️",
text: `
Hello Team,