Compare commits

...

24 Commits

Author SHA1 Message Date
llaniau 96b08352a0 Minheight à 200px sur les offres pour les écrans mac 2020-09-09 17:09:37 +02:00
llaniau 7a45d19d2b Amelioration parcours talent 2020-09-08 17:37:18 +02:00
llaniau c73b08c1aa referencement 2020-09-07 18:44:54 +02:00
llaniau b6e4347abb Mise a jour Borganisation cliente 2020-09-07 15:58:55 +02:00
llaniau adb9d2ccde Changement de la page Help pour intéger les pages comment faire un cv video 2020-09-03 17:35:11 +02:00
llaniau edd7f705ab Cv video detachement 2020-09-02 18:39:08 +02:00
llaniau ea372ba0f2 AccountEtape3 modif du lien Front 2020-09-02 08:53:53 +02:00
llaniau 779b722662 bug requete offre 2020-08-24 18:29:00 +02:00
llaniau 6bb8baf636 variablisation url symfony 2020-08-20 17:40:42 +02:00
llaniau 083f7b9c16 cas cabinet recrutement (champ entreprise) 2020-08-18 18:15:31 +02:00
llaniau 0eed896aec next config 2020-08-18 10:40:41 +02:00
llaniau e8ae224414 VARIABILISATION DES URL EN DUR (CHANGEMENT DE NOM DE DOMAINE) 2020-08-17 11:28:32 +02:00
llaniau fa3dcd8fd2 suppression d'un attribut (job) pour jobposting 2020-08-13 18:14:56 +02:00
llaniau 2c0c0a2632 Mise en place Job Posting 2020-08-13 17:12:45 +02:00
llaniau 501ee57430 referencement index.js 2020-08-13 12:43:28 +02:00
llaniau 0f6ec17fef OgHead 2020-08-13 11:40:03 +02:00
llaniau 112541275b Modif Referencement 2020-08-13 11:36:41 +02:00
llaniau e08b879691 gestion adresse json webapp 2020-08-12 15:43:53 +02:00
llaniau 527351c232 video de pres Web app V2 2020-08-11 17:30:55 +02:00
llaniau 0ed8da11e1 package.json 2020-07-22 12:11:35 +02:00
llaniau f522e4389e bug 2020-07-22 11:55:33 +02:00
llaniau efb6527b9b v2.0.1 2020-07-22 08:23:55 +02:00
llaniau ba43bcddc7 mise en place modif profile 2020-07-20 14:38:00 +02:00
llaniau 3523cc95ee Design update profile et video 2020-07-16 17:10:27 +02:00
44 changed files with 18643 additions and 1310 deletions
+2
View File
@@ -6,6 +6,7 @@ import AssignmentIcon from '@material-ui/icons/Assignment';
import RoomIcon from '@material-ui/icons/Room';
import LocationOnIcon from '@material-ui/icons/LocationOn';
import BusinessCenterIcon from '@material-ui/icons/BusinessCenter';
import Business from '@material-ui/icons/Business';
import Typography from '@material-ui/core/Typography';
const variantIcon = {
@@ -13,6 +14,7 @@ const variantIcon = {
room: RoomIcon,
location_on: LocationOnIcon,
business_center: BusinessCenterIcon,
business: Business,
};
const styles = theme => ({
@@ -6,12 +6,14 @@ import RoomIcon from '@material-ui/icons/Room';
import LocationOnIcon from '@material-ui/icons/LocationOn';
import BusinessCenterIcon from '@material-ui/icons/BusinessCenter';
import Typography from '@material-ui/core/Typography';
import Business from '@material-ui/icons/Business';
const variantIcon = {
assignment: AssignmentIcon,
room: RoomIcon,
location_on: LocationOnIcon,
business_center: BusinessCenterIcon,
business: Business,
};
const styles = theme => ({
+34
View File
@@ -0,0 +1,34 @@
import React from 'react'
import { JobPostingJsonLd } from 'next-seo';
const JobPosting = props => {
return (
<JobPostingJsonLd
datePosted="2020-01-06T03:37:40Z"
description={props.job_description}
hiringOrganization={{
name: props.job_brand,
sameAs: props.job_brand_link,
}}
jobLocation={{
addressLocality: props.job_location,
}}
title={props.job_title}
validThrough="2020-01-06"
applicantLocationRequirements="FR"
/>
)
}
JobPosting.propTypes = {
// seo_title: PropTypes.string.isRequired,
// seo_description: PropTypes.string.isRequired,
// seo_url: PropTypes.string.isRequired,
// image: PropTypes.string.isRequired,
}
export default JobPosting
+9 -3
View File
@@ -6,7 +6,8 @@ const OgHead = props => {
return (
<Head>
<title key="title">{props.seo_title}</title>
<meta name="description" key="description" content={props.seo_description} />
<meta name="robots" content="noindex, nofollow"></meta>
<meta name="description" kenoindexy="description" content={props.seo_title} />
<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" />
@@ -18,9 +19,14 @@ const OgHead = props => {
/>
<meta name="keywords" content={props.seo_key}/>
<meta key="og:image" property="og:image" content={props.image} />
<link rel="canonical" href={ props.seo_url} />
<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:image" content={props.image}/>
<link rel="canonical" href={ props.seo_url} />
</Head>
)
}
+34 -2
View File
@@ -30,6 +30,32 @@ const useStyles = makeStyles(theme => ({
height: '100%',
},
},
},
videoPresentation: {
display: 'flex',
flexDirection: 'column',
position: 'relative',
paddingBottom: '56%', /* 16:9 58%*/
'& iframe': {
position: 'absolute',
top: 0,
left: 'calc(50% - 50vw)',
width: '100vw',
height: '100%',
},
[theme.breakpoints.up('md')]: {
display: 'flex',
flexDirection: 'column',
position: 'relative',
paddingBottom: '56.5%', /* 16:9 */
'& iframe': {
position: 'absolute',
top: 0,
left: 'calc(50% - 32vw)',
width: '64vw',
height: '100%',
},
},
}
}));
@@ -37,14 +63,20 @@ export default function VideoVimeo(props) {
const {videoId, title, options, classesOverride, autoplay} = props;
const classes = useStyles();
let className = classes.video;
if (classesOverride) {
className = classes.videoPresentation;
}
return (
<section className={classes.video +' '+classesOverride}>
<section className={className +' '+classesOverride}>
<iframe className='player'
src={"https://player.vimeo.com/video/"+ videoId + options+"?autoplay="+autoplay}
frameBorder="0"
title={title}
webkitallowfullscreen="true" mozallowfullscreen="true" allowFullScreen></iframe>
</section>
)
}
@@ -1,386 +0,0 @@
import React, { Component, Fragment } from 'react'
import { withStyles } from '@material-ui/core/styles';
import { Button, Typography } from '@material-ui/core';
import TextField from '@material-ui/core/TextField';
import { Alert, AlertTitle } from '@material-ui/lab';
import Input from '@material-ui/core/Input';
import { connect } from 'react-redux'
import { postAdAnswerRequest } from '../../actions/answer'
import { updateUserRequest, updateUserPictureRequest } from '../../actions/user'
import Avatar from '@material-ui/core/Avatar';
import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight';
import Loader from './../templates/loader'
import getConfig from 'next/config'
import Validator from "validator";
import ReactHtmlParser, { processNodes, convertNodeToElement, htmlparser2 } from 'react-html-parser';
const styles = theme => ({
container: {
width: '100%',
},
form: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
padding: '24px',
paddingBottom: theme.spacing(8),
marginBottom: theme.spacing(8),
'&>div': {
marginTop: theme.spacing(1.5),
marginBottom: theme.spacing(1.5),
},
[theme.breakpoints.up('md')]: {
padding: '0 calc(25vw + 24px)',
},
},
importContainer: {
alignSelf: 'flex-start',
},
textField: {
width: '100%',
'&:disabled': {
color: theme.palette.secondary.dark,
},
'& label': {
color: theme.palette.primary.dark,
},
'& fieldset:hover': {
borderColor: theme.palette.primary.main + ' !important',
},
},
foot: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
zIndex: '10',
width: '100%',
position: 'fixed',
bottom: 0,
padding: theme.spacing(1.2, 0),
backgroundColor: theme.palette.secondary.main,
boxShadow: '0px 0px 10px rgba(30, 35, 39, 0.10)',
},
rootButton: {
textTransform: 'inherit',
border: '1px solid',
'&:hover': {
border: '1px solid',
},
},
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,
},
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,
},
},
});
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 {
constructor(props) {
super(props);
// This binding is necessary to make `this` work in the callback
this.handleChange = this.handleChange.bind(this);
this.onBlur = this.onBlur.bind(this)
this.onSubmit = this.onSubmit.bind(this);
}
state = {
file: null,
firstname: '',
lastname: '',
phone: '',
currentJob: '',
linkedin: '',
twitter: '',
website: '',
mediaId: null,
companyId: null,
};
handleChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
//console.log(this.refs.myTextField.input.value);
//this.soumettre(e);
}
onBlur(event) {
console.log("blur")
this.soumettre();
}
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,
mediaId: nextProps.mediaId,
companyId: nextProps.companyId,
errors: !!!nextProps.errors ? { errors: { message: "" } } : nextProps.errors,
})
}
componentDidMount() {
this.setState({
firstname: this.props.user.firstname,
lastname: this.props.user.lastname,
phone: this.props.user.phone,
currentJob: this.props.user.currentJob,
linkedin: this.props.user.linkedin,
twitter: this.props.user.twitter,
website: this.props.user.website,
})
}
onSubmit = (e) => {
e.preventDefault();
this.soumettre(e);
}
soumettre(e){
const errors = this.validate(this.state);
this.setState({ errors });
if (!this.state.errors || !this.state.errors.message){
const data = new FormData()
data.append('firstname', this.state.firstname)
data.append('lastname', this.state.lastname)
data.append('phone', this.state.phone)
//data.append('email', this.state.email)
data.append('currentJob', this.state.currentJob)
data.append('linkedin', this.state.linkedin)
data.append('twitter', this.state.twitter)
data.append('website', this.state.website)
//TODO:maybe add this two in a single transactionnal saga
this.props.updateUserRequest(data)
}
}
validate = data => {
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 += "Le prénom est obligatoire<br />";
if (!data.lastname || data.lastname==="") errors.message += "Le nom est obligatoire<br />";
if (!Validator.isMobilePhone(data.phone, "fr-FR")) errors.message += "Le téléphone n'est pas correct<br />";
//console.log(errors.email);
return errors;
};
AfficherErreurs() {
if (!this.state.errors || !this.state.errors.message){
return "";
}else if (this.state.errors.length != 0 && this.state.errors.message!="") {
console.log("Erreur"+this.state.errors.message);
console.log("afficher erreur");
return (
<Alert severity="error">
{ ReactHtmlParser(this.state.errors.message)}
</Alert>
);
}
return "";
}
inputFilesystemChange = (e) => {
console.log("inputFilesystemChange");
var file = e.target.files[0]
this.setState({ picture: file })
const data = new FormData()
data.append('file', file)
this.props.updateUserPictureRequest(data)
}
render() {
const { classes, user } = this.props
const logoUrl = user.picture;
return (
<section className={classes.container}>
<form className={classes.form}
autoComplete="off" focused="true" name="monForm" ref="formToSubmit">
{!!logoUrl && <Avatar className={classes.logo}
classes={{ img: classes.MuiAvatarImg }}
src={publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.postedContentUrl + logoUrl} alt="candidatLogo" />}
{!!user.pictureLoading && <Loader />}
{!!!user.pictureLoading && !!!logoUrl &&
(<Fragment><input
type="file" accept="image/*" capture="filesystem"
className={classes.input}
style={{ display: 'none' }}
id="raised-button-file"
multiple
type="file"
onChange={this.inputFilesystemChange}
/>
<label htmlFor="raised-button-file">
<Button component="span" className={classes.importButton} classes={{ root: classes.rootButton }}>
<img alt="talents-tube" src='/static/images/default/account-avatar-default.svg'
className={classes.iconButton} />
<Typography align="left" className={classes.textButton}>
J'<span className={classes.underlined}>importe</span> ma photo de profil
</Typography>
<KeyboardArrowRightIcon className={classes.InputKeyboardArrowRightIcon} />
</Button>
</label></Fragment>)
}
{this.AfficherErreurs()}
<TextField
name="lastname"
required
id="outlined-required"
label="Nom :"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.lastname}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<TextField
name="firstname"
required
id="outlined-required"
label="Prénom"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.firstname}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<TextField
name="phone"
id="outlined"
label="Téléphone"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.phone}
onChange={this.handleChange}
type="tel"
onBlur={this.onBlur}
/>
<TextField
name="email"
id="outlined"
label="E-mail"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={user.email}
onChange={this.handleChange}
type="mail"
onBlur={this.onBlur}
/>
<TextField
name="currentJob"
id="outlined"
label="Poste actuel"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.currentJob}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<TextField
name="linkedin"
id="outlined"
label="Linkedin"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
placeholder="http://www.linkedin.com/in/"
value={this.state.linkedin}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<TextField
name="twitter"
id="outlined"
label="Twitter"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
placeholder="http://twitter.com/.."
value={this.state.twitter}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<TextField
name="website"
id="outlined"
label="Site internet"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
placeholder="http://monsite.fr"
value={this.state.website}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
</form>
<div id="F" className={classes.foot}>
<Button variant="contained" className={classes.button + ' cypButtonSendApplication'} onClick={this.onSubmit}>Mettre à jour!</Button>
</div>
</section>
)
}
}
function mapStateToProps(state, ownProps) {
return {
user: state.user,
loading: !!state.user.loading,
pictureLoading: !!state.user.pictureLoading,
errors: state.user.errors || ownProps.errors,
mediaId: state.media.message && state.media.message.mediaId,
};
}
export default withStyles(styles)(connect(mapStateToProps, { postAdAnswerRequest, updateUserRequest, updateUserPictureRequest })(Accountdetails))
+487 -17
View File
@@ -1,25 +1,495 @@
import React from 'react';
import { makeStyles } from '@material-ui/styles';
import AccountDetails from '../organisms/AccountDetails';
import Button from '@material-ui/core/Button';
import React, { useState, Component, Fragment } from 'react'
import { withStyles } from '@material-ui/core/styles';
import TextField from '@material-ui/core/TextField';
import { Alert, AlertTitle } from '@material-ui/lab';
import Snackbar from '@material-ui/core/Snackbar';
import { connect } from 'react-redux'
import { updateUserRequest } from '../../actions/user'
import getConfig from 'next/config'
import Validator from "validator";
import ReactHtmlParser, { processNodes, convertNodeToElement, htmlparser2 } from 'react-html-parser';
import {
Button,
} from '@material-ui/core';
class AccountEtape1 extends React.Component {
const styles = theme => ({
container: {
width: '85%',
},
form: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
padding: '24px',
paddingBottom: theme.spacing(8),
marginBottom: theme.spacing(8),
'&>div': {
marginTop: theme.spacing(1.5),
marginBottom: theme.spacing(1.5),
}
},
textField: {
width: '85%',
'&:disabled': {
color: theme.palette.secondary.dark,
},
'& label': {
color: theme.palette.primary.dark,
},
'& fieldset:hover': {
borderColor: theme.palette.primary.main + ' !important',
},
},
textFieldSmall: {
width: '48%',
'&:disabled': {
color: theme.palette.secondary.dark,
},
'& label': {
color: theme.palette.primary.dark,
},
'& fieldset:hover': {
borderColor: theme.palette.primary.main + ' !important',
},
padding: '5px',
},
});
const { publicRuntimeConfig } = getConfig();
//https://xd.adobe.com/view/ba98331a-9145-4d67-7e27-25a36e519ef4-cca9/screen/a96779d7-bdb3-410a-8f19-e6987acb98ee/Candidature-Step-3
class Accountdetails extends Component {
constructor(props) {
super(props);
// This binding is necessary to make `this` work in the callback
this.handleChange = this.handleChange.bind(this);
this.handleClose = this.handleClose.bind(this);
this.onBlur = this.onBlur.bind(this)
this.onSubmit = this.onSubmit.bind(this);
}
state = {
file: null,
firstname: '',
lastname: '',
email:'',
phone: '',
currentJob: '',
address1:'',
address2 : '',
zipCode : '',
city : '',
country : '',
linkedin: '',
twitter: '',
website: '',
mediaId: null,
companyId: null,
};
handleChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
//console.log(this.refs.myTextField.input.value);
//this.soumettre(e);
}
handleClose = (e, reason) => {
if (reason === 'clickaway') {
return;
}
//setOpen(false);
};
onBlur(e) {
console.log("blur")
this.setState({ [e.target.name]: e.target.value });
this.soumettre();
}
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
firstname: nextProps.user.firstname,
lastname: nextProps.user.lastname,
phone: nextProps.user.phone,
email: nextProps.user.email,
currentJob: nextProps.user.currentJob,
address1 : nextProps.user.address1,
address2 : nextProps.user.address2,
zipCode : nextProps.user.zipCode,
city : nextProps.user.city,
country : nextProps.user.country,
linkedin: nextProps.user.linkedin,
twitter: nextProps.user.twitter,
website: nextProps.user.website,
companyId: nextProps.companyId,
errors: !!!nextProps.errors ? { errors: { message: "" } } : nextProps.errors,
})
}
componentDidMount() {
this.setState({
firstname: this.props.user.firstname,
lastname: this.props.user.lastname,
phone: this.props.user.phone,
email: this.props.user.email,
address1: this.props.user.address1,
address2 : this.props.user.address2,
zipCode : this.props.user.zipCode,
city : this.props.user.city,
country : this.props.user.country,
currentJob: this.props.user.currentJob,
linkedin: this.props.user.linkedin,
twitter: this.props.user.twitter,
website: this.props.user.website,
})
}
onSubmit = (e) => {
e.preventDefault();
this.soumettre(e);
}
soumettre(e){
const errors = this.validate(this.state);
const success = {};
this.setState({ errors });
if (!this.state.errors || !this.state.errors.message){
success.message ="Profil mis à jour";
this.setState({ success });
const data = new FormData()
data.append('firstname', this.state.firstname)
data.append('lastname', this.state.lastname)
data.append('phone', this.state.phone)
//data.append('email', this.state.email)
data.append('currentJob', this.state.currentJob)
data.append('address1', this.state.address1)
data.append('address2', this.state.address2)
data.append('zipCode', this.state.zipCode)
data.append('city', this.state.city)
data.append('country', this.state.country)
data.append('linkedin', this.state.linkedin)
data.append('twitter', this.state.twitter)
data.append('website', this.state.website)
//TODO:maybe add this two in a single transactionnal saga
this.props.updateUserRequest(data)
}
}
validate = data => {
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 />";
//console.log(errors.email);
return errors;
};
AfficherErreurs() {
if (!this.state.errors || !this.state.errors.message){
return "";
}else if (this.state.errors.length != 0 && this.state.errors.message!="") {
return (
<Alert severity="error">
{ ReactHtmlParser(this.state.errors.message)}
</Alert>
);
}
return "";
}
AfficherSuccess() {
// if (this.state.success && this.state.success.length != 0 && this.state.success.message != "") {
// return (
// <Snackbar open={open} autoHideDuration={1000} onClose={() => this.setState({open: false})}>
// <Alert onClose={() => this.setState({open: false})} severity="success">
// {ReactHtmlParser(this.state.success.message)}
// </Alert>
// </Snackbar>
// );
// }
return "";
}
inputFilesystemChange = (e) => {
console.log("inputFilesystemChange");
var file = e.target.files[0]
this.setState({ picture: file })
const data = new FormData()
data.append('file', file)
this.props.updateUserPictureRequest(data)
}
render() {
const { classes, user } = this.props
const logoUrl = user.picture;
function refresh() {
document
.location
.reload(true);
}
return (
<div><AccountDetails />
<Button
variant="contained"
color="primary"
onClick={this.props.test}
>
Suivant
</Button></div>
);
<section className={classes.container}>
<form className={classes.form}
autoComplete="off" focused="true" name="monForm" ref="formToSubmit">
{/* {!!logoUrl && <Avatar className={classes.logo}
classes={{ img: classes.MuiAvatarImg }}
src={publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.postedContentUrl + logoUrl} alt="candidatLogo" />} */}
{/* {!!user.pictureLoading && <Loader />}
{!!!user.pictureLoading && !!!logoUrl &&
(<Fragment><input
type="file" accept="image/*" capture="filesystem"
className={classes.input}
style={{ display: 'none' }}
id="raised-button-file"
multiple
type="file"
onChange={this.inputFilesystemChange}
/>
<label htmlFor="raised-button-file">
<Button component="span" className={classes.importButton} classes={{ root: classes.rootButton }}>
<img alt="talents-tube" src='/static/images/default/account-avatar-default.svg'
className={classes.iconButton} />
<Typography align="left" className={classes.textButton}>
J'<span className={classes.underlined}>importe</span> ma photo de profil
</Typography>
<KeyboardArrowRightIcon className={classes.InputKeyboardArrowRightIcon} />
</Button>
</label></Fragment>)
} */}
{this.AfficherErreurs()}
{this.AfficherSuccess()}
<TextField
name="firstname"
required
id="outlined-required"
label="Prénom"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.firstname}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<TextField
name="lastname"
required
id="outlined-required"
label="Nom"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.lastname}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<TextField
disabled
name="email"
id="outlined"
label="E-mail"
required
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.email}
onChange={this.handleChange}
type="mail"
onBlur={this.onBlur}
/>
<TextField
name="phone"
id="outlined"
label="Téléphone"
required
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.phone ? this.state.phone: ''}
onChange={this.handleChange}
type="tel"
onBlur={this.onBlur}
/>
<TextField
name="currentJob"
id="outlined"
label="Poste actuel"
required
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.currentJob && this.state.currentJob !='null' ? this.state.currentJob : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<TextField
name="address1"
id="outlined"
label="Adresse"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.address1 && this.state.address1 !='null' ? this.state.address1 : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<TextField
name="address2"
id="outlined"
label="Adresse complémentaire"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.address2 && this.state.address2 !='null' ? this.state.address2 : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<div className={classes.container}>
<TextField
name="zipCode"
id="outlined"
label="Code postal"
className={classes.textField}
classes={{ root: classes.textFieldSmall }}
variant="outlined"
value={this.state.zipCode && this.state.zipCode !='null' ? this.state.zipCode : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<TextField
name="city"
id="outlined"
label="Ville"
className={classes.textField}
classes={{ root: classes.textFieldSmall }}
variant="outlined"
value={this.state.city && this.state.city !='null' ? this.state.city : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<TextField
name="country"
id="outlined"
label="Pays"
className={classes.textField}
classes={{ root: classes.textFieldSmall }}
variant="outlined"
value={this.state.country && this.state.country !='null' ? this.state.country : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
</div>
<TextField
name="linkedin"
id="outlined"
label="Linkedin"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
placeholder="http://www.linkedin.com/in/"
value={this.state.linkedin && this.state.linkedin !='null' ? this.state.linkedin : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<TextField
name="twitter"
id="outlined"
label="Twitter"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
placeholder="http://twitter.com/.."
value={this.state.twitter && this.state.twitter !='null' ? this.state.twitter : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<TextField
name="website"
id="outlined"
label="Site internet"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
placeholder="http://monsite.fr"
value={this.state.website && this.state.website !='null' ? this.state.website : ''}
onChange={this.handleChange}
onBlur={this.onBlur}
/>
<Button
variant="contained"
color="primary"
onClick={refresh}
className={classes.button}>
Enregistrer
</Button>
</form>
{/* <div id="F" className={classes.foot}>
<Button variant="contained" className={classes.button + ' cypButtonSendApplication'} onClick={this.onSubmit}>Mettre à jour!</Button>
</div> */}
</section>
)
}
}
function mapStateToProps(state, ownProps) {
return {
user: state.user ,
loading: !!state.user.loading,
pictureLoading: !!state.user.pictureLoading,
errors: state.user.errors || ownProps.errors,
mediaId: state.media.message && state.media.message.mediaId,
};
}
export default AccountEtape1;
export default withStyles(styles)(connect(mapStateToProps, { updateUserRequest })(Accountdetails))
+285 -337
View File
@@ -1,369 +1,317 @@
import React, {Fragment} from 'react'
import { connect } from "react-redux";
import { makeStyles } from '@material-ui/styles';
import {connect} from "react-redux";
import {makeStyles} from '@material-ui/styles';
import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight';
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
import { Button, Typography } from '@material-ui/core';
import {Button, Typography} from '@material-ui/core';
import dynamic from 'next/dynamic'
import { withStyles } from '@material-ui/core/styles'
import { uploadMediaPres } from '../../actions/media'
import { errorMessageSelector } from '../../reducers/media'
import { fetchCompanyRequest } from '../../actions/companies'
import { fetchCurrentUserRequest } from '../../actions/user'
import {withStyles} from '@material-ui/core/styles'
import {uploadMediaPres} from '../../actions/media'
import {errorMessageSelector} from '../../reducers/media'
import {fetchCompanyRequest} from '../../actions/companies'
import {fetchCurrentUserRequest} from '../../actions/user'
import VideoVimeo from '../atoms/VideoVimeo'
import Router from 'next/router'
import Loader from '../templates/loader'
import Ar from "lodash/array"
import Snackbar from '@material-ui/core/Snackbar';
import { Alert, AlertTitle } from '@material-ui/lab';
import ReactHtmlParser, { processNodes, convertNodeToElement, htmlparser2 } from 'react-html-parser';
import Grid from '@material-ui/core/Grid';
import Container from '@material-ui/core/Container';
import Hidden from '@material-ui/core/Hidden';
const styles = theme => ({
root: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'flex-start',
margin: theme.spacing(1),
},
rootStepperContainer: {
padding: theme.spacing(2, 12),
width: '25vw',
[theme.breakpoints.up('md')]: {
width: '7vw',
alignItems: 'center',
container: {
width: '100%',
},
'& .MuiStep-horizontal, & .MuiStepLabel-iconContainer': {
padding: '0 !important',
[theme.breakpoints.up('md')]: {
padding: 'inherit',
},
root: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'flex-start',
margin: theme.spacing(1),
flexWrap: 'wrap',
overflow: 'hidden',
backgroundColor: theme.palette.background.paper,
},
'& .Mui-disabled .MuiStepConnector-line': {
borderColor: theme.palette.answer.main + '!important',
},
'& .Mui-disabled .MuiStepIcon-root': {
color: theme.palette.answer.main + '!important',
},
},
rootStepperDefault: {
'& .MuiStepConnector-line': {
borderColor: theme.palette.secondary.dark,
}
},
rootStepperActive: {
'& .MuiStepConnector-line': {
borderColor: theme.palette.primary.main,
}
},
headerContainer: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
padding: theme.spacing(2),
},
infoContainer: {
display: 'flex',
flexDirection: 'column',
padding: theme.spacing(0, 1.5),
},
logoContainer: {
display: 'flex',
alignItems: 'center',
width: 60,
height: 60,
backgroundColor: 'white',
boxShadow: '0px 6px 15px rgba(30, 35, 39, 0.10)',
border: 'solid 5px white',
borderRadius: '6px',
},
recorderContainer: {
//display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '400px',
},
helpContainer: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '400px',
},
logo: {
width: 'inherit',
height: '100%',
objectFit: 'contain',
borderRadius: '3px',
},
MuiAvatarImg: {
objectFit: 'contain',
},
title: {
fontSize: '1em',
fontWeight: '500',
},
companyName: {
fontSize: '0.9em',
fontWeight: '300',
},
textContainer: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
'& p': {
fontWeight: '300',
},
'& > p:nth-child(1)': {
'& span': {
fontWeight: '500',
}
},
'& > p:nth-child(2)': {
paddingBottom: theme.spacing(2),
borderBottom: '1px solid #E8E8E8',
'& span': {
fontWeight: '500',
color: theme.palette.primary.main,
}
},
},
rootButton: {
textTransform: 'inherit',
},
underlined: {
textDecoration: 'underline',
},
textButton: {
fontWeight: '700',
fontSize: '1.15em',
paddingLeft: theme.spacing(2),
},
iconHelpButton: {
fontSize: '1.5em',
fontWeight: '500',
padding: theme.spacing(0, 2),
color: theme.palette.secondary.important,
},
helpButton: {
color: theme.palette.primary.dark,
backgroundColor: 'transparent',
padding: theme.spacing(0, 2),
margin: theme.spacing(1),
width: '100%',
'& span.MuiButton-label': {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}
},
captureButton: {
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.main,
padding: theme.spacing(5, 2),
margin: theme.spacing(1),
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 4px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.14)',
'&:hover': {
backgroundColor: theme.palette.primary.main,
},
},
importButton: {
color: theme.palette.primary.main,
backgroundColor: theme.palette.secondary.main,
padding: theme.spacing(3, 2),
margin: theme.spacing(1),
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,
},
},
HelpKeyboardArrowRightIcon: {
fontSize: '2.5em',
color: theme.palette.primary.dark,
},
InputKeyboardArrowRightIcon: {
fontSize: '2.5em',
color: theme.palette.secondary.main,
},
InputKeyboardArrowDownIcon: {
fontSize: '2.5em',
color: theme.palette.primary.main,
},
});
const Recorder = dynamic(() => import('../organisms/Recorder'), {
ssr: false
})
class Etape2 extends React.Component {
state = {
loading: true,
activeStep: 0,
data:{},
openSnack: false,
errors: {},
};
componentDidMount() {
localStorage.setItem('loginRedirect', window.location)
if(!!!localStorage.getItem('ttJWT'))
{
Router.push("/Login")
}
else
this.setState({
loading: false,
firstname: this.props.user.firstname,
videoPres : this.props.user.videoPres,
video: this.props.user.presentation_video_id,
})
}
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
loading: nextProps.loading,
openSnack: !!!_.isEmpty(nextProps.errors),
errors: !!!nextProps.errors ? { errors: { message: "" } } : nextProps.errors,
})
window.location.reload(false);
if(nextProps.media.status === 'success'){
this.setActiveStep(1);
recorderContainer: {
//display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%'
},
rootButton: {
textTransform: 'inherit'
},
underlined: {
textDecoration: 'underline'
},
textButton: {
fontWeight: '700',
fontSize: '1.15em',
paddingLeft: theme.spacing(2)
},
videoPresentation: {
width: "100%",
height: "100%"
},
conseilButton: {
color: "#ffffff",
backgroundColor: "#25D89A",
padding: theme.spacing(3, 2),
margin: theme.spacing(1),
width: "100%",
textAlign: "right",
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1' +
'px rgba(0, 0, 0, 0.14)',
'&:hover': {
color: "#ffffff",
backgroundColor: "#25D89A",
}
},
importButton: {
color: theme.palette.primary.main,
backgroundColor: theme.palette.secondary.main,
padding: theme.spacing(3, 2),
margin: theme.spacing(1),
width: "100%",
textAlign: "right",
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1' +
'px rgba(0, 0, 0, 0.14)',
'&:hover': {
color: theme.palette.primary.main,
backgroundColor: theme.palette.secondary.main,
}
},
InputKeyboardArrowDownIconBlank: {
fontSize: '2.5em',
color: "#ffffff",
textAlign: "right"
},
InputKeyboardArrowDownIcon: {
fontSize: '2.5em',
color: "#1689FB",
textAlign: "right"
}
}
});
const Recorder = dynamic(() => import ('../organisms/Recorder'), {ssr: false})
class Etape2 extends React.Component {
state = {
loading: true,
activeStep: 0,
data: {},
openSnack: false,
errors: {},
success : {}
};
setActiveStep = (step) => {
this.setState({ activeStep: step })
}
componentDidMount() {
localStorage.setItem('loginRedirect', window.location)
inputFilesystemChange = (e) => {
this.uploadMediaPres(e)
}
inputCamRecorderChange = (e) => {
this.uploadMediaPres(e)
}
uploadMediaPres = (e) => {
var file = e.target.files[0]
const data = new FormData()
data.append('upload', file)
this.props.uploadMediaPres(data)
}
handleClose = (event, reason) => {
this.setState({ openSnack: false });
}
render() {
const { classes, company } = this.props;
const { loading, activeStep } = this.state;
let video;
if (this.state.videoPres) {
video = <VideoVimeo videoId={Ar.last(_.split(this.state.videoPres, '/'))} autoplay='1' />;
} else {
video = "";
if (!!!localStorage.getItem('ttJWT')) {
Router.push("/Login")
} else
this.setState({loading: false, firstname: this.props.user.firstname, videoPres: this.props.user.videoPres, video: this.props.user.presentation_video_id})
}
return (
<Fragment>
{ loading}
<div className={classes.root}>
{video}
<div className={classes.textContainer}>
<Typography gutterBottom align="center">
Vous allez créer une <span>vidéo</span> de motivation !
</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>
{/* <Fragment>
<input
type="file" accept="video/*" capture="camcorder"
style={{ display: 'none' }}
id="record-button-file"
multiple
onChange={this.inputCamRecorderChange}
/>
<label htmlFor="record-button-file">
<Button component="span" >
<img alt="talents-tube" src='/statique/images/capture.svg' />
<Typography align="left" >
Je <span >réalise</span> ma vidéo de réponse
</Typography>
<KeyboardArrowRightIcon />
</Button>
</label>
</Fragment> */}
<div className={classes.recorderContainer}>
<Recorder uploader={this.props.uploadMediaPres} />
</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>
</Fragment>
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
loading: nextProps.loading,
openSnack: !!!_.isEmpty(nextProps.errors),
errors: !!!nextProps.errors
? {
errors: {
message: ""
}
}
: nextProps.errors,
videoPres: nextProps.videoPres,
video: nextProps.video
})
//window.location.reload(false);
if (nextProps.media.status === 'success') {
const success = {};
success.message ="Vidéo mis à jour";
this.setState({ success });
this.setActiveStep(1);
}
}
setActiveStep = (step) => {
this.setState({activeStep: step})
}
inputFilesystemChange = (e) => {
this.uploadMediaPres(e)
}
inputCamRecorderChange = (e) => {
this.uploadMediaPres(e)
}
uploadMediaPres = (e) => {
var file = e.target.files[0]
const data = new FormData()
data.append('upload', file)
//this.setState({ videoPres: videoPres })
);
}
this
.props
.uploadMediaPres(data)
}
AfficherSuccess() {
if (!this.state.success || !this.state.success.message) {
} else if (this.state.success.length != 0 && this.state.success.message != "") {
return (
<Snackbar open={open} autoHideDuration={1000} onClose={() => this.setState({open: false})}>
<Alert onClose={() => this.setState({open: false})} severity="success">
{ReactHtmlParser(this.state.success.message)}
</Alert>
</Snackbar>
);
}
return "";
}
handleClose = (event, reason) => {
this.setState({openSnack: false});
}
render() {
const {classes, company} = this.props;
const {loading, activeStep} = this.state;
let video;
if (this.state.videoPres) {
video = <VideoVimeo videoId={Ar.last(_.split(this.state.videoPres, '/'))} autoplay='1' classesOverride="videoPresentation"/>;
} else {
video = "";
}
return (
<section className={classes.container}>
<Fragment>
{this.AfficherSuccess()}
{ loading ? <Loader/> : <div></div> }
<div className={classes.root}>
<Hidden xsUp>
&nbsp;
</Hidden>
<Container maxWidth="md">
<Grid container
justify="center"
alignItems="center"
spacing={2}>
<Grid item xs={12} sm={12} md={12} lg={6} lg={6}>
<div className={classes.recorderContainer}>
<Recorder uploader={this.props.uploadMediaPres} titreBouton="Remplacer ma vidéo"/>
</div>
</Grid>
<Grid item xs={12} sm={12} md={12} lg={6} xl={6}>
<div>
<label htmlFor="import-conseil">
<Button
component="span"
className={classes.conseilButton}
classes={{
root: classes.rootButton}}
onClick={() => Router.push(`/Conseils`)}>
<img
alt="talents-tube"
src='/statique/images/conseils-talentstube.svg'
className={classes.iconButton}/>
<Typography align="left" className={classes.textButton}>
<span className={classes.underlined}>Comment</span> créer ma vidéo
</Typography>
<KeyboardArrowDownIcon className={classes.InputKeyboardArrowDownIconBlank}/>
</Button>
</label>
</div>
<div>
<input
type="file"
accept="video/*"
className={classes.input + ' cypButtonImportVid'}
style={{display: 'none'}}
id="import-button-file"
onChange={this.inputFilesystemChange}/>
<label htmlFor="import-button-file">
<Button
component="span"
className={classes.importButton}
classes={{
root: classes.rootButton}}>
<img
alt="talents-tube"
src='/statique/images/Import.svg'
className={classes.iconButton}/>
<Typography align="left" className={classes.textButton}>
J'<span className={classes.underlined}>importe</span> ma vidéo de réponse
</Typography>
<KeyboardArrowDownIcon className={classes.InputKeyboardArrowDownIcon}/>
</Button>
</label>
</div>
</Grid>
<Hidden xsUp>
&nbsp;
</Hidden>
<Grid item xs={12} sm={12} md={12} lg={12} xl={12}>
<div className={classes.videoPresentation}>
{video}
</div>
</Grid>
</Grid>
</Container>
</div>
{/* <div className={classes.textContainer}>
</div> */}
</Fragment>
</section>
);
}
}
Etape2.getInitialProps = function (context) {
const { companyId } = context.query
const {res} = context
const {companyId} = context.query
const {res} = context
//TODO :really needed ?
context.store.dispatch(fetchCurrentUserRequest())
context
.store
.dispatch(fetchCurrentUserRequest())
if(!!companyId)
context.store.dispatch(fetchCompanyRequest(companyId))
if (!!companyId)
context.store.dispatch(fetchCompanyRequest(companyId))
return {};//leave this please
return {}; //leave this please
}
function mapStateToProps(state) {
return {
loading: !!state.media.loading,
media: state.media,
offre: state.ad,
//errors: errorMessageSelector(state),
user: state.user,
company: state.company
};
return {
loading: !!state.media.loading,
media: state.media,
offre: state.ad,
//errors: errorMessageSelector(state),
user: state.user,
company: state.company
};
}
export default withStyles(styles)(connect(mapStateToProps, { fetchCurrentUserRequest, fetchCompanyRequest, uploadMediaPres })(Etape2));
export default withStyles(styles)(connect(mapStateToProps, {fetchCurrentUserRequest, fetchCompanyRequest, uploadMediaPres})(Etape2));
+168 -176
View File
@@ -1,13 +1,23 @@
import React from 'react';
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 { withStyles } from '@material-ui/core/styles'
import { makeStyles } from '@material-ui/styles';
import { Button, Typography } from '@material-ui/core';
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 Snack from '../../components/atoms/snack';
import Snackbar from '@material-ui/core/Snackbar';
import { Alert, AlertTitle } from '@material-ui/lab';
import ReactHtmlParser from 'react-html-parser';
import getConfig from 'next/config'
import Card from '@material-ui/core/Card';
import CardActions from '@material-ui/core/CardActions';
import CardContent from '@material-ui/core/CardContent';
const styles = theme => ({
root: {
@@ -17,108 +27,6 @@ const styles = theme => ({
justifyContent: 'flex-start',
margin: theme.spacing(1),
},
rootStepperContainer: {
padding: theme.spacing(2, 12),
width: '25vw',
[theme.breakpoints.up('md')]: {
width: '7vw',
alignItems: 'center',
},
'& .MuiStep-horizontal, & .MuiStepLabel-iconContainer': {
padding: '0 !important',
[theme.breakpoints.up('md')]: {
padding: 'inherit',
},
},
'& .Mui-disabled .MuiStepConnector-line': {
borderColor: theme.palette.answer.main + '!important',
},
'& .Mui-disabled .MuiStepIcon-root': {
color: theme.palette.answer.main + '!important',
},
},
rootStepperDefault: {
'& .MuiStepConnector-line': {
borderColor: theme.palette.secondary.dark,
}
},
rootStepperActive: {
'& .MuiStepConnector-line': {
borderColor: theme.palette.primary.main,
}
},
headerContainer: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
padding: theme.spacing(2),
},
infoContainer: {
display: 'flex',
flexDirection: 'column',
padding: theme.spacing(0, 1.5),
},
logoContainer: {
display: 'flex',
alignItems: 'center',
width: 60,
height: 60,
backgroundColor: 'white',
boxShadow: '0px 6px 15px rgba(30, 35, 39, 0.10)',
border: 'solid 5px white',
borderRadius: '6px',
},
recorderContainer: {
//display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '400px',
},
helpContainer: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '400px',
},
logo: {
width: 'inherit',
height: '100%',
objectFit: 'contain',
borderRadius: '3px',
},
MuiAvatarImg: {
objectFit: 'contain',
},
title: {
fontSize: '1em',
fontWeight: '500',
},
companyName: {
fontSize: '0.9em',
fontWeight: '300',
},
textContainer: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
'& p': {
fontWeight: '300',
},
'& > p:nth-child(1)': {
'& span': {
fontWeight: '500',
}
},
'& > p:nth-child(2)': {
paddingBottom: theme.spacing(2),
borderBottom: '1px solid #E8E8E8',
'& span': {
fontWeight: '500',
color: theme.palette.primary.main,
}
},
},
rootButton: {
textTransform: 'inherit',
},
@@ -130,62 +38,71 @@ const styles = theme => ({
fontSize: '1.15em',
paddingLeft: theme.spacing(2),
},
iconHelpButton: {
fontSize: '1.5em',
fontWeight: '500',
padding: theme.spacing(0, 2),
color: theme.palette.secondary.important,
},
helpButton: {
color: theme.palette.primary.dark,
backgroundColor: 'transparent',
padding: theme.spacing(0, 2),
margin: theme.spacing(1),
width: '100%',
'& span.MuiButton-label': {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}
},
captureButton: {
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.main,
padding: theme.spacing(5, 2),
margin: theme.spacing(1),
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 4px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.14)',
'&:hover': {
backgroundColor: theme.palette.primary.main,
},
},
importButton: {
color: theme.palette.primary.main,
backgroundColor: theme.palette.secondary.main,
padding: theme.spacing(3, 2),
margin: theme.spacing(1),
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,
},
},
HelpKeyboardArrowRightIcon: {
fontSize: '2.5em',
color: theme.palette.primary.dark,
},
InputKeyboardArrowRightIcon: {
fontSize: '2.5em',
color: theme.palette.secondary.main,
},
InputKeyboardArrowDownIcon: {
fontSize: '2.5em',
color: theme.palette.primary.main,
},
importButton: {
color: theme.palette.primary.main,
backgroundColor: theme.palette.secondary.main,
padding: theme.spacing(3, 2),
margin: theme.spacing(1),
width: "400px",
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1' +
'px rgba(0, 0, 0, 0.14)',
'&:hover': {
color: theme.palette.primary.main,
backgroundColor: theme.palette.secondary.main,
}
},
});
const { publicRuntimeConfig } = getConfig();
class Etape3 extends React.Component {
state = {
loading: true,
openSnack: false,
cv:false,
errors: {},
success : {}
};
componentDidMount() {
localStorage.setItem('loginRedirect', window.location)
if(!!!localStorage.getItem('ttJWT'))
{
Router.push("/Login")
}
else
this.setState({
loading: false,
cvLink: this.props.user.cv
})
}
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
cvLink: nextProps.cvLink,
loading: nextProps.loading,
openSnack: !!!_.isEmpty(nextProps.errors),
errors: !!!nextProps.errors ? { errors: { message: "" } } : nextProps.errors,
})
this.state.cvLink = nextProps.cvLink;
if (nextProps.loading) {
const success = {};
success.message ="CV mis à jour";
console.log("CV mis à jour!!!")
if(this.state.cvLink) console.log(this.state.cvLink)
this.setState({ success });
}
}
inputFilesystemChange = (e) => {
this.uploadMediaCv(e)
}
@@ -199,40 +116,115 @@ class Etape3 extends React.Component {
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.props.user.cv !="") {
return (
<Fragment>
<Hidden>&nbsp;</Hidden>
<Hidden>&nbsp;</Hidden>
<Divider style={{width:400+"px"}}/>
<Hidden>&nbsp;</Hidden>
<Card variant="outlined" style={{width:400+"px"}}>
<CardActions>
<Button size="small">Mon CV numérique</Button>
</CardActions>
<CardContent>
<Typography>
<a href={publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.postedContentCv + this.state.cvLink} target="_blank">Lien vers le cv téléchargé</a><br />
{/* <a href="https://www.permatheque.fr/PDF/mansobufukuoka-larevolutiondunseulbrindepaille.pdf" target="_blank">lien</a> */}
</Typography>
</CardContent>
</Card>
</Fragment>
);
}
return "";
}
render() {
const { classes, company } = this.props;
const { loading } = this.state;
return (
<div>
<input
type="file"
accept=".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document, .pdf, .odt"
className={classes.input+' cypButtonImportVid'}
style={{ display: 'none' }}
id="import-button-file"
onChange={this.inputFilesystemChange}
/>
<label htmlFor="import-button-file">
<Button component="span" className={classes.importButton} classes={{ root: classes.rootButton }}>
<img alt="talents-tube" src='/statique/images/Import.svg' className={classes.iconButton} />
<Typography align="left" className={classes.textButton}>
J'<span className={classes.underlined}>importe</span> mon CV au format PDF
</Typography>
<KeyboardArrowDownIcon className={ classes. InputKeyboardArrowDownIcon }/>
</Button>
</label>
</div>
<Fragment>
{ loading ?
<Loader /> :
<Fragment>
{this.AfficherSuccess()}
<input
type="file"
accept=".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document, .pdf, .odt"
className={classes.input+' cypButtonImportVid'}
style={{ display: 'none' }}
id="import-button-file"
onChange={this.inputFilesystemChange}
/>
<label htmlFor="import-button-file">
<Button component="span" className={classes.importButton} classes={{ root: classes.rootButton }}>
<img alt="talents-tube" src='/statique/images/Import-cv-candidat.svg' className={classes.iconButton} />
<Typography className={classes.textButton}>
J'<span className={classes.underlined}>importe</span> mon CV au format PDF
</Typography>
<KeyboardArrowDownIcon className={ classes. InputKeyboardArrowDownIcon }/>
</Button>
</label>
{this.AfficherLienCv()}
</Fragment>
}
</Fragment>
);
}
}
Etape3.getInitialProps = function (context) {
const { adId, companyId } = context.query
const {res} = context
//TODO :really needed ?
context.store.dispatch(fetchCurrentUserRequest())
if(!!adId)
context.store.dispatch(fetchAdRequest(adId))
else if(!!companyId)
context.store.dispatch(fetchCompanyRequest(companyId))
return {};//leave this please
}
function mapStateToProps(state) {
// console.log("mapStateToProps")
// console.log(state.loading)
// console.log(state.user)
// console.log(state.media.message)
return {
user: state.user ,
cvLink : state.media.message,
loading: !!state.media.loading,
media: state.media,
offre: state.ad,
cv : true,
//errors: errorMessageSelector(state),
user: state.user,
company: state.company
+414 -277
View File
@@ -1,306 +1,419 @@
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import moment from 'moment';
import AccountStep from "../../components/organisms/AccountStep";
// import AccountStep from "../../components/organisms/AccountStep";
import AccountEtape1 from '../organisms/AccountEtape1';
import AccountEtape2 from '../organisms/AccountEtape2';
import AccountEtape3 from '../organisms/AccountEtape3';
import { makeStyles } from '@material-ui/styles';
import AccountEtape3 from '../organisms/AccountEtape3';
import {withStyles} from '@material-ui/core/styles';
// import Switch from '@material-ui/core/Switch';
import PhoneIcon from '@material-ui/icons/Phone';
import MailIcon from '@material-ui/icons/Mail';
import PublicIcon from '@material-ui/icons/Public';
import DuoIcon from '@material-ui/icons/Duo';
import LinkedInIcon from '@material-ui/icons/LinkedIn';
import Facebook from '@material-ui/icons/Facebook';
// import FormGroup from '@material-ui/core/FormGroup'; import FormControlLabel
// from '@material-ui/core/FormControlLabel'; import FormControl from
// '@material-ui/core/FormControl';
import {updateUserRequest, updateUserPictureRequest} from '../../actions/user'
import {makeStyles} from '@material-ui/styles';
import {connect} from 'react-redux'
import getConfig from 'next/config'
import BottomNavigation from '@material-ui/core/BottomNavigation';
// import BottomNavigationAction from
// '@material-ui/core/BottomNavigationAction';
import RefreshIcon from '@material-ui/icons/Refresh';
// import FavoriteIcon from '@material-ui/icons/Favorite'; import LocationOnIcon
// from '@material-ui/icons/LocationOn';
import Box from '@material-ui/core/Box';
import {
Card,
CardActions,
CardContent,
Avatar,
Typography,
Divider,
Button,
LinearProgress,
Stepper,
Step,
StepLabel,
StepContent,
StepButton,
Paper,
Grid
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)
},
uploadButton: {
marginRight: theme.spacing(2)
},
button: {
marginTop: theme.spacing(1),
marginRight: theme.spacing(1),
},
actionsContainer: {
marginBottom: theme.spacing(2),
},
resetContainer: {
padding: theme.spacing(3),
},
root: {},
details: {
display: 'flex'
},
avatar: {
marginLeft: 'auto',
height: 110,
width: 100,
flexShrink: 0,
flexGrow: 0
},
progress: {
marginTop: theme.spacing(2)
},
information: {
display: 'flex',
flexDirection: 'column',
backgroundColor: theme.palette.primary.main,
[
theme
.breakpoints
.up('md')
]: {
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-start',
justifyContent: 'space-around',
backgroundColor: theme.palette.primary.main,
padding: theme.spacing(7, 7)
},
'& a': {
textDecoration: 'none'
}
},
texteBlanc: {
color: "#fff"
},
uploadButton: {
marginRight: theme.spacing(2)
},
button: {
marginTop: theme.spacing(1),
marginRight: theme.spacing(1)
},
actionsContainer: {
marginBottom: theme.spacing(2)
},
resetContainer: {
padding: theme.spacing(3)
}
}));
function getSteps() {
return ['Informations personnelles', 'Vidéo de présentation', 'Expériences professionnelles'];
return ['Informations personnelles', 'Vidéo de présentation', 'Expériences professionnelles'];
}
function getStepContent(step) {
switch (step) {
case 0:
return <AccountEtape1 ></AccountEtape1>;
case 1:
return <AccountEtape2></AccountEtape2>;
case 2:
return <AccountEtape3></AccountEtape3>;
default:
return 'Unknown step';
}
switch (step) {
case 0:
return <AccountEtape1 ></AccountEtape1>;
case 1:
return <AccountEtape2></AccountEtape2>;
case 2:
return <AccountEtape3></AccountEtape3>;
default:
return 'Unknown step';
}
}
const AccountProfile = props => {
const { className, ...rest } = props;
const {
className,
user,
...rest
} = props;
const logoUrl = user.picture;
const classes = useStyles();
const classes = useStyles();
// const user = { name: 'Laurent Laniau', city: 'Questembert', country:
// 'France', timezone: '', avatar: '/images/avatars/avatar_11.png' };
const {publicRuntimeConfig} = getConfig()
const [activeStep,
setActiveStep] = React.useState(0);
const [completed,
setCompleted] = React.useState(new Set());
const [skipped,
setSkipped] = React.useState(new Set());
const [state,
setState] = React.useState({checkedA: true, checkedB: true});
const steps = getSteps();
const user = {
name: 'Laurent Laniau',
city: 'Questembert',
country: 'France',
timezone: '',
avatar: '/images/avatars/avatar_11.png'
};
const totalSteps = () => {
return getSteps().length;
};
const [activeStep, setActiveStep] = React.useState(0);
const [completed, setCompleted] = React.useState(new Set());
const [skipped, setSkipped] = React.useState(new Set());
const steps = getSteps();
const isStepOptional = (step) => {
return step === 4;
};
const totalSteps = () => {
return getSteps().length;
};
const handleSkip = () => {
if (!isStepOptional(activeStep)) {
// You probably want to guard against something like this it should never occur
// unless someone's actively trying to break something.
throw new Error("You can't skip a step that isn't optional.");
}
const isStepOptional = (step) => {
return step === 4;
};
setActiveStep((prevActiveStep) => prevActiveStep + 1);
setSkipped((prevSkipped) => {
const newSkipped = new Set(prevSkipped.values());
newSkipped.add(activeStep);
return newSkipped;
});
};
const handleSkip = () => {
if (!isStepOptional(activeStep)) {
// You probably want to guard against something like this
// it should never occur unless someone's actively trying to break something.
throw new Error("You can't skip a step that isn't optional.");
}
const skippedSteps = () => {
return skipped.size;
};
setActiveStep((prevActiveStep) => prevActiveStep + 1);
setSkipped((prevSkipped) => {
const newSkipped = new Set(prevSkipped.values());
newSkipped.add(activeStep);
return newSkipped;
});
};
const completedSteps = () => {
return completed.size;
};
const skippedSteps = () => {
return skipped.size;
};
const allStepsCompleted = () => {
return completedSteps() === totalSteps() - skippedSteps();
};
const completedSteps = () => {
return completed.size;
};
const isLastStep = () => {
return activeStep === totalSteps() - 1;
};
const allStepsCompleted = () => {
return completedSteps() === totalSteps() - skippedSteps();
};
const handleNext = () => {
const newActiveStep = isLastStep() && !allStepsCompleted()
? // It's the last step, but not all steps have been completed
// find the first step that has been completed
steps.findIndex((step, i) => !completed.has(i))
: activeStep + 1;
const isLastStep = () => {
return activeStep === totalSteps() - 1;
};
setActiveStep(newActiveStep);
};
const handleNext = () => {
const newActiveStep =
isLastStep() && !allStepsCompleted()
? // It's the last step, but not all steps have been completed
// find the first step that has been completed
steps.findIndex((step, i) => !completed.has(i))
: activeStep + 1;
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
};
setActiveStep(newActiveStep);
};
const handleStep = (step) => () => {
console.log("step");
console.log(step);
setActiveStep(step);
};
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
};
const handleComplete = () => {
const newCompleted = new Set(completed);
newCompleted.add(activeStep);
setCompleted(newCompleted);
const handleStep = (step) => () => {
console.log("step");
console.log(step);
setActiveStep(step);
};
const handleComplete = () => {
const newCompleted = new Set(completed);
newCompleted.add(activeStep);
setCompleted(newCompleted);
/**
/**
* Sigh... it would be much nicer to replace the following if conditional with
* `if (!this.allStepsComplete())` however state is not set when we do this,
* thus we have to resort to not being very DRY.
*/
if (completed.size !== totalSteps() - skippedSteps()) {
handleNext();
if (completed.size !== totalSteps() - skippedSteps()) {
handleNext();
}
};
const handleReset = () => {
setActiveStep(0);
setCompleted(new Set());
setSkipped(new Set());
};
const isStepSkipped = (step) => {
return skipped.has(step);
};
const handleChange = (event) => {
setState({
...state,
[event.target.name]: event.target.checked
});
};
function isStepComplete(step) {
return completed.has(step);
}
function refresh() {
document
.location
.reload(true);
console.log("refresh")
}
};
const handleReset = () => {
setActiveStep(0);
setCompleted(new Set());
setSkipped(new Set());
};
return (
<Grid
container
spacing={4}
direction="row"
justify="space-between"
alignItems="flex-start">
<Grid item lg={3} md={6} xl={4} xs={12}>
<Card {...rest} className={clsx(classes.root, className)}>
<CardContent>
<div id="fb-root"></div>
<script
async
defer
crossorigin="anonymous"
src="https://connect.facebook.net/fr_FR/sdk.js#xfbml=1&version=v8.0&appId=2332071840142634&autoLogAppEvents=1"
nonce="O28M4TTm"></script>
<div className={classes.details}>
<div>
<Typography gutterBottom variant="h5">
{user.lastname}
&nbsp; {user.firstname}
<a href="#" onClick={refresh}><RefreshIcon className={classes.menuButton}/></a>
</Typography>
<Typography
className={classes.locationText}
color="textSecondary"
variant="body1">
<MailIcon className={classes.menuButton}/>
: {user.email}<br/>
<PhoneIcon className={classes.menuButton}/>
: {user.phone}<br/>
<LinkedInIcon className={classes.menuButton}/>
: {(user.linkedin && user.linkedin != '' && user.linkedin != 'null')
? <a href={user.linkedin} target="_blank">Lien sur mon linkendIn</a>
: 'Non renseigné'}<br/>
<PublicIcon className={classes.menuButton}/>
: {(user.website && user.website != '' && user.website != 'null')
? <a href={user.website} target="_blank">Lien sur mon site</a>
: 'Non renseigné'}<br/>
</Typography>
</div>
{/* <Avatar
className={classes.avatar}
src={publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.postedContentUrl + logoUrl}/> */}
</div>
<div>
<Box m={3}/>
<Divider/>
<Box m={3}/>
<Typography
className={classes.locationText}
color="textSecondary"
variant="body1">
<DuoIcon className={classes.menuButton}/>
: {(user.alias && user.alias != '' && user.alias != 'null')
? <a
href={publicRuntimeConfig.cvThequeUrl + "talent/" + user.alias}
target="_blank">Voir mon profil TalentsTube
</a>
: 'Non renseigné'}<br/>
<div
class="fb-share-button"
data-href={publicRuntimeConfig.cvThequeUrl + "talent/" + user.alias}
data-layout="button_count"
data-size="small">
const isStepSkipped = (step) => {
return skipped.has(step);
};
<Facebook className={classes.menuButton}/>
:
<a
target="_blank"
href={"https://www.facebook.com/sharer/sharer.php?u=" + publicRuntimeConfig.cvThequeUrl + "talent/" + user.alias + "%2F&amp;src=sdkpreparse"}
class="fb-xfbml-parse-ignore"> Partager mon profil
</a>
</div>
</Typography>
</div>
{/* <div className={classes.progress}>
<Typography variant="body1">Etat du Profil: 70%</Typography>
<LinearProgress value={70} variant="determinate"/>
</div> */}
function isStepComplete(step) {
return completed.has(step);
}
</CardContent>
<Box m={2}/>
<Divider/>
<Box m={2}/>
<div className={classes.information}>
<Typography className={classes.texteBlanc} align="left"></Typography>
</div>
{/* <CardActions>
<Button className={classes.uploadButton} color="primary" variant="text">
Remplacer une photo de profil
</Button>
<Button variant="text">Supprimer photo de profil</Button>
</CardActions> */}
<Box m={1}/>
<Divider/>
{/* <CardContent>
<Typography variant="body1"></Typography>
<FormControlLabel
value="end"
control={< Switch checked = {
state.checkedA
}
onChange = {
handleChange
}
name = "checkedA" color = "primary" />}
label="Je souhaite afficher mon profil sur la CV Vidéothèque Talents Tube"
labelPlacement="start"/>
return (
<Grid
container
spacing={4}
direction="row"
justify="space-between"
alignItems="flex-start">
<Grid
item
lg={3}
md={6}
xl={4}
xs={12}>
<Card
{...rest}
className={clsx(classes.root, className)}
>
<CardContent>
<div className={classes.details}>
<div>
<Typography
gutterBottom
variant="h2"
>
Laurent Laniau
</Typography>
<Typography
className={classes.locationText}
color="textSecondary"
variant="body1"
>
{user.city}, {user.country}
</Typography>
<Typography
className={classes.dateText}
color="textSecondary"
variant="body1"
>
{moment().format('HH:mm')}
</Typography>
</div>
<Avatar
className={classes.avatar}
src={user.avatar}
/>
</div>
<div className={classes.progress}>
<Typography variant="body1">Etat du Profil: 70%</Typography>
<LinearProgress
value={70}
variant="determinate"
/>
</div>
</CardContent>
<Divider />
<CardActions>
<Button
className={classes.uploadButton}
color="primary"
variant="text"
>
Télécharger une photo de profil
</Button>
<Button variant="text">Supprimer photo de profil</Button>
</CardActions>
</CardContent> */}
<Stepper nonLinear activeStep={activeStep} orientation="vertical">
{steps.map((label, index) => {
const stepProps = {};
const buttonProps = {};
if (isStepOptional(index)) {
buttonProps.optional = <Typography variant="caption">Optional</Typography>;
}
if (isStepSkipped(index)) {
stepProps.completed = false;
}
return (
<Step key={label} className={classes.actionsContainer} {...stepProps}>
<StepButton
onClick={handleStep(index)}
completed={isStepComplete(index)}
{...buttonProps}
>
{label}
</StepButton>
</Step>
);
})}
</Stepper>
<CardActions>
<Stepper nonLinear activeStep={activeStep} orientation="vertical">
{steps.map((label, index) => {
const stepProps = {};
const buttonProps = {};
if (isStepOptional(index)) {
buttonProps.optional = <Typography variant="caption">Optional</Typography>;
}
if (isStepSkipped(index)) {
stepProps.completed = false;
}
return (
<Step key={label} className={classes.actionsContainer} {...stepProps}>
<StepButton
onClick={handleStep(index)}
completed={isStepComplete(index)}
{...buttonProps}>
{label}
</StepButton>
</Step>
);
})}
</Stepper>
</CardActions>
<Divider/>
<div>
{allStepsCompleted() ? (
<div>
<Typography className={classes.instructions}>
All steps completed - you&apos;re finished
</Typography>
<Button onClick={handleReset}>Reset</Button>
</div>
) : (
<div>
<div>
<Button disabled={activeStep === 0} onClick={handleBack} className={classes.button}>
Back
</Button>
<Button
variant="contained"
color="primary"
onClick={handleNext}
className={classes.button}
>
Next
</Button>
{isStepOptional(activeStep) && !completed.has(activeStep) && (
<div>
<div>
<div>
{/* {isStepOptional(activeStep) && !completed.has(activeStep) && (
<Button
variant="contained"
color="primary"
@@ -309,9 +422,9 @@ const AccountProfile = props => {
>
Skip
</Button>
)}
)} */}
{activeStep !== steps.length &&
{/* {activeStep !== steps.length &&
(completed.has(activeStep) ? (
<Typography variant="caption" className={classes.completed}>
Step {activeStep + 1} already completed
@@ -320,29 +433,53 @@ const AccountProfile = props => {
<Button variant="contained" color="primary" onClick={handleComplete}>
{completedSteps() === totalSteps() - 1 ? 'Finish' : 'Complete Step'}
</Button>
))}
</div>
</div>
)}
</div>
))} */}
</div>
</div>
</Card>
</Grid>
<Grid
item
lg={9}
md={6}
xl={8}
xs={12}>
{getStepContent(activeStep)}
</Grid>
</Grid>
);
</div>
<Box m={2}/>
<CardContent>
<BottomNavigation className={classes.stickToBottom}>
<Button
disabled={activeStep === 0}
onClick={handleBack}
className={classes.button}>
Etape précédente
</Button>
<Button
variant="contained"
color="primary"
onClick={handleNext}
className={classes.button}>
Etape suivante
</Button>
{/* <BottomNavigationAction label="Recents" icon={< RestoreIcon />}/>
<BottomNavigationAction label="Favorites" icon={< FavoriteIcon />}/>
<BottomNavigationAction label="Nearby" icon={< LocationOnIcon />}/> */}
</BottomNavigation>
</CardContent>
</Card>
</Grid>
<Grid item lg={9} md={6} xl={8} xs={12}>
{getStepContent(activeStep)}
</Grid>
</Grid>
);
};
AccountProfile.propTypes = {
className: PropTypes.string
className: PropTypes.string
};
function mapStateToProps(state, ownProps) {
return {
user: state.user,
loading: !!state.user.loading,
errors: state.user.errors || ownProps.errors
};
}
export default AccountProfile;
export default withStyles(styles)(connect(mapStateToProps, {updateUserRequest})(AccountProfile))
@@ -20,7 +20,7 @@ const useStyles = makeStyles(() => ({
root: {}
}));
const AccountDetails = props => {
const AccountVideoPres = props => {
const { className, ...rest } = props;
const classes = useStyles();
@@ -35,8 +35,8 @@ const AccountDetails = props => {
);
};
AccountDetails.propTypes = {
AccountVideoPres.propTypes = {
className: PropTypes.string
};
export default AccountDetails;
export default AccountVideoPres;
+10 -23
View File
@@ -39,6 +39,7 @@ import { withRouter } from "next/router";
import ActiveLink from "./../atoms/Activelink";
import axios from 'axios';
import setAuthorizationHeader from "../../data/setAuthorizationHeader";
import getConfig from 'next/config'
const styles = theme => ({
root: {
@@ -329,7 +330,7 @@ class Header extends React.Component {
render() {
const { classes } = this.props;
const { publicRuntimeConfig } = getConfig();
return (
@@ -385,7 +386,7 @@ class Header extends React.Component {
</div>
<div>
<div className={classes.blogLinkGroup}>
<a href="https://blog.talentstube.com" className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<a href={publicRuntimeConfig.blogUrl} className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<NotesIcon className={classes.icon} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Blog'>
</ListItemText>
@@ -393,7 +394,7 @@ class Header extends React.Component {
</a>
</div>
<div className={classes.recruteurLinkGroup}>
<a href="https://www.talentstube.com/faire-offre-emploi-video" className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<a href={publicRuntimeConfig.symphonyUrl } className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<SupervisorAccountIcon className={classes.icon} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Recruteurs'>
</ListItemText>
@@ -451,7 +452,7 @@ class Header extends React.Component {
<Divider light={true} />
<div className={classes.linkGroup}>
<a href="https://www.talentstube.com/faire-offre-emploi-video" className={classes.lightMenuItem}><ListItem classes={{ primary: classes.ListItemText }} classes={{ root: classes.rootListItemIcon }}>
<a href={publicRuntimeConfig.symphonyUrl + "/faire-offre-emploi-video"} className={classes.lightMenuItem}><ListItem classes={{ primary: classes.ListItemText }} classes={{ root: classes.rootListItemIcon }}>
<WorkOutlineIcon className={classes.icon} />
<ListItemText primary='Connexion recruteurs'>
</ListItemText>
@@ -463,7 +464,7 @@ class Header extends React.Component {
{!!!this.props.loading && !!this.props.fetched &&
<Fragment>
{this.props.user.picture ?
<img alt="talents-tube" src={`http://localhost/uploads/img/${this.props.user.picture}`} className={classes.menuAvatar} />
<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} />
}
@@ -487,27 +488,13 @@ class Header extends React.Component {
</ListItemText>
</ListItem></a>
</Link>
<Link href="" >
<a onClick={this.onRedirectAccount} className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<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="" >
<a onClick={this.onRedirectAccount} className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<PermContactCalendar className={classes.icon} />
<ListItemText primary='Mon profil'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="" >
<a onClick={this.onRedirectAccount} className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<VideoCam className={classes.icon} />
<ListItemText primary='Mon CV vidéo'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="/Parametres" >
<a className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
@@ -559,7 +546,7 @@ class Header extends React.Component {
</ActiveLink>
<ActiveLink activeClassName={classes.active} href="/Entreprises" >
<a className={classes.desktopMenuItem}>
<ListItemText primary='Nos entreprises !'>
<ListItemText primary='Nos entreprises'>
</ListItemText>
</a>
</ActiveLink>
@@ -618,7 +605,7 @@ class Header extends React.Component {
</section>
<section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection3}>
<a href="https://www.talentstube.com/faire-offre-emploi-video" className={classes.desktopMenuItem}>
<a href={publicRuntimeConfig.symphonyUrl + "/faire-offre-emploi-video"} className={classes.desktopMenuItem}>
<ListItemText primary='Espace recruteurs'>
</ListItemText>
<ArrowForward className={classes.icon} />
+22 -10
View File
@@ -18,6 +18,8 @@ import Link from 'next/link'
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
import VideoVimeo from '../atoms/VideoVimeo'
import OgHead from '../atoms/OgHead'
import JobPosting from '../atoms/JobPosting'
import Moment from 'react-moment';
const styles = theme => ({
primary: {
@@ -155,7 +157,7 @@ const styles = theme => ({
objectFit: 'contain',
},
title: {
fontSize: '1em',
fontSize: '1.3em',
fontWeight: '500',
[theme.breakpoints.up('md')]: {
paddingTop: theme.spacing(2),
@@ -163,7 +165,7 @@ const styles = theme => ({
},
offreTitle: {
[theme.breakpoints.up('md')]: {
fontSize: '1.2em',
fontSize: '1.3em',
fontWeight: '600',
},
},
@@ -190,7 +192,7 @@ const styles = theme => ({
textAlign: 'center',
},
companyName: {
fontSize: '0.9em',
fontSize: '1.3em',
fontWeight: '300',
[theme.breakpoints.up('md')]: {
fontSize: '1em',
@@ -209,18 +211,18 @@ const styles = theme => ({
},
iconTextIcon: {
color: theme.palette.offerlistitem.icon,
fontSize: '1em',
fontSize: '1.3em',
},
iconTextText: {
fontWeight: 'lighter',
color: theme.palette.offerlistitem.text,
fontSize: '0.7em',
fontSize: '1em',
paddingLeft: theme.spacing(1),
},
iconTextTextDesktop: {
fontWeight: 'lighter',
color: theme.palette.offerlistitem.text,
fontSize: '0.7em',
fontSize: '1em',
paddingLeft: theme.spacing(1),
width: '100%',
},
@@ -304,11 +306,20 @@ function OffreDetail(props) {
return (
<Fragment>
<OgHead seo_title={offre.title}
seo_description={offre.description}
seo_url={socialShareUrl}
image={imgUrlDesktop}
></OgHead>
<JobPosting job_title={offre.title}
job_description={offre.description}
job_brand= {offre.company.brand_name && offre.company.brand_name}
job_brand_link= {entrepriseLink}
job_title = {offre.title}
job_location = {offre.location.gmap_address.formatted_address}
job_date = {offre.published_at}
></JobPosting>
{offre.video && (
<Fragment>
<Hidden smDown>
@@ -319,17 +330,17 @@ function OffreDetail(props) {
<div className={classes.logoContainer}>
<Avatar className={classes.logo} classes={{ img: classes.MuiAvatarImg }}
src={logoUrl} alt="companyLogo" />
src={logoUrl} alt={offre.company.brand_name && offre.company.brand_name} />
</div>
</a>
<div className={classes.infoContainer}>
<Typography gutterBottom className={classes.offreTitle}>
{offre.title}
{offre.title} {/*- publié le <Moment format="DD/MM/YYYY" date={offre.published_at} /> */}
</Typography>
<a href={entrepriseLink} >
<Typography gutterBottom variant="subtitle1" className={classes.companyName}>
{offre.company.brand_name && offre.company.brand_name}
{offre.company.brand_name ? offre.company.brand_name : ""}
</Typography>
</a>
{offre.is_promoted && (
@@ -390,6 +401,7 @@ function OffreDetail(props) {
<section className={classes.IconTextContainerDesktop}>
<IconTextInline classes={{ icon: classes.iconTextIcon, text: classes.iconTextText }} variant="assignment" text={offre.extra.contract_type} />
<IconTextInline classes={{ icon: classes.iconTextIcon, text: classes.iconTextText }} variant="location_on" text={offre.location.gmap_address.formatted_address} />
{offre.beneficiaire && (<IconTextInline classes={{ icon: classes.iconTextIcon, text: classes.iconTextText }} variant="business" text={offre.beneficiaire} /> )}
</section>
</Hidden>
<SimpleCollapse>
@@ -437,7 +449,7 @@ function OffreDetail(props) {
<a href={entrepriseLink}>
<div className={classes.discoverContainerImage}>
<img src={isWidthUp('sm', props.width) ? imgUrlDesktop : imgUrl} alt="company" />
<img src={isWidthUp('sm', props.width) ? imgUrlDesktop : imgUrl} alt={offre.company.brand_name && offre.company.brand_name} />
<KeyboardArrowleftIcon className={classes.iconPlay} />
</div>
</a>
+12 -9
View File
@@ -51,14 +51,15 @@ const styles = theme => ({
alignItems: 'flex-start',
padding: theme.spacing(2),
width: '75%',
minHeight: '200px',
},
jobTitle: {
fontSize: '1em',
fontSize: '1.2em',
fontWeight: 'bold',
color: theme.palette.offerlistitem.title,
},
companyTitle: {
fontSize: '0.8em',
fontSize: '1.2em',
fontWeight: '300',
color: theme.palette.offerlistitem.title,
},
@@ -96,11 +97,11 @@ const styles = theme => ({
},
iconTextIcon: {
color: theme.palette.offerlistitem.icon,
fontSize: '0.8em',
fontSize: '1.2em',
},
iconTextText: {
color: theme.palette.offerlistitem.text,
fontSize: '0.6em',
fontSize: '1em',
paddingLeft: theme.spacing(1),
},
chip: {
@@ -144,14 +145,14 @@ class OffreRowComponent extends React.Component {
variant="h6"
component="h3"
className={classes.jobTitle}>
{rowData.title}
{rowData.title}
</Typography>
<Typography
variant="headline"
variant="h6"
component="h4"
component="h3"
className={classes.companyTitle}>
{!!companyR.brand_name?companyR.brand_name:"-"}
{companyR.brand_name ? companyR.brand_name : "Non renseigné"}
</Typography>
<div>
{rowData.is_promoted && (
@@ -160,8 +161,10 @@ class OffreRowComponent extends React.Component {
{!rowData.is_promoted && (
<Fragment>
<IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="location_on" text={rowData.extra.contract_type} />
<IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="business_center" text={rowData.location.gmap_address.formatted_address} />
<IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="business_center" text={rowData.extra.contract_type} />
<IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="location_on" text={rowData.location.gmap_address.formatted_address} />
{rowData.beneficiaire ? <IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="business" text={rowData.beneficiaire} /> : ""}
</Fragment>
)}
+10 -2
View File
@@ -130,7 +130,15 @@ class Recorder extends Component {
}
render() {
const { classes } = this.props;
const { classes, titreBouton } = this.props;
let titreButtonLabel= "Envoyer";
if (titreBouton) {
titreButtonLabel = titreBouton;
console.log("titre");
console.log(titreButtonLabel);
}
return (
<div>
<div data-vjs-player>
@@ -140,7 +148,7 @@ class Recorder extends Component {
{ this.state.canSend && <Button type="submit" variant="outlined" color="primary"
className={classes.button}
onClick={this.sendBlob}>
Envoyer
{titreButtonLabel}
</Button>}
</div>
</div>
@@ -8,6 +8,7 @@ import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
import VideoVimeo from '../atoms/VideoVimeo'
const styles = theme => ({
root: {
position: 'relative',
@@ -169,7 +170,7 @@ class ShortVideoHooker extends Component {
return (
<div className={classes.video}>
<VideoVimeo classesOverride={ classes.videoVimeo } videoId={videoList[this.state.i].vimeoId} title={videoList[this.state.i].title}
{/* <VideoVimeo classesOverride={ classes.videoVimeo } videoId={videoId}
options={`?byline=0&title=0&background=1&autoplay=1&mute=1`} />
<section className={classes.text}>
<Typography gutterBottom
@@ -199,7 +200,7 @@ class ShortVideoHooker extends Component {
>
Voir l'offre
</Button>
</Link>
</Link> */}
</div>
)
}
+1 -1
View File
@@ -113,7 +113,7 @@ class Tile extends React.Component {
/>
<KeyboardArrowleftIcon className={classes.iconPlay} />
<div className={classes.logoContainer}>
<Avatar className={classes.logo} src={logoUrl} alt="company"/>
<Avatar className={classes.logo} src={logoUrl} alt={rowData.title}/>
</div>
{ children }
</CardContent>
+8 -4
View File
@@ -10,11 +10,11 @@ const styles = theme => ({
flexDirection: 'column',
justifyContent: 'space-between',
position: 'absolute',
top: '51%',
top: '44%',
width: '100%',
},
companyTitle: {
fontSize: '0.8em',
fontSize: '1em',
fontWeight: '100',
padding: theme.spacing(0, 2),
marginTop: '4vh',
@@ -24,7 +24,7 @@ const styles = theme => ({
},
},
jobTitle: {
fontSize: '1em',
fontSize: '1.2em',
padding: theme.spacing(0, 2),
minHeight: '8vh',
[theme.breakpoints.up('lg')]: {
@@ -59,7 +59,7 @@ class TileOffre extends React.Component {
component="h4"
align="center"
className={classes.companyTitle}>
{tile.company.brand_name && tile.company.brand_name}
{tile.company.brand_name && tile.company.brand_name}
</Typography>
<Typography
gutterBottom
@@ -82,6 +82,10 @@ class TileOffre extends React.Component {
{tile.extra && tile.extra.contract_type &&
<IconText classes={{ root: classes.rootIconText }} variant="assignment" text={tile.extra.contract_type} />
}
{tile.beneficiaire &&
<IconText classes={{ root: classes.rootIconText }} variant="business" text={tile.beneficiaire} />
}
</section>
</Fragment>
);
+1 -1
View File
@@ -73,7 +73,7 @@ export default {
//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 = null, isEmphasis = null }) => {
fetchAds: ({ limit = null, order = "", keyword = "", offset = 1, status = 'PUBLISHED', isPromoted = false, isEmphasis = false }) => {
isPromoted = isPromoted !== null ? isPromoted * 1 : isPromoted;
isEmphasis = isEmphasis !== null ? isEmphasis * 1 : isEmphasis;
+8 -5
View File
@@ -33,18 +33,21 @@ module.exports = withPlugins(
}
],
importScripts:
['/static/js/Edeclic-service-worker.js',
'/static/js/backgroundSync-sw.js'
['/statique/js/Edeclic-service-worker.js',
'/statique/js/backgroundSync-sw.js'
]
},
}],
[{
publicRuntimeConfig: {
symphonyUrl: 'https://www.talentstube.com',
frontServerUrl: 'https://pp.app.talentstube.com',
adListDefaultUrl: '/static/images/default/default_picture_company.svg',
symphonyUrl: 'https://recruteur.talentstube.com',
blogUrl: 'https://blog.talentstube.com',
frontServerUrl: 'https://www.talentstube.com',
cvThequeUrl: 'https://cvtheque.talentstube.com/',
adListDefaultUrl: '/statique/images/default/default_picture_company.svg',
cachedMediaUrl: '/media/cache/profile_thumb/uploads/img/',
postedContentUrl: '/uploads/img/',
postedContentCv: '/uploads/cv/',
ReCAPTCHA: {
"siteKey": "6LdyqLwUAAAAADKI5uC7d5W9VqVgzd8VEmMU2Yi-"
},
+16912
View File
File diff suppressed because it is too large Load Diff
+5 -2
View File
@@ -7,8 +7,8 @@
},
"dependencies": {
"@blunck/next-alias": "^1.0.0",
"@material-ui/core": "^4.2.0",
"@material-ui/icons": "^3.0.1",
"@material-ui/core": "^4.9.10",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "^4.0.0-alpha.56",
"@ostai/next-css": "^1.0.2",
"axios": "^0.18.0",
@@ -34,6 +34,7 @@
"next-optimized-images": "^1.4.1",
"next-redux-saga": "^4.0.2",
"next-redux-wrapper": "^3.0.0-alpha.2",
"next-seo": "^4.7.3",
"next-transpile-modules": "^2.3.1",
"node-mailjet": "^3.3.1",
"nodemailer": "^4.6.8",
@@ -45,11 +46,13 @@
"passport-oauth2": "https://github.com/Huaoe/passport-oauth2.git",
"prop-types": "latest",
"react": "^16.9.0",
"react-ad-block-detect": "^1.0.1",
"react-dom": "^16.9.0",
"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-redux": "^7.0.3",
"react-swipeable-views": "^0.13.3",
"reactstrap": "^6.4.0",
+1
View File
@@ -147,6 +147,7 @@ class Candidature extends React.Component {
<LayoutCandidature>
<Head>
<title key="title">Candidature</title>
<meta name="robots" content="noindex, nofollow"></meta>
</Head>
<Fragment>
<div className={classes.container}>
+1
View File
@@ -45,6 +45,7 @@ class Candidatures extends React.Component {
<LayoutGrid backLink="/">
<Head>
<title key="title">Candidatures</title>
<meta name="robots" content="noindex, nofollow"></meta>
</Head>
{/* TODO */}
+1 -1
View File
@@ -178,7 +178,7 @@ class Confidentialite extends Component {
<a href="http://windows.microsoft.com/fr-fr/internet-explorer/delete-manage-cookies#ie=ie-11" className={classes.link} target="_blank">Internet Explorer</a><br />
`
Pour plus dinformations sur les cookies et la façon de les gérer, nous vous recommandons de consulter le site `} <a href="http://www.youronlinechoices.com/fr/" className={classes.link} target="_blank">www.youronlinechoices.com</a>{`, développé par lorganisme EDAA (European Interactive Digital Advertising Alliance).
Pour plus dinformations sur les cookies et la façon de les gérer, nous vous recommandons de consulter le site ` <a href="http://www.youronlinechoices.com/fr/" className={classes.link} target="_blank">www.youronlinechoices.com</a>{`, développé par lorganisme EDAA (European Interactive Digital Advertising Alliance).
`
}
</Typography>
+1 -1
View File
@@ -31,7 +31,7 @@ class Conseils extends React.Component {
<title>Quelques conseils !</title>
<meta name="description" content="Quelques conseils !" />
<meta key="robots" name="robots" content="noindex, nofollow"></meta>
<link rel="canonical" href="https://app.talentstube.com" />
</Head>
<section className={classes.container}>
<VideoVimeo videoId='356411947' autoplay='1' />
+2 -2
View File
@@ -357,9 +357,9 @@ class Entreprise extends React.Component {
render() {
const { classes, company } = this.props;
const logoUrl = (company.logo ? publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.cachedMediaUrl + company.logo : "https://www.talentstube.com/img/default_picture_svg")
const logoUrl = (company.logo ? publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.cachedMediaUrl + company.logo : publicRuntimeConfig.symphonyUrl + "/img/default_picture_svg")
const DefaultUrl = "https://www.talentstube.com/img/default_picture_svg"
const DefaultUrl = publicRuntimeConfig.symphonyUrl + "/img/default_picture_svg"
const imgUrl = (company.presentation_video && company.presentation_video.thumbnails[0] && company.presentation_video.thumbnails[0].sizes[2]) ? company.presentation_video.thumbnails[0].sizes[2].link : DefaultUrl
const offre = (company.count_ads == 1) ? company.count_ads + ' offre' : company.count_ads + ' offres'
+3 -2
View File
@@ -69,7 +69,7 @@ class Entreprises extends React.Component {
const { publicRuntimeConfig } = getConfig();
const socialShareUrl = typeof window !== 'undefined' ? window.location
: publicRuntimeConfig.frontServerUrl + `/Entreprises`;
const DefaultUrl = "https://www.talentstube.com/img/default_picture_svg"
const DefaultUrl = publicRuntimeConfig.symphonyUrl + "/img/default_picture_svg"
const imgUrl = DefaultUrl ;
return (
<LayoutGrid backLink="/">
@@ -98,7 +98,8 @@ class Entreprises extends React.Component {
seo_description="Les entreprises en vidéo."
seo_url={socialShareUrl}
image={imgUrl}
seo_key="test"
seo_key="Recrutement, video"
></OgHead>
<Typography gutterBottom component="h1"
className={classes.title}>
+32 -3
View File
@@ -8,8 +8,8 @@ import { withStyles } from '@material-ui/core/styles';
import Layout from "../components/templates/Layout"
import Footer from '../components/organisms/Footer';
import Link from 'next/link';
import Head from 'next/head'
import VideoVimeo from './../components/atoms/VideoVimeo'
import Head from 'next/head';
import VideoVimeo from './../components/atoms/VideoVimeo';
const styles = theme => ({
root: {
@@ -102,6 +102,7 @@ function Help(props) {
<Layout>
<Head>
<title key="title">Recrutement vidéo : fonctionnement Talents Tube</title>
<meta key="robots" name="robots" content="noindex, nofollow"></meta>
</Head>
<section className={classes.root}>
<Typography gutterBottom component="h1"
@@ -128,7 +129,35 @@ function Help(props) {
gutterBottom>
Suivez nos conseils pour postuler simplement aux offres demploi. La vidéo de motivation vous permet de dévoiler votre personnalité, vos compétences, votre parcours, vos valeurs, vos soft-skills, votre ambition,…. et bien plus encore.
</Typography>
<Typography gutterBottom component="h2"
className={classes.subTitle}>
Comment réussir votre CV vidéo
</Typography>
<Typography
className={classes.text}
gutterBottom>
Suivez ce <a href="https://blog.talentstube.com/faire-cv-video" target="_blank" >lien</a>
</Typography>
<Typography gutterBottom component="h2"
className={classes.subTitle}>
Accompagnement à la création d'un CV vidéo professionnel
</Typography>
<Typography
className={classes.text}
gutterBottom>
Suivez ce <a href="https://blog.talentstube.com/accompagnement-cv-video" target="_blank" >lien</a>
</Typography>
<Typography gutterBottom component="h2"
className={classes.subTitle}>
Pourquoi faire un CV vidéo ?
</Typography>
<Typography
className={classes.text}
gutterBottom>
Suivez ce <a href="https://blog.talentstube.com/faire-cv-video" target="_blank" >lien</a>
</Typography>
</section>
+14 -6
View File
@@ -13,6 +13,8 @@ import { fetchAdsRequest, togglePromotedFilterRequest} from '../actions/ads'
import { AdsSelector } from '../reducers/ads'
import { TextField } from '@material-ui/core';
import Head from 'next/head'
import OgHead from '../components/atoms/OgHead';
import getConfig from 'next/config'
const styles = theme => ({
@@ -84,14 +86,20 @@ class Offres extends React.Component {
const { classes } = this.props;
const countColor = this.props.promotedFilter ? classes.provided : classes.primary;
const btnClass = this.props.promotedFilter ? classes.buttonDefault : classes.buttonProvided;
const { publicRuntimeConfig } = getConfig();
const socialShareUrl = typeof window !== 'undefined' ? window.location
: publicRuntimeConfig.frontServerUrl + `/Offres`;
const DefaultUrl = publicRuntimeConfig.symphonyUrl + "/img/default_picture_svg"
const imgUrl = DefaultUrl ;
return (
<LayoutGrid backLink="/">
<Head>
<title key="title">Offres demploi en vidéo Talents Tube</title>
<meta name="description" content="Les offres d'emploi en vidéo." />
</Head>
<OgHead seo_title="Offres demploi en vidéo Talents Tube"
seo_description="Les offres d'emploi en vidéo."
seo_url={socialShareUrl}
image={imgUrl}
seo_key="Recrutement, video"
></OgHead>
<Typography gutterBottom component="h1"
className={classes.title}>
+1 -1
View File
@@ -282,7 +282,7 @@ class Reponse extends React.Component {
<title>Candidature vidéo</title>
<meta name="description" content="Talent's tube, postulez en video." />
<meta key="robots" name="robots" content="noindex, nofollow"></meta>
<link rel="canonical" href="https://app.talentstube.com" />
</Head>
{/* https://codesandbox.io/s/ii0us */}
{ loading ?
+1
View File
@@ -107,6 +107,7 @@ class ResetPassword extends Component {
<Layout>
<Head>
<title key="title">Reset password</title>
<meta key="robots" name="robots" content="noindex, nofollow"></meta>
</Head>
<div className={classes.container}>
<Typography
+14 -19
View File
@@ -15,7 +15,8 @@ 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'
const VideoSlider = dynamic(() => import('../components/organisms/ShortVideoHooker'), {
ssr: false
@@ -35,7 +36,7 @@ const TileOffre = dynamic(() => import('../components/organisms/TileOffre'), {
const Footer = dynamic(() => import('../components/organisms/Footer'), {
ssr: false
});
const { publicRuntimeConfig } = getConfig();
const styles = theme => ({
root: {
position: 'relative',
@@ -155,26 +156,20 @@ class Index extends React.Component {
}
render() {
const { classes } = this.props;
const socialShareUrl = typeof window !== 'undefined' ? window.location
: publicRuntimeConfig.frontServerUrl ;
const DefaultUrl = publicRuntimeConfig.symphonyUrl + "/img/default_picture_svg"
const imgUrl = DefaultUrl
return (
<Layout>
<Head>
<title key="title"> Talents tube - La recherche d'emploi en vidéo</title>
<meta name="description" content="Talents Tube est la première plateforme réservée aux offres d'emploi et aux CV vidéos. Découvrez un nouvelle méthode de recrutement ! Installez notre application." />
<OgHead seo_title="Entreprises qui recrutent Talents Tube"
seo_description="Les entreprises en vidéo."
seo_url={socialShareUrl}
image={imgUrl}
seo_key="Recrutement, video"
<meta name="twitter:card" content="summary"/>
<meta name="twitter:site" content="@TalentsTube"/>
<meta name="twitter:title" content="Talents Tube : Le 1er job board 100% vidéo"/>
<meta name="twitter:description" content="Talents Tube est la première plateforme réservée aux offres d'emploi et aux CV vidéos. Découvrez un nouvelle méthode de recrutement !"/>
<meta name="twitter:image" content=""/>
{/* Open Graph data pour le partage sur les réseaux sociaux (ex Facebook..) */}
<meta property="og:title" content="Talents Tube : Le 1er job board 100% vidéo" />
<meta property="og:type" content="article" />
<meta property="og:image" content="" />
<meta property="og:description" content="Talents Tube est la première plateforme réservée aux offres d'emploi et aux CV vidéos. Découvrez un nouvelle méthode de recrutement !" />
<meta property="og:site_name" content="Talents Tube" />
<meta property="og:url" content="" />
</Head>
></OgHead>
<div className={classes.container}>
<VideoSlider />
+1 -2
View File
@@ -3,7 +3,6 @@ import { makeStyles } from '@material-ui/styles';
import { Grid } from '@material-ui/core';
import Layout from "../components/templates/Layout";
import AccountProfile from "../components/organisms/AccountProfile";
import AccountDetails from "../components/organisms/AccountDetails";
import AccountVideoPres from "../components/organisms/AccountVideoPres";
const useStyles = makeStyles(theme => ({
@@ -43,7 +42,7 @@ const Account = () => {
xl={8}
xs={12}
>
<AccountDetails />
</Grid>
</Grid>
+11 -5
View File
@@ -2,10 +2,8 @@ import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Layout from "../components/templates/Layout";
import AccountProfile from "../components/organisms/AccountProfile";
import AccountDetails from "../components/organisms/AccountDetails";
import AccountVideoPres from "../components/organisms/AccountVideoPres";
import AccountStep from "../components/organisms/AccountStep";
import { Grid } from '@material-ui/core';
import Head from 'next/head'
// import AdBlockDetect from 'react-ad-block-detect';
const useStyles = makeStyles((theme) => ({
root: {
@@ -30,9 +28,17 @@ export default function HorizontalNonLinearStepper() {
return (
<Layout>
<div className={classes.root}>
<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>
);
}
+73
View File
@@ -0,0 +1,73 @@
{
"name": "Talents Tube",
"short_name": "Talents Tube",
"lang": "fr",
"orientation":"portrait",
"icons": [
{
"src": "/static/images/icons/talentstubeIco16x16.png",
"sizes": "16x16",
"type": "image/png"
},
{
"src": "/static/images/icons/talentstubeIco32x32.png",
"sizes": "32x32",
"type": "image/png"
},
{
"src": "/static/images/icons/talentstubeIco57x57.png",
"sizes": "57x57",
"type": "image/png"
},
{
"src": "/static/images/icons/talentstubeIco72x72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "/static/images/icons/talentstubeIco114x114.png",
"sizes": "114x114",
"type": "image/png"
},
{
"src": "/static/images/icons/talentstubeIco128x128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "/static/images/icons/talentstubeIco144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "/static/images/icons/talentstubeIco152x152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "/static/images/icons/talentstubeIco192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/static/images/icons/talentstubeIco180x180.png",
"sizes": "180x180",
"type": "image/png"
},
{
"src": "/static/images/icons/talentstubeIco256x256.png",
"sizes": "256x256",
"type": "image/png"
},
{
"src": "/static/images/icons/talentstubeIco512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "/",
"display": "standalone",
"background_color": "#1689FB",
"theme_color": "#1689FB",
"gcm_sender_id":"103953800507"
}
View File
@@ -0,0 +1,35 @@
<svg xmlns="http://www.w3.org/2000/svg" width="73.762" height="69.644" viewBox="0 0 73.762 69.644">
<g id="Import" transform="translate(0 13.219)">
<g id="Groupe_7895" data-name="Groupe 7895" transform="translate(53.502 2.911) rotate(131)">
<rect id="Rectangle_316" data-name="Rectangle 316" width="37.465" height="23.87" transform="translate(0.976 1.838)"/>
<rect id="Rectangle_321" data-name="Rectangle 321" width="4.656" height="4.656" transform="translate(2.783 18.724)" fill="#fff"/>
<rect id="Rectangle_398" data-name="Rectangle 398" width="1.656" height="12.656" transform="translate(2.781 4.725)" fill="#fff"/>
<rect id="Rectangle_399" data-name="Rectangle 399" width="1.656" height="8.656" transform="translate(5.781 8.725)" fill="#fff"/>
<rect id="Rectangle_400" data-name="Rectangle 400" width="1.656" height="18.656" transform="translate(10.781 4.725)" fill="#fff"/>
<path id="Tracé_396" data-name="Tracé 396" d="M0-3H1.656V8.656H0Z" transform="translate(13.781 14.724)" fill="#fff"/>
<rect id="Rectangle_401" data-name="Rectangle 401" width="1.656" height="18.656" transform="translate(17.781 4.725)" fill="#fff"/>
<path id="Tracé_397" data-name="Tracé 397" d="M0-3H1.656V15.656H0Z" transform="translate(20.781 7.725)" fill="#fff"/>
<path id="Tracé_398" data-name="Tracé 398" d="M0-3H1.656V10.788H0Z" transform="translate(23.781 12.593)" fill="#fff"/>
<rect id="Rectangle_402" data-name="Rectangle 402" width="1.656" height="18.656" transform="translate(27.781 4.725)" fill="#fff"/>
<path id="Tracé_399" data-name="Tracé 399" d="M0,9H1.656v6.656H0Z" transform="translate(33.781 7.725)" fill="#fff"/>
<path id="Tracé_400" data-name="Tracé 400" d="M0-3H1.656V10.788H0Z" transform="translate(30.781 12.593)" fill="#fff"/>
</g>
<path id="Tracé_279" data-name="Tracé 279" d="M217.367,282.859l-6.93,6.93-48.507-6.93L155,275.93l6.93-6.93h55.437Z" transform="translate(-155 -233.363)" fill="#155ee4"/>
<path id="Tracé_280" data-name="Tracé 280" d="M173,269v6.93h48.507l6.93-6.93Z" transform="translate(-166.07 -233.363)" opacity="0.25"/>
<g id="Groupe_7897" data-name="Groupe 7897" transform="translate(28.442 19.099)">
<g id="Groupe_7896" data-name="Groupe 7896" transform="translate(3.551)">
<path id="Tracé_281" data-name="Tracé 281" d="M239.065,257.45a.488.488,0,0,1-.231-.039.939.939,0,0,1-.693-1.155,50.925,50.925,0,0,0,1.463-12.088,51.857,51.857,0,0,0-.346-6.006.969.969,0,1,1,1.925-.231,55.915,55.915,0,0,1,.346,6.237,52.807,52.807,0,0,1-1.5,12.55A.952.952,0,0,1,239.065,257.45Z" transform="translate(-238.104 -232.827)" fill="#25d89a"/>
<path id="Tracé_282" data-name="Tracé 282" d="M240.5,229.337a1.021,1.021,0,0,1-.962-.808c-.077-.462-.154-.885-.27-1.347a.944.944,0,0,1,1.848-.385c.077.462.192.924.269,1.386a.969.969,0,0,1-.77,1.116A.141.141,0,0,1,240.5,229.337Z" transform="translate(-238.804 -226.042)" fill="#25d89a"/>
</g>
<path id="Tracé_283" data-name="Tracé 283" d="M233.084,279.525l-4.042-6.237a.972.972,0,1,1,1.617-1.078l3,4.62,4.62-3a.972.972,0,0,1,1.078,1.617Z" transform="translate(-228.879 -254.171)" fill="#25d89a"/>
</g>
<path id="Tracé_284" data-name="Tracé 284" d="M316.393,300.545h-9.008a.385.385,0,1,1,0-.77h8.7l5.505-5.659a.381.381,0,1,1,.539.539Z" transform="translate(-248.483 -248.739)" fill="#25d89a"/>
<path id="Tracé_285" data-name="Tracé 285" d="M317.93,299.2h-6.545a.385.385,0,0,1,0-.77h6.237l4.2-4.312a.381.381,0,1,1,.539.539Z" transform="translate(-250.943 -248.739)" fill="#fa6362"/>
<g id="Groupe_7899" data-name="Groupe 7899" transform="translate(30.144 40.641)">
<g id="Groupe_7898" data-name="Groupe 7898" transform="translate(0 0)">
<path id="Tracé_286" data-name="Tracé 286" d="M233.3,282l2.5,3.811,5.89-3.811h-3.542l-.654.423a1.636,1.636,0,0,0,.077-.423H233.3Z" transform="translate(-233.3 -282)" fill="#21b77e"/>
</g>
</g>
<rect id="Rectangle_325" data-name="Rectangle 325" width="55.437" height="13.859" transform="translate(0 42.566)" fill="#1689fb"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

@@ -0,0 +1,12 @@
<svg id="Groupe_8099" data-name="Groupe 8099" xmlns="http://www.w3.org/2000/svg" width="65.497" height="40.618" viewBox="0 0 65.497 40.618">
<path id="Tracé_401" data-name="Tracé 401" d="M0,0H62.62V35.2H0Z" transform="translate(0 5.559) rotate(-5.093)"/>
<rect id="Rectangle_317" data-name="Rectangle 317" width="3.917" height="3.917" transform="translate(2.066 9.081) rotate(-5.093)" fill="#fff"/>
<rect id="Rectangle_318" data-name="Rectangle 318" width="3.917" height="3.917" transform="translate(2.751 16.917) rotate(-5.093)" fill="#fff"/>
<rect id="Rectangle_319" data-name="Rectangle 319" width="3.917" height="3.917" transform="translate(3.431 24.696) rotate(-5.093)" fill="#fff"/>
<rect id="Rectangle_320" data-name="Rectangle 320" width="3.917" height="3.917" transform="translate(4.167 32.47) rotate(-5.093)" fill="#fff"/>
<rect id="Rectangle_321" data-name="Rectangle 321" width="3.917" height="3.917" transform="translate(57.023 4.199) rotate(-5.093)" fill="#fff"/>
<rect id="Rectangle_322" data-name="Rectangle 322" width="3.917" height="3.917" transform="translate(57.703 11.978) rotate(-5.093)" fill="#fff"/>
<rect id="Rectangle_323" data-name="Rectangle 323" width="3.917" height="3.917" transform="translate(58.444 19.809) rotate(-5.093)" fill="#fff"/>
<rect id="Rectangle_324" data-name="Rectangle 324" width="3.917" height="3.917" transform="translate(59.124 27.588) rotate(-5.093)" fill="#fff"/>
<text id="_" data-name="?" transform="matrix(0.996, -0.087, 0.087, 0.996, 26.298, 31.189)" fill="#fff" font-size="29" font-family="Roboto-Bold, Roboto" font-weight="700"><tspan x="0" y="0">?</tspan></text>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

+1 -1
View File
@@ -16,7 +16,7 @@ exports.sendConfirmationEmail = function (nom, prenom, tokenUrl, mail) {
const tranport = setup();
const email = {
from: process.env.EMAIL_FROM,
to: process.env.NODE_ENV === 'production'? mail : 'thomas.berrod@e-declic.com',
to: process.env.NODE_ENV === 'production'? mail : 'l.laniau@talentstube.com',
subject: `Bienvenue ${mail} 🔑`,
text: `
Bonjour ${prenom} ${nom},
+3 -3
View File
@@ -4,14 +4,14 @@ const formatDate = require("./formatDate");
// ROBOTS.txt
// const robotsTxt = `User-agent: *
// Sitemap: https://app.talentstube.com/sitemap_local.xml
// Sitemap: https://www.talentstube.com/sitemap_local.xml
// Disallow:`;
const robotsTxt = `# crawl setup
User-agent: *
Disallow: /Login*
# Sitemap
Sitemap: https://app.talentstube.com/sitemap_local.xml`
Sitemap: https://www.talentstube.com/sitemap_local.xml`
fs.writeFileSync("out/robots.txt", robotsTxt);
console.log("robots.txt saved!");
@@ -23,7 +23,7 @@ const sitemapXml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${Object.keys(pathsObj).map(
path => `<url>
<loc>https://app.talentstube.com${path}</loc>
<loc>https://www.talentstube.com${path}</loc>
<lastmod>${
pathsObj[path].lastModified
? formatDate(new Date(pathsObj[path].lastModified))
+4 -4
View File
@@ -61,10 +61,10 @@ class Image extends React.Component {
],
links: [
'https://www.talentstube.com/entreprise/5-e-declic/',
'https://www.facebook.com/edeclic/',
'https://twitter.com/edeclic',
'https://www.linkedin.com/company/edeclic/',
'#',
'#',
'#',
'#',
//
],
+1
View File
@@ -171,6 +171,7 @@ class Contact extends React.Component {
<title>Devis Développement PWA</title>
<meta name="description" content="Vous souhaitez créer une PWA, développer des fonctionnalités à votre site web et améliorer l'expérience utilisateur sur votre site internet? Contactez-nous pour parler de votre projet." />
<link rel="canonical" href="https://www.application.bzh/contact"/>
<meta key="robots" name="robots" content="noindex, nofollow"></meta>
</Head>
<div className={classes.root}>
<div className={classes.wrapper}>
+1
View File
@@ -57,6 +57,7 @@ class Index extends React.Component {
<title>Boilerplate PWA</title>
<meta name="description" content="Vous souhaitez créer une PWA, développer des fonctionnalités à votre site web et améliorer l'expérience utilisateur sur votre site internet? Contactez-nous pour parler de votre projet." />
<link rel="canonical" href="https://pwa-boiler.bzh" />
<meta key="robots" name="robots" content="noindex, nofollow"></meta>
</Head>
<div className={classes.root}>