Compare commits

...

63 Commits

Author SHA1 Message Date
Huaoe 7d70b308cf gitignore 2019-09-17 11:29:36 +02:00
Huaoe 077df03406 after merge 2019-09-17 11:28:32 +02:00
Sébastien GLATZ 9becfbe2fc Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-06-27 11:12:46 +02:00
Sébastien GLATZ e27d66dc3d Add component IconText 2019-06-27 11:12:38 +02:00
Sébastien GLATZ 1e83e98042 Add new theme color 2019-06-27 11:12:06 +02:00
Sébastien GLATZ a18c9fd223 Trim App logo 2019-06-27 11:11:36 +02:00
Sébastien GLATZ c41716d0e4 Update style HomePage 2019-06-27 11:11:16 +02:00
Thomas Berrod 4521fbb868 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
# Conflicts:
#	nextjs/pages/index.js
2019-06-27 09:29:21 +02:00
Thomas Berrod 13cba95879 english renaming 2019-06-27 09:21:21 +02:00
Thomas Berrod 9f7a319913 register form 2019-06-26 17:28:38 +02:00
Sébastien GLATZ 3cd2a61276 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-06-26 16:14:27 +02:00
Sébastien GLATZ 6fca2f5435 Add searchBar to Header 2019-06-26 16:14:22 +02:00
Sébastien GLATZ d4da57b006 Update style and semantics 2019-06-26 16:13:39 +02:00
Sébastien GLATZ ef41f9ddd3 Decomposition of Tile from HorizontalScroller 2019-06-26 16:11:12 +02:00
Sébastien GLATZ 5066a73313 Factorization HorizontalScroller 2019-06-26 16:09:11 +02:00
Sébastien GLATZ a502dc944f Evolution home page 2019-06-26 16:05:53 +02:00
Sébastien GLATZ a847305b4a Evolution style thème 2019-06-26 16:05:10 +02:00
Sébastien GLATZ 5405603c70 Changement logo AppBar 2019-06-26 16:04:50 +02:00
Sébastien GLATZ f7ef867b5a Changement logo AppBar 2019-06-26 12:15:57 +02:00
Thomas Berrod 6e427e6713 newsletter + register begining 2019-06-25 17:34:06 +02:00
Thomas Berrod 17aa918c89 supress image dir 2019-06-25 11:19:08 +02:00
Thomas Berrod 34df2c28a5 swipable Login REgister 2019-06-24 17:45:15 +02:00
Thomas Berrod 3c92605ca3 offres: button back 2019-06-24 16:46:04 +02:00
Thomas Berrod e2ade8dc6f centrage du btn postuler 2019-06-24 16:13:23 +02:00
Thomas Berrod 973603fef0 app bar responsiveness 2019-06-21 16:25:04 +02:00
Thomas Berrod 7e2886219f Mes candidatures setup 2019-06-21 16:09:34 +02:00
Thomas Berrod 54ea1f7ac5 login drawer 2019-06-21 15:55:33 +02:00
Thomas Berrod 55322567ae added companies company 2019-06-20 17:04:04 +02:00
Thomas Berrod 177bf112aa video rotator with labels 2019-06-19 15:05:37 +02:00
Thomas Berrod 3701577e3b index video rotator beta 2019-06-19 14:56:22 +02:00
Thomas Berrod 7329256a9f menu skeleton 2019-06-19 11:00:38 +02:00
Thomas Berrod 8bcd62519d fb + linkedin working 2019-06-18 18:01:06 +02:00
Thomas Berrod 62c118519e facebook passport first integration 2019-06-07 17:02:44 +02:00
Thomas Berrod f8e55d7466 login JWT storage 2019-06-07 11:13:48 +02:00
Thomas Berrod a88f8dd7e5 try reducer serving old data before fetch 2019-06-06 17:42:37 +02:00
Thomas Berrod 14a90e3aac variant deprecation fix 2019-06-06 16:49:53 +02:00
Thomas Berrod 4734b10243 recorder integration 2019-06-06 16:45:54 +02:00
Thomas Berrod ac90054670 Merge branch 'master' into Saga
# Conflicts:
#	nextjs/pages/Login.js
2019-06-06 10:37:59 +02:00
Thomas Berrod 74104ed115 Merge branch 'master' of https://git.e-declic.net/talents-tube/app 2019-06-06 10:35:42 +02:00
Thomas Berrod 5fe94dd60f gitignore 2019-06-06 10:35:01 +02:00
Thomas Berrod ec91b3afbd token change 2019-06-06 10:34:38 +02:00
Thomas Berrod 2b180f9d4a uploading webm 2019-06-06 10:34:38 +02:00
Thomas Berrod fdc7b6056e webRTC rebirth 2019-06-06 10:34:37 +02:00
Thomas Berrod 014184509b comment 2019-06-05 09:23:25 +02:00
Thomas Berrod d73655af40 gitignore not ignored 2019-06-04 11:49:51 +02:00
Thomas Berrod e33f43e86a node_modules hell 2019-06-04 11:49:37 +02:00
Thomas Berrod 4b1c634829 root reducer update 2019-06-04 11:01:02 +02:00
Thomas Berrod 060521f380 grid paging 2019-06-03 18:53:42 +02:00
Thomas Berrod 9a8a2d7728 merge Master on saga 2019-06-03 09:34:43 +02:00
Sébastien GLATZ fad4c8822e Gestion erreurs formulaire Login et Register 2019-05-31 11:46:14 +02:00
Sébastien GLATZ 1c5244f3dc Feat: gitignore update 2019-05-31 10:34:39 +02:00
Thomas Berrod 5439b98f15 avancement 2019-05-29 16:00:28 +02:00
Thomas Berrod 2d4ac00df2 avancement Saga 2019-05-28 17:28:03 +02:00
Thomas Berrod 15c612c2ca login roundtrip 2019-05-27 18:36:27 +02:00
Thomas Berrod 23234a12c7 stall 2019-05-27 14:36:05 +02:00
Thomas Berrod dd47a62655 saga 2019-05-27 14:22:27 +02:00
Sébastien GLATZ 96d599ba26 Revert "Modification page liste offres"
This reverts commit cf59b8cede, reversing
changes made to 0c5c702f78.

Retour en arrière pour enlever node modules
2019-05-27 12:56:05 +02:00
Sébastien GLATZ cf59b8cede Modification page liste offres 2019-05-27 09:47:06 +02:00
Sébastien GLATZ 0c5c702f78 Feat: Modification css Grid pour liste d’offres 2019-05-27 09:36:27 +02:00
Sébastien GLATZ 0eff69eac4 Feat : Ajout page liste des offres 2019-05-27 09:35:23 +02:00
Thomas Berrod 221e3de753 restore login 2019-05-24 09:36:15 +02:00
Thomas Berrod 2b2ae4eeba WebRTC 2019-05-23 16:38:47 +02:00
Sébastien GLATZ fbd6e78840 Feat: Création formulaire Login et Register 2019-05-23 15:46:38 +02:00
34411 changed files with 43070 additions and 2733211 deletions
+4
View File
@@ -0,0 +1,4 @@
/nextjs/node_modules/
/node_modules/
/nextjs/node_modules/
/jenkins/
-3
View File
@@ -1,3 +0,0 @@
{
"presets": ["next/babel"]
}
+25
View File
@@ -0,0 +1,25 @@
SERVER_URL=http://localhost:80
MONGO_URI=mongodb://declic:declic42@ds115653.mlab.com:15653/next-auth
FACEBOOK_ID=2332071840142634
FACEBOOK_SECRET=afb8bbca72bd8c517c64f81e998e4f12
PROD_FACEBOOK_ID=1800752833559014
PROD_FACEBOOK_SECRET=454de729b1e58f506f94c8b50ca5c011
TT_LINKEDIN_ID=86m6hegwyj8lbo
TT_LINKEDIN_SECRET=LIOibqDszsP2vQSr
LINKEDIN_ID=77k1m8qx7w6ygj
LINKEDIN_SECRET=mbcnVjyy2vqAZz1B
GOOGLE_ID=
GOOGLE_SECRET=
TWITTER_KEY=
TWITTER_SECRET=
EMAIL_FROM=contact@application.bzh
EMAIL_SERVER=mail.gandi.net
EMAIL_PORT=587
EMAIL_SECURE=true
EMAIL_USERNAME=noreply@application.bzh
EMAIL_PASSWORD=PWApwaPWApwa56!!!
FIREBASE_API_KEY=AAAAHlF5rsI:APA91bHXvjGDJRLzVvqmBDPM1Et96Bw0Iuvc7EGe9wt4a_lSJijDlbZ3RT96seLDK-QM6Mf8qQ4dH6MI9iWt1_d3uzKG2bxr56zltglZ3Z9xU8gz2iJeRGmlOd0YdV43IumIVe6dIOr-
RECAPTCHA_VERIFY_URL=https://www.google.com/recaptcha/api/siteverify
RECAPTCHA_SECRET=6LcCvHcUAAAAAIG-_iR5AXqkwxINfgqxKZ_kG244
MJ_APIKEY_PUBLIC=355697fac93fca865660734b4fdffaeb
MJ_APIKEY_PRIVATE=ddecf75321ca89c09e561857b13534c8
+4 -1
View File
@@ -1 +1,4 @@
/.next
/node_modules/
.next/
.gitignore
+4
View File
@@ -20,3 +20,7 @@ yarn dev
## The framework used
[Next.js](https://github.com/zeit/next.js) is a framework for server-rendered React apps.
[Redux-Saga]
https://redux-saga.js.org/docs/basics/ErrorHandling.html
is a library that aims to make application side effect asynchronous things like data fetching and impure things like accessing the browser cache
+63
View File
@@ -0,0 +1,63 @@
import {
FETCH_ADS_REQUEST,
FETCH_ADS_SUCCESS,
FETCH_ADS_FAILURE,
FETCH_AD_REQUEST,
FETCH_AD_SUCCESS,
FETCH_AD_FAILURE,
FETCH_PROMOTED_ADS_REQUEST,
FETCH_PROMOTED_ADS_SUCCESS,
FETCH_PROMOTED_ADS_FAILURE,
} from '../types'
//Ads list
export const fetchAdsRequest = (payload) => ({
type: FETCH_ADS_REQUEST,
payload
});
export const fetchAdsSuccess = res => ({
type: FETCH_ADS_SUCCESS,
res
});
export const fetchAdsFailure = res => ({
type: FETCH_ADS_FAILURE,
res
});
//Ads list
export const fetchPromotedAdsRequest = (payload) => ({
type: FETCH_PROMOTED_ADS_REQUEST,
payload
});
export const fetchPromotedAdsSuccess = res => ({
type: FETCH_PROMOTED_ADS_SUCCESS,
res
});
export const fetchPromotedAdsFailure = res => ({
type: FETCH_PROMOTED_ADS_FAILURE,
res
});
//Single ad
export const fetchAdRequest = payload => ({
type: FETCH_AD_REQUEST,
payload
});
export const fetchAdSuccess = res => ({
type: FETCH_AD_SUCCESS,
res
});
export const fetchAdFailure = res => ({
type: FETCH_AD_FAILURE,
res
});
+48
View File
@@ -0,0 +1,48 @@
import { USER_LOGGED_IN, USER_LOGGED_OUT, REQUEST_LOGIN, REQUEST_LOGIN_FAILURE,
REQUEST_OAUTH_LOGIN, REQUEST_OAUTH_LOGIN_FAILURE,
REQUEST_LOGOUT,
REQUEST_REGISTER, REQUEST_REGISTER_FAILURE
} from "../types";
export const requestLogin = data => ({
type: REQUEST_LOGIN,
data
});
export const userLoggedIn = user => ({
type: USER_LOGGED_IN,
user
});
export const requestLogout = data => ({
type: REQUEST_LOGOUT,
});
export const userLoggedOut = () => ({
type: USER_LOGGED_OUT
});
export const requestLoginFailure = errors => ({
type: REQUEST_LOGIN_FAILURE,
errors
});
export const requestOauthLogin = () => ({
type: REQUEST_OAUTH_LOGIN,
});
export const requestOauthLoginFailure = errors => ({
type: REQUEST_OAUTH_LOGIN_FAILURE,
errors
});
export const requestRegister = data => ({
type: REQUEST_REGISTER,
data
});
export const requestRegisterFailure = errors => ({
type: REQUEST_REGISTER_FAILURE,
errors
});
+23
View File
@@ -0,0 +1,23 @@
import {
FETCH_COMPANIES_REQUEST,
FETCH_COMPANIES_SUCCESS,
FETCH_COMPANIES_FAILURE,
} from '../types'
//COMPANIES list
export const fetchCompaniesRequest = (payload) => ({
type: FETCH_COMPANIES_REQUEST,
payload
});
export const fetchCompaniesSuccess = res => ({
type: FETCH_COMPANIES_SUCCESS,
res
});
export const fetchCompaniesFailure = res => ({
type: FETCH_COMPANIES_FAILURE,
res
});
+52
View File
@@ -0,0 +1,52 @@
import {
FETCH_CURRENT_USER_REQUEST,
FETCH_CURRENT_USER_SUCCESS,
FETCH_CURRENT_USER_FAILURE,
SUBSCRIBE_NEWSLETTER_REQUEST,
SUBSCRIBE_NEWSLETTER_SUCCESS,
SUBSCRIBE_NEWSLETTER_FAILURE,
REQUEST_REGISTER,
REQUEST_REGISTER_SUCCESS,
REQUEST_REGISTER_FAILURE
} from '../types'
export const fetchCurrentUserRequest = () => ({
type: FETCH_CURRENT_USER_REQUEST
});
export const fetchCurrentUserSuccess = user => ({
type: FETCH_CURRENT_USER_SUCCESS,
user
});
export const fetchCurrentUserFailure = user => ({
type: FETCH_CURRENT_USER_FAILURE,
user
});
export const registerUserRequest = (payload) => ({
type: REQUEST_REGISTER,
payload
});
export const registerUserSuccess = () => ({
type: REQUEST_REGISTER_SUCCESS,
});
export const registerUserFailure = (err) => ({
type: REQUEST_REGISTER_FAILURE,
err
});
export const subscribeToNewsletterRequest = (payload) => ({
type: SUBSCRIBE_NEWSLETTER_REQUEST,
payload
});
export const subscribeToNewsletterSuccess = () => ({
type: SUBSCRIBE_NEWSLETTER_SUCCESS,
});
export const subscribeToNewsletterFailure = () => ({
type: SUBSCRIBE_NEWSLETTER_FAILURE,
});
+36
View File
@@ -0,0 +1,36 @@
import React, { Fragment } from 'react';
import PropTypes from "prop-types";
import { withStyles } from '@material-ui/core/styles';
import SvgIcon from '@material-ui/core/SvgIcon';
const styles = theme => ({
card: {
display: 'flex',
position: 'relative',
height: '60vh',
width: '100%',
},
});
class IconText extends React.Component {
render() {
return (
<Fragment>
<SvgIcon>
<path d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z" />
</SvgIcon>
</Fragment>
);
}
}
IconText.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
};
export default withStyles(styles, { withTheme: true })(IconText);
+33
View File
@@ -0,0 +1,33 @@
import { createMuiTheme } from '@material-ui/core/styles';
import red from '@material-ui/core/colors/red';
// Create a theme instance.
const theme = createMuiTheme({
palette: {
primary: {
main: '#155EE4',
},
secondary: {
main: '#19857b',
},
flash: {
main: '#25D89A',
},
error: {
main: red.A400,
},
background: {
default: '#fff',
},
},
overrides: {
MuiPaper: {
elevation1: {
transition: 'box-shadow .25s',
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.2)',
},
},
},
});
export default theme;
@@ -1,78 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import IconButton from '@material-ui/core/IconButton';
import { withStyles } from '@material-ui/core/styles';
import SvgIcon from '@material-ui/core/SvgIcon';
const styles = theme => ({
root: {
width: '100%',
display: 'flex',
},
grow: {
flexGrow: 1,
},
sectionDesktop: {
justifyContent: 'center',
display: 'flex',
},
sectionMobile: {
// display: 'flex',
},
});
class BottomToolBar extends React.Component {
state = {
anchorEl: null,
mobileMoreAnchorEl: null,
};
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<AppBar position="relative">
<Toolbar className={classes.sectionDesktop}>
<div >
<IconButton aria-label="TT">
<SvgIcon>
<path d="M15.94,10.179l-2.437-0.325l1.62-7.379c0.047-0.235-0.132-0.458-0.372-0.458H5.25c-0.241,0-0.42,0.223-0.373,0.458l1.634,7.376L4.06,10.179c-0.312,0.041-0.446,0.425-0.214,0.649l2.864,2.759l-0.724,3.947c-0.058,0.315,0.277,0.554,0.559,0.401l3.457-1.916l3.456,1.916c-0.419-0.238,0.56,0.439,0.56-0.401l-0.725-3.947l2.863-2.759C16.388,10.604,16.254,10.22,15.94,10.179M10.381,2.778h3.902l-1.536,6.977L12.036,9.66l-1.655-3.546V2.778z M5.717,2.778h3.903v3.335L7.965,9.66L7.268,9.753L5.717,2.778zM12.618,13.182c-0.092,0.088-0.134,0.217-0.11,0.343l0.615,3.356l-2.938-1.629c-0.057-0.03-0.122-0.048-0.184-0.048c-0.063,0-0.128,0.018-0.185,0.048l-2.938,1.629l0.616-3.356c0.022-0.126-0.019-0.255-0.11-0.343l-2.441-2.354l3.329-0.441c0.128-0.017,0.24-0.099,0.295-0.215l1.435-3.073l1.435,3.073c0.055,0.116,0.167,0.198,0.294,0.215l3.329,0.441L12.618,13.182z" />
</SvgIcon>
</IconButton>
<IconButton aria-label="TT">
<SvgIcon>
<path d="M18.303,4.742l-1.454-1.455c-0.171-0.171-0.475-0.171-0.646,0l-3.061,3.064H2.019c-0.251,0-0.457,0.205-0.457,0.456v9.578c0,0.251,0.206,0.456,0.457,0.456h13.683c0.252,0,0.457-0.205,0.457-0.456V7.533l2.144-2.146C18.481,5.208,18.483,4.917,18.303,4.742 M15.258,15.929H2.476V7.263h9.754L9.695,9.792c-0.057,0.057-0.101,0.13-0.119,0.212L9.18,11.36h-3.98c-0.251,0-0.457,0.205-0.457,0.456c0,0.253,0.205,0.456,0.457,0.456h4.336c0.023,0,0.899,0.02,1.498-0.127c0.312-0.077,0.55-0.137,0.55-0.137c0.08-0.018,0.155-0.059,0.212-0.118l3.463-3.443V15.929z M11.241,11.156l-1.078,0.267l0.267-1.076l6.097-6.091l0.808,0.808L11.241,11.156z" />
</SvgIcon>
</IconButton>
<IconButton aria-label="TT">
<SvgIcon>
<path d="M12.075,10.812c1.358-0.853,2.242-2.507,2.242-4.037c0-2.181-1.795-4.618-4.198-4.618S5.921,4.594,5.921,6.775c0,1.53,0.884,3.185,2.242,4.037c-3.222,0.865-5.6,3.807-5.6,7.298c0,0.23,0.189,0.42,0.42,0.42h14.273c0.23,0,0.42-0.189,0.42-0.42C17.676,14.619,15.297,11.677,12.075,10.812 M6.761,6.775c0-2.162,1.773-3.778,3.358-3.778s3.359,1.616,3.359,3.778c0,2.162-1.774,3.778-3.359,3.778S6.761,8.937,6.761,6.775 M3.415,17.69c0.218-3.51,3.142-6.297,6.704-6.297c3.562,0,6.486,2.787,6.705,6.297H3.415z" />
</SvgIcon>
</IconButton>
<IconButton aria-label="TT">
<SvgIcon>
<path d="M15.684,16.959L10.879,8.52c0.886-0.343,1.517-1.193,1.517-2.186c0-1.296-1.076-2.323-2.396-2.323S7.604,5.037,7.604,6.333c0,0.993,0.63,1.843,1.517,2.186l-4.818,8.439c-0.189,0.311,0.038,0.708,0.412,0.708h10.558C15.645,17.667,15.871,17.27,15.684,16.959 M8.562,6.333c0-0.778,0.645-1.382,1.438-1.382s1.438,0.604,1.438,1.382c0,0.779-0.645,1.412-1.438,1.412S8.562,7.113,8.562,6.333 M5.55,16.726L10,8.91l4.435,7.815H5.55z M15.285,9.62c1.26-2.046,1.26-4.525,0-6.572c-0.138-0.223-0.064-0.512,0.162-0.646c0.227-0.134,0.521-0.063,0.658,0.16c1.443,2.346,1.443,5.2,0,7.546c-0.236,0.382-0.641,0.17-0.658,0.159C15.221,10.131,15.147,9.842,15.285,9.62 M13.395,8.008c0.475-1.063,0.475-2.286,0-3.349c-0.106-0.238,0.004-0.515,0.246-0.62c0.242-0.104,0.525,0.004,0.632,0.242c0.583,1.305,0.583,2.801,0,4.106c-0.214,0.479-0.747,0.192-0.632,0.242C13.398,8.523,13.288,8.247,13.395,8.008 M3.895,10.107c-1.444-2.346-1.444-5.2,0-7.546c0.137-0.223,0.431-0.294,0.658-0.16c0.226,0.135,0.299,0.424,0.162,0.646c-1.26,2.047-1.26,4.525,0,6.572c0.137,0.223,0.064,0.512-0.162,0.646C4.535,10.277,4.131,10.489,3.895,10.107 M5.728,8.387c-0.583-1.305-0.583-2.801,0-4.106c0.106-0.238,0.39-0.346,0.631-0.242c0.242,0.105,0.353,0.382,0.247,0.62c-0.475,1.063-0.475,2.286,0,3.349c0.106,0.238-0.004,0.515-0.247,0.62c-0.062,0.027-0.128,0.04-0.192,0.04C5.982,8.668,5.807,8.563,5.728,8.387" />
</SvgIcon>
</IconButton>
<IconButton aria-label="TT">
<SvgIcon>
<path d="M6.176,7.241V6.78c0-0.221-0.181-0.402-0.402-0.402c-0.221,0-0.403,0.181-0.403,0.402v0.461C4.79,7.416,4.365,7.955,4.365,8.591c0,0.636,0.424,1.175,1.006,1.35v3.278c0,0.222,0.182,0.402,0.403,0.402c0.222,0,0.402-0.181,0.402-0.402V9.941c0.582-0.175,1.006-0.714,1.006-1.35C7.183,7.955,6.758,7.416,6.176,7.241 M5.774,9.195c-0.332,0-0.604-0.272-0.604-0.604c0-0.332,0.272-0.604,0.604-0.604c0.332,0,0.604,0.272,0.604,0.604C6.377,8.923,6.105,9.195,5.774,9.195 M10.402,10.058V6.78c0-0.221-0.181-0.402-0.402-0.402c-0.222,0-0.402,0.181-0.402,0.402v3.278c-0.582,0.175-1.006,0.714-1.006,1.35c0,0.637,0.424,1.175,1.006,1.351v0.461c0,0.222,0.181,0.402,0.402,0.402c0.221,0,0.402-0.181,0.402-0.402v-0.461c0.582-0.176,1.006-0.714,1.006-1.351C11.408,10.772,10.984,10.233,10.402,10.058M10,12.013c-0.333,0-0.604-0.272-0.604-0.604S9.667,10.805,10,10.805c0.332,0,0.604,0.271,0.604,0.604S10.332,12.013,10,12.013M14.629,8.448V6.78c0-0.221-0.182-0.402-0.403-0.402c-0.221,0-0.402,0.181-0.402,0.402v1.668c-0.581,0.175-1.006,0.714-1.006,1.35c0,0.636,0.425,1.176,1.006,1.351v2.07c0,0.222,0.182,0.402,0.402,0.402c0.222,0,0.403-0.181,0.403-0.402v-2.07c0.581-0.175,1.006-0.715,1.006-1.351C15.635,9.163,15.21,8.624,14.629,8.448 M14.226,10.402c-0.331,0-0.604-0.272-0.604-0.604c0-0.332,0.272-0.604,0.604-0.604c0.332,0,0.604,0.272,0.604,0.604C14.83,10.13,14.558,10.402,14.226,10.402 M17.647,3.962H2.353c-0.221,0-0.402,0.181-0.402,0.402v11.27c0,0.222,0.181,0.402,0.402,0.402h15.295c0.222,0,0.402-0.181,0.402-0.402V4.365C18.05,4.144,17.869,3.962,17.647,3.962 M17.245,15.232H2.755V4.768h14.49V15.232z" />
</SvgIcon>
</IconButton>
</div>
</Toolbar>
</AppBar>
</div>
);
}
}
BottomToolBar.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(BottomToolBar);
+169
View File
@@ -0,0 +1,169 @@
import React from 'react';
import PropTypes from "prop-types";
import Router from 'next/router'
import getConfig from 'next/config'
import { withStyles } from '@material-ui/core/styles';
import Avatar from '@material-ui/core/Avatar';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import CardHeader from '@material-ui/core/CardHeader';
import CardMedia from '@material-ui/core/CardMedia';
import Typography from '@material-ui/core/Typography';
const { publicRuntimeConfig } = getConfig()
const styles = theme => ({
card: {
display: 'flex',
position: 'relative',
height: '50vh',
width: '100%',
[theme.breakpoints.up('md')]: {
width : '30%',
},
[theme.breakpoints.down('md')]: {
width : '40%',
},
[theme.breakpoints.down('xs')]: {
width : '100%',
},
margin: '1vh 2vh 1vh 2vh',
[theme.breakpoints.up('sm')]: {
margin: '1vh 0 1vh 0',
},
borderRadius: 0
},
details_container: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '8vh 0 0 0',
},
company_title: {
fontSize: '1em',
fontWeight: 'normal',
textTransform: 'uppercase',
},
content: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
flexWrap: 'wrap',
width: '100%',
padding: 0,
},
cover: {
width: '100%',
height: '50%',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
},
logo_container: {
display: 'flex',
alignItems: 'center',
width: 100,
height: 100,
position: 'absolute',
left: '50%',
top: '50%',
transform: 'translate(-50%, -66%)',
backgroundColor: 'white',
boxShadow: '0 8px 6px -6px grey',
},
logo: {
width: '100%',
height: 'auto',
objectfit: 'contain',
borderRadius: 0,
},
chip: {
margin: '0 1vh 0 1vh',
}
});
class CompanyRowComponent extends React.Component {
render() {
const { classes, theme, rowData } = this.props;
const imgDefaultUrl = "https://www.talentstube.com/img/default_picture_company.svg"
const imgUrl = (rowData.presentation_video && rowData.presentation_video.thumbnails[0] && rowData.presentation_video.thumbnails[0].sizes[4]) ? rowData.presentation_video.thumbnails[0].sizes[4].link : imgDefaultUrl
const logoUrl = publicRuntimeConfig.logoRootUrl + rowData.logo
return (
<Card onClick={() => Router.push(`/Company?id=${rowData.id}`)}>
<CardContent className={classes.content}>
<CardMedia
className={classes.cover}
image={imgUrl}
title={rowData.title}
/>
<div className={classes.logo_container}>
<Avatar className={classes.logo} src={logoUrl} />
</div>
<div className={classes.details_container}>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h4"
align="center"
className={classes.company_title}>
{rowData.business_name}
</Typography>
{/* <Typography
gutterBottom
variant="headline"
variant="h6"
component="h3"
align="center"
className={classes.job_title}>
{rowData.title}
</Typography> */}
</div>
<div>
{/* <Chip label={rowData.extra.contract_type} className={classes.chip} />
<Chip label={rowData.location.gmap_address.address_components[0].long_name} className={classes.chip} /> */}
</div>
</CardContent>
{/* <CardHeader />
<CardContent>
<CardMedia
className={classes.cover}
image={imgUrl}
title={rowData.presentation_video&&rowData.presentation_video.title}
/>
<Typography gutterBottom component="h3"
className={classes.details}>
{rowData.brand_name}
</Typography>
<Typography gutterBottom component="h4"
className={classes.details}>
{rowData.website}
</Typography>
<Typography gutterBottom component="h5"
className={classes.details}>
{rowData.description}
</Typography>
</CardContent> */}
</Card>
);
}
}
CompanyRowComponent.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
rowData: PropTypes.object.isRequired
};
export default withStyles(styles, { withTheme: true })(CompanyRowComponent);
@@ -1,94 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import Input from '@material-ui/core/Input';
import Badge from '@material-ui/core/Badge';
import MenuItem from '@material-ui/core/MenuItem';
import Menu from '@material-ui/core/Menu';
import { fade } from '@material-ui/core/styles/colorManipulator';
import { withStyles } from '@material-ui/core/styles';
import SearchIcon from '@material-ui/icons/Search';
import AccountCircle from '@material-ui/icons/AccountCircle';
import MailIcon from '@material-ui/icons/Mail';
import NotificationsIcon from '@material-ui/icons/Notifications';
import MoreIcon from '@material-ui/icons/MoreVert';
import SvgIcon from '@material-ui/core/SvgIcon';
import Router from 'next/router'
const styles = theme => ({
root: {
width: '100%',
},
grow: {
flexGrow: 1,
},
logo: {
width: '48px',
height: '48px'
},
sectionMobile: {
display: 'flex',
},
});
class PrimarySearchAppBar extends React.Component {
state = {
anchorEl: null,
mobileMoreAnchorEl: null,
};
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<AppBar position="fixed">
<Toolbar>
{
this.props.backLink != "" ?
<IconButton className={classes.menuButton} color="inherit" aria-label="Back" onClick={() => Router.push(this.props.backLink)}>
<SvgIcon>
<path d="M11.739,13.962c-0.087,0.086-0.199,0.131-0.312,0.131c-0.112,0-0.226-0.045-0.312-0.131l-3.738-3.736c-0.173-0.173-0.173-0.454,0-0.626l3.559-3.562c0.173-0.175,0.454-0.173,0.626,0c0.173,0.172,0.173,0.451,0,0.624l-3.248,3.25l3.425,3.426C11.911,13.511,11.911,13.789,11.739,13.962 M18.406,10c0,4.644-3.763,8.406-8.406,8.406S1.594,14.644,1.594,10S5.356,1.594,10,1.594S18.406,5.356,18.406,10 M17.521,10c0-4.148-3.373-7.521-7.521-7.521c-4.148,0-7.521,3.374-7.521,7.521c0,4.148,3.374,7.521,7.521,7.521C14.147,17.521,17.521,14.148,17.521,10"></path>
</SvgIcon>
</IconButton>
:
<IconButton className={classes.menuButton} color="inherit" aria-label="Open drawer" onClick={() => Router.push('/')}>
<SvgIcon>
<path d="M20 12l-1.41-1.41L13 5.17V4h-2v12.17l-5.58-5.59L1 12l8 8 8-8z" />
</SvgIcon>
</IconButton>
}
<div className={classes.logo}>
<img src={this.props.logo} />
</div>
<div className={classes.grow} />
<div className={classes.sectionMobile}>
<IconButton color="inherit">
<Badge className={classes.margin} badgeContent={42} color="secondary">
<NotificationsIcon />
</Badge>
</IconButton>
</div>
</Toolbar>
</AppBar>
</div>
);
}
}
PrimarySearchAppBar.propTypes = {
classes: PropTypes.object.isRequired,
backLink: PropTypes.string,
logo: PropTypes.string,
};
export default withStyles(styles)(PrimarySearchAppBar);
+23
View File
@@ -0,0 +1,23 @@
import Link from 'next/link'
import { withStyles } from '@material-ui/core/styles'
import { Fragment, Children } from 'react';
import { Button } from '@material-ui/core';
const styles = theme => ({
root: {
position: 'relative',
height: '10vh'
},
});
function Footer(props) {
const { classes } = props;
return (
<Fragment>
{props.children}
</Fragment>
);
}
export default withStyles(styles)(Footer)
+315
View File
@@ -0,0 +1,315 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import { withStyles, getMuiTheme } from '@material-ui/core/styles';
import MenuIcon from '@material-ui/icons/Menu';
import Link from 'next/link'
import Drawer from '@material-ui/core/Drawer';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import Divider from '@material-ui/core/Divider';
import SendIcon from '@material-ui/icons/Send';
import CodeIcon from '@material-ui/icons/Code';
import HomeIcon from '@material-ui/icons/Home';
import FingerprintIcon from '@material-ui/icons/Fingerprint';
import LocalBarIcon from '@material-ui/icons/LocalBar';
import AccountCircle from '@material-ui/icons/AccountCircle';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import { ListItemText } from '@material-ui/core';
import CircularProgress from '@material-ui/core/CircularProgress';
import { connect } from 'react-redux'
import { fetchCurrentUserRequest } from "../../actions/user";
import { requestLogout } from "../../actions/auth";
import Button from '@material-ui/core/Button';
const styles = theme => ({
root: {
width: '100%',
'& a': {
textDecoration: 'none'
}
},
grow: {
flexGrow: 1,
},
bar: {
},
menuButton: {
marginLeft: -12,
marginRight: 20,
display: 'block'
},
menuLogo: {
cursor: 'pointer',
[theme.breakpoints.down('md')]: {
width:'200px'
},
[theme.breakpoints.down('sm')]: {
width:'100px'
},
},
title: {
display: 'none',
[theme.breakpoints.up('sm')]: {
display: 'block',
},
[theme.breakpoints.down('md')]: {
display: 'none',
},
marginRight: 15,
cursor: 'pointer'
},
sectionDesktop: {
display: 'none',
[theme.breakpoints.up('md')]: {
display: 'flex',
},
},
sectionMobile: {
display: 'flex',
[theme.breakpoints.up('md')]: {
display: 'none',
},
},
fullList: {
width: 'auto',
cursor: 'pointer'
},
});
class Header extends React.Component {
state = {
top: false,
left: false,
bottom: false,
right: false,
toggle: true
};
componentDidMount() {
}
toggleDrawer = (side, open) => () => {
this.setState({
[side]: open,
});
};
toggle = () => this.setState(state => ({ toggle: !state.toggle }))
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<Drawer anchor="left" open={this.state.left} onClose={this.toggleDrawer('left', false)}>
<div
tabIndex={0}
role="button"
onClick={this.toggleDrawer('left', false)}
onKeyDown={this.toggleDrawer('left', false)}
>
<div className={classes.fullList}>
<List>
<Link href="/" prefetch >
<a><ListItem>
<img alt="talents-tube" src='/static/images/logos/Logo-header.svg' className={classes.menuLogo} />
</ListItem></a>
</Link>
<Divider />
<Link href="/" prefetch >
<a><ListItem>
<ListItemText primary='Accueil'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="/Offres" prefetch >
<a><ListItem>
<ListItemText primary="Offres d'emploi">
</ListItemText>
</ListItem></a>
</Link>
<Link href="/Companies" prefetch >
<a><ListItem>
<ListItemText primary='Entreprises'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="/help" prefetch >
<a><ListItem>
<ListItemText primary='Comment ça marche ?'>
</ListItemText>
</ListItem></a>
</Link>
<Divider />
<Link href="/" prefetch >
<a><ListItem>
<ListItemText primary='CV vidéothèque'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="https://blog.talentstube.com" prefetch >
<a><ListItem>
<ListItemText primary='Blog'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="/contact" prefetch >
<a><ListItem>
<ListItemText primary='Contact'>
</ListItemText>
</ListItem></a>
</Link>
<Divider />
<Link href="https://www.talentstube.com/faire-offre-emploi-video" prefetch >
<a><ListItem>
<ListItemText primary='Recruteurs'>
</ListItemText>
</ListItem></a>
</Link>
</List>
</div>
</div>
</Drawer>
<Drawer anchor="right" open={this.state.right} onClose={this.toggleDrawer('right', false)}>
<div
tabIndex={0}
role="button"
onClick={this.toggleDrawer('right', false)}
onKeyDown={this.toggleDrawer('right', false)}
>{!!this.props.loading &&
(<div className="alert alert-info"><CircularProgress color="secondary" />Chargement...</div>
)}
{!!!this.props.loading && !!!this.props.fetched
&&
<div className={classes.fullList}>
<List>
<ListItem>
</ListItem>
<ListItem>
</ListItem>
<ListItem>
</ListItem>
<ListItem>
</ListItem>
<Divider />
<Link href="/login" prefetch >
<a><ListItem>
<ListItemText primary='Connexion'>
</ListItemText>
</ListItem></a>
</Link>
{/* TODO */}
<Link href="/login" prefetch >
<a><ListItem>
<ListItemText primary='Inscription'>
</ListItemText>
</ListItem></a>
</Link>
<Divider />
<Link href="https://www.talentstube.com/faire-offre-emploi-video" >
<a><ListItem>
<ListItemText primary='Espace recruteurs'>
</ListItemText>
</ListItem></a>
</Link>
</List>
</div>}
{!!!this.props.loading && !!this.props.fetched &&
<Fragment>
<ListItem>
{this.props.user.firstname}
{this.props.user.lastname}
{this.props.user.email}
</ListItem>
<Divider />
{/* TODO:real links */}
<Link href="/Candidatures" prefetch >
<a><ListItem>
<ListItemText primary='Mes candidatures'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="/help" prefetch >
<a><ListItem>
<ListItemText primary='Mon compte'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="/help" prefetch >
<a><ListItem>
<ListItemText primary='Paramètres'>
</ListItemText>
</ListItem></a>
</Link>
<ListItem>
<Button
variant="contained"
color="primary"
className={classes.button}
onClick={() => this.props.requestLogout()}>Déconnexion</Button>
</ListItem>
</Fragment>
}
</div>
</Drawer>
<AppBar position="static" className={classes.appBar}>
<Toolbar>
<IconButton className={classes.menuButton} onClick={this.toggleDrawer('left', true)}
color="inherit" aria-label="Open drawer">
<MenuIcon />
</IconButton>
<div className={classes.grow} />
<img alt="talents-tube" src='/static/images/logos/Logo-header.svg' className={classes.menuLogo} />
<div className={classes.grow} />
<IconButton
edge="end"
aria-label="Profile"
aria-controls={'primary-search-account-menu'}
aria-haspopup="true"
onClick={this.toggleDrawer('right', true)}
color="inherit"
>
<AccountCircle />
</IconButton>
</Toolbar>
</AppBar>
</div >
);
}
}
Header.propTypes = {
classes: PropTypes.object.isRequired,
};
function mapStateToProps(state) {
return {
user: state.user,
fetched: !!state.user.fetched,
loading: !!state.user.loading
};
}
export default withStyles(styles)(connect(mapStateToProps, { fetchCurrentUserRequest, requestLogout })(Header));
@@ -0,0 +1,68 @@
import React, { Component, Fragment } from 'react'
import GridList from '@material-ui/core/GridList';
import GridListTile from '@material-ui/core/GridListTile';
import { withStyles } from '@material-ui/core/styles';
import Tile from './Tile';
const styles = theme => ({
root: {
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'space-around',
overflow: 'hidden',
backgroundColor: theme.palette.background.paper,
},
gridList: {
flexWrap: 'nowrap',
// Promote the list into his own layer on Chrome. This cost memory but helps keeping high FPS.
transform: 'translateZ(0)',
height: '100%',
},
gridListTile: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
height: '100% !important',
'&:first-child': {
marginLeft: '3vw',
},
},
rootGridListTile: {
margin: '3vw',
},
tile: {
width: '100% !important',
overflow: 'visible !important',
},
});
class HorizontalScroller extends Component {
render() {
const { classes } = this.props
const children =(tile)=> React.Children.map(this.props.children, child => {
return React.cloneElement(child, {
tile
});
});
return (
<div> {/* Ne pas mettre de Fragment */}
<GridList className={classes.gridList} cols={1.2}>
{this.props.data.map(tile => (
<GridListTile className={classes.gridListTile} classes={{ root: classes.rootGridListTile, tile: classes.tile }} key={tile.title}>
<Tile rowData={tile}>
{ children(tile) }
</Tile>
</GridListTile>
))}
</GridList>
</div>
)
}
}
export default withStyles(styles)(HorizontalScroller)
@@ -0,0 +1,34 @@
import React, { Component } from 'react'
import { Typography, Button } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import TextField from '@material-ui/core/TextField';
const styles = theme => ({
textField: {
textAlign: 'center',
justifyContent: 'center',
},
})
class NewsLetterRegistration extends Component {
render() {
let {classes} = this.props
return (
<div>
<Typography gutterBottom component="h3">
Recevez les dernières nouvelles de Talents Tube par e-mail
</Typography>
<TextField
id="outlined-bare"
className={classes.textField}
margin="normal"
variant="outlined"
inputProps={{ 'aria-label': 'bare' }}
/>
<Button variant="outlined" onClick={() => alert("Salut, tu veux faire un tuto ?")}>Ok</Button>
</div>
)
}
}
export default withStyles(styles)(NewsLetterRegistration)
+97 -21
View File
@@ -1,8 +1,11 @@
import React from 'react';
import PropTypes from "prop-types";
import Router from 'next/router'
import getConfig from 'next/config'
import { withStyles } from '@material-ui/core/styles';
import Avatar from '@material-ui/core/Avatar';
import Card from '@material-ui/core/Card';
import Chip from '@material-ui/core/Chip';
import CardContent from '@material-ui/core/CardContent';
import CardHeader from '@material-ui/core/CardHeader';
import CardMedia from '@material-ui/core/CardMedia';
@@ -12,48 +15,121 @@ import Typography from '@material-ui/core/Typography';
const styles = theme => ({
card: {
display: 'flex',
position: 'relative',
height: '50vh',
width: '100%',
[theme.breakpoints.up('md')]: {
width : '30%',
},
[theme.breakpoints.down('md')]: {
width : '40%',
},
[theme.breakpoints.down('xs')]: {
width : '100%',
},
margin: '1vh 2vh 1vh 2vh',
[theme.breakpoints.up('sm')]: {
margin: '1vh 0 1vh 0',
},
borderRadius: 0
},
details: {
details_container: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '10vh 0 0 0',
},
company_title: {
fontSize: '1em',
fontWeight: 'normal',
textTransform: 'uppercase',
},
content: {
flex: '1 0 auto',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
flexWrap: 'wrap',
width: '100%',
padding: 0,
},
cover: {
width: 151,
height: 151,
width: '100%',
height: '50%',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
},
logo_container: {
display: 'flex',
alignItems: 'center',
width: 100,
height: 100,
position: 'absolute',
left: '50%',
top: '50%',
transform: 'translate(-50%, -66%)',
backgroundColor: 'white',
boxShadow: '0 8px 6px -6px grey',
},
logo: {
width: '100%',
height: 'auto',
objectfit: 'contain',
borderRadius: 0,
},
});
const { publicRuntimeConfig } = getConfig()
class OffreRowComponent extends React.Component {
render() {
const { classes, theme, rowData } = this.props;
const imgDefaultUrl = "https://www.talentstube.com/img/default_picture_company.svg"
const imgUrl = (rowData.video.thumbnails[0] && rowData.video.thumbnails[0].sizes[4]) ? rowData.video.thumbnails[0].sizes[4].link : imgDefaultUrl
const { classes, rowData } = this.props;
const imgUrl = (rowData.video.thumbnails[0] && rowData.video.thumbnails[0].sizes[4]) ? rowData.video.thumbnails[0].sizes[4].link : publicRuntimeConfig.adListDefaultUrl
const logoUrl = publicRuntimeConfig.logoRootUrl + rowData.company.logo
//rowData._embedded.company.business_name
return (
<Card onClick={() => Router.push(`/Offre?id=${rowData.id}`)}>
<CardHeader />
<CardContent>
<Card className={classes.card} onClick={() => Router.push(`/Offre?id=${rowData.id}`)}>
<CardContent className={classes.content}>
<CardMedia
className={classes.cover}
image={imgUrl}
title={rowData.title}
/>
<Typography gutterBottom variant="headline" component="h3"
className={classes.details}>
{rowData.title}
</Typography>
<Typography gutterBottom variant="headline" component="h4"
className={classes.details}>
{rowData._embedded.company.business_name}
</Typography>
</CardContent>
<div className={classes.logo_container}>
<Avatar className={classes.logo} src={logoUrl} />
</div>
<div className={classes.details_container}>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h3"
align="center"
className={classes.company_title}>
{rowData.company.business_name}
</Typography>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h4"
align="center"
className={classes.job_title}>
{rowData.title}
</Typography>
</div>
<div>
<Chip label={rowData.extra.contract_type} className={classes.chip} />
<Chip label={rowData.location.gmap_address.address_components[0].long_name} className={classes.chip} />
</div>
</CardContent>
</Card>
);
}
@@ -0,0 +1,164 @@
import React, { Component, Fragment } from 'react';
import Button from '@material-ui/core/Button';
import Card from '@material-ui/core/Card';
import CardActionArea from '@material-ui/core/CardActionArea';
import CardActions from '@material-ui/core/CardActions';
import CardContent from '@material-ui/core/CardContent';
import CardMedia from '@material-ui/core/CardMedia';
import Typography from '@material-ui/core/Typography';
import { withStyles } from '@material-ui/core/styles';
import Snackbar from '@material-ui/core/Snackbar';
const styles = theme => ({
cardSnack: {
maxWidth: 345,
},
media: {
height: 140,
}
});
class PWAInstallSnack extends Component {
state = {
openSnack: false,
buttonDisplay: true
}
isAvailable = () =>{
console.log(this.buttonDisplay)
return this.state.buttonDisplay;
}
initInstall = () =>
{
this.setState({openSnack: true})
}
getStateAndHelpers() {
return {
on: this.state.openSnack,
initInstall: this.initInstall,
}
}
iOS() {
var iDevices = [
'iPad Simulator',
'iPhone Simulator',
'iPod Simulator',
'iPad',
'iPhone',
'iPod'
];
if (!!navigator.platform) {
while (iDevices.length) {
if (navigator.platform === iDevices.pop()){ return true; }
}
}
return false;
}
componentDidMount() {
if (window !== undefined) {
// don't show if we are in App
if (window.navigator.standalone ||
window.matchMedia('(display-mode: standalone)').matches)
{
console.log('standalone')
this.setState({ openSnack: false, buttonDisplay: false })
}
else if(this.IsSafari())
{
console.log('safari')
this.setState({ openSnack: false, buttonDisplay: false })
if(this.iOS())
this.setState({ openSnack: false, buttonDisplay: true })
}
}
}
//A2HS 'Add 2 Home Screen'
PromptA2HS = (event, reason) => {
this.setState({ openSnack: false })
console.log('prompted')
if (window !== undefined) {
window.promptInstall();
}
}
IsSafari = () => {
if (typeof window !== 'undefined') {
var isSafari = /Safari/.test(window.navigator.userAgent) && /Apple Computer/.test(window.navigator.vendor);
return isSafari;
} else
return false;
}
handleClose = () => {
this.setState({ openSnack: false });
}
render() {
const { classes } = this.props;
var safariSnack = (<Card className={classes.cardSnack}>
<CardActionArea>
<CardMedia
className={classes.media}
image="/static/images/help/addToHomeFull.png"
title="homeScreen"
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
-> les PWA doivent encore s'installer manuellement sous IOS
</Typography>
</CardContent>
<CardActions>
<Button name="compris" size="small" color="secondary" onClick={this.handleClose}>
j'ai compris
</Button>
</CardActions>
</CardActionArea>
</Card>);
var usualSnack = (<Card className={classes.cardSnack}>
<CardActionArea>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
Voulez-vous installer notre application ?
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button name='oui' size="small" color="secondary" onClick={this.PromptA2HS}>
oui
</Button>
<Button name='non' size="small" color="secondary" onClick={this.handleClose}>
non
</Button>
</CardActions>
</Card>);
return <Fragment>
<Snackbar
anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
open={this.state.openSnack}
onClose={this.handleClose}
ContentProps={{
'aria-describedby': 'message-id',
}}>
{this.IsSafari() ? safariSnack : usualSnack}
</Snackbar>
{this.state.buttonDisplay && this.props.children(this.getStateAndHelpers())}
</Fragment>
}
}
export default withStyles(styles)(PWAInstallSnack)
@@ -1,140 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import Input from '@material-ui/core/Input';
import Badge from '@material-ui/core/Badge';
import MenuItem from '@material-ui/core/MenuItem';
import Menu from '@material-ui/core/Menu';
import { fade } from '@material-ui/core/styles/colorManipulator';
import { withStyles } from '@material-ui/core/styles';
import SearchIcon from '@material-ui/icons/Search';
import AccountCircle from '@material-ui/icons/AccountCircle';
import MailIcon from '@material-ui/icons/Mail';
import NotificationsIcon from '@material-ui/icons/Notifications';
import MoreIcon from '@material-ui/icons/MoreVert';
import SvgIcon from '@material-ui/core/SvgIcon';
import Router from 'next/router'
const styles = theme => ({
root: {
width: '100%',
},
grow: {
flexGrow: 1,
},
search: {
position: 'relative',
borderRadius: theme.shape.borderRadius,
backgroundColor: fade(theme.palette.common.white, 0.15),
'&:hover': {
backgroundColor: fade(theme.palette.common.white, 0.25),
},
marginRight: theme.spacing.unit * 2,
marginLeft: 0,
width: '100%',
[theme.breakpoints.up('sm')]: {
marginLeft: theme.spacing.unit * 3,
width: 'auto',
},
},
searchIcon: {
width: theme.spacing.unit * 9,
height: '100%',
position: 'absolute',
pointerEvents: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
inputRoot: {
color: 'inherit',
width: '100%',
},
inputInput: {
paddingTop: theme.spacing.unit,
paddingRight: theme.spacing.unit,
paddingBottom: theme.spacing.unit,
paddingLeft: theme.spacing.unit,
transition: theme.transitions.create('width'),
width: '100%',
[theme.breakpoints.up('md')]: {
width: 500,
},
},
sectionDesktop: {
display: 'flex',
},
sectionMobile: {
display: 'flex',
},
});
class PrimarySearchAppBar extends React.Component {
state = {
anchorEl: null,
mobileMoreAnchorEl: null,
};
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<AppBar position="fixed">
<Toolbar>
{
this.props.backLink != "" ?
<IconButton className={classes.menuButton} color="inherit" aria-label="Back" onClick={() => Router.push(this.props.backLink)}>
<SvgIcon>
<path d="M11.739,13.962c-0.087,0.086-0.199,0.131-0.312,0.131c-0.112,0-0.226-0.045-0.312-0.131l-3.738-3.736c-0.173-0.173-0.173-0.454,0-0.626l3.559-3.562c0.173-0.175,0.454-0.173,0.626,0c0.173,0.172,0.173,0.451,0,0.624l-3.248,3.25l3.425,3.426C11.911,13.511,11.911,13.789,11.739,13.962 M18.406,10c0,4.644-3.763,8.406-8.406,8.406S1.594,14.644,1.594,10S5.356,1.594,10,1.594S18.406,5.356,18.406,10 M17.521,10c0-4.148-3.373-7.521-7.521-7.521c-4.148,0-7.521,3.374-7.521,7.521c0,4.148,3.374,7.521,7.521,7.521C14.147,17.521,17.521,14.148,17.521,10"></path>
</SvgIcon>
</IconButton>
:
<IconButton className={classes.menuButton} color="inherit" aria-label="Open drawer" onClick={() => Router.push('/')}>
<SvgIcon>
<path d="M20 12l-1.41-1.41L13 5.17V4h-2v12.17l-5.58-5.59L1 12l8 8 8-8z" />
</SvgIcon>
</IconButton>
}
<div className={classes.search}>
<Input
placeholder="Recherche…"
disableUnderline
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
/>
</div>
<div className={classes.grow} />
<div className={classes.sectionMobile}>
<IconButton color="inherit">
<Badge className={classes.margin} badgeContent={42} color="secondary">
<NotificationsIcon />
</Badge>
</IconButton>
</div>
</Toolbar>
</AppBar>
</div>
);
}
}
PrimarySearchAppBar.propTypes = {
classes: PropTypes.object.isRequired,
backLink: PropTypes.string,
};
export default withStyles(styles)(PrimarySearchAppBar);
+119
View File
@@ -0,0 +1,119 @@
import React, { Component } from 'react'
import videojs from 'video.js';
import dynamic from 'next/dynamic'
import Button from '@material-ui/core/Button';
import { withStyles } from '@material-ui/core/styles'
import axios from 'axios'
import CircularProgress from '@material-ui/core/CircularProgress';
import setAuthorizationHeader from "../../data/setAuthorizationHeader";
import 'videojs/dist/video-js.css';
import 'videojs-record/dist/css/videojs.record.css';
dynamic(() => import('webrtc-adapter'), {
ssr: false
})
const RTCRecorder = dynamic(() => import('RecordRTC'), {
ssr: false
})
const styles = theme => ({
root: {
margin: theme.spacing.unit,
maxWidth: '400px', [theme.breakpoints.down('md')]: {
maxWidth: `${100 - (theme.spacing.unit)}vw`
},
button: {
margin: theme.spacing.unit,
alignSelf: 'flex-end'
},
}
})
class Recorder extends Component {
async componentDidMount() {
var record = (await import('videojs-record')).default
// instantiate Video.js
this.player = videojs(this.videoNode, this.props, () => {
// print version information at startup
var version_info = 'Using video.js ' + videojs.VERSION +
' with videojs-record ' + videojs.getPluginVersion('record') +
' and recordrtc ' + RTCRecorder.VERSION;
videojs.log(version_info);
});
// device is ready
this.player.on('deviceReady', () => {
console.log('device is ready!');
});
// user clicked the record button and started recording
this.player.on('startRecord', () => {
console.log('started recording!');
});
// user completed recording and stream is available
this.player.on('finishRecord', () => {
// recordedData is a blob object containing the recorded data that
// can be downloaded by the user, stored on server etc.
console.log('finished recording: ', this.player.recordedData);
});
// error handling
this.player.on('error', (element, error) => {
console.warn(error);
});
this.player.on('deviceError', () => {
console.error('device error:', this.player.deviceErrorCode);
});
}
// destroy player on unmount
componentWillUnmount() {
if (this.player) {
this.player.dispose();
}
}
sendBlob = () => {
console.log('accessing recording: ', this.player.recordedData)
var formData = new FormData();
formData.append('upload', this.player.recordedData, "myupload");
// formData.append('user', 7);//TODO: taking from auth
setAuthorizationHeader('eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE1NTk4OTE4ODIsImV4cCI6MTU1OTg5NTQ4Miwicm9sZXMiOlsiUk9MRV9UQUxFTlQiLCJST0xFX1VTRVIiXSwidXNlcm5hbWUiOiJ0aG9tYXMuYmVycm9kQGUtZGVjbGljLmNvbSJ9.dnXiifet5SIyZf1zOBnu6RvVqA6k-aT16O_YNy6ZAhRZUuQtqP21enNkug0KxLEFMy91gcj0gkGuETqMwcHBL_xkx7rJvb2dLoOo0yduZxJLzngWKroCZE152t-V5Edn2Gje3CHMGqTZLwjBowEgUTpgfyTE9IaJn-q2pizukWBzjmfmdz5mYFgoIQrsjThkPxRH8cNOTit0bj6SebjsCCsPb_jdM6rek03qtwELz2ABJaHJU1FiGGTLYtcF3k32AGlRwa5P9etKwQUrz0AL5q3lroKgbtwhxY3cKyRKAo-o68s3v12_T6R86WqEegOx6TyBb06GJhTcP1MIGBMMgNIm5GxSi0U0RvRDmLuFtsuZv5wBUZqkpth8Z_dK5H003k67XjLrYC4TnMhQXxUGV6Eji3lkCY5fOWbQjwXRO9R_rPCNSiPEZj0o_-ach0a4Y5nLhzVlnb3J0plpb4lwpN3D9t9FNfizKQ5VX9eLoozrzkI-apIbV-Z0is8i6j4yt7R24PR9dyreQXZ3-e_tEwu5UTKi-zYAaHaHrRgCSjWg4d6ozuyXQmzi64d1-Fnx6IkU_KtXtUYRVsZhQUvJpri2x1szLLM-Hqdsh2Ljuu5qDdJrHRKeG1gZeKWPfvZweZ3SWrfvlNZHKNWX-2pmEvz9sJdpsAO-NnmTEUVrpzY')
axios.post("http://localhost/app_dev.php/api/media",
formData,
{
headers: {
'Content-Type': `multipart/form-data;`
},
withCredentials: true
})
.then(res => console.log(res)).catch(err => console.log(err))
console.log('end send Blob')
}
render() {
const { classes } = this.props;
return (
<div>
<div data-vjs-player>
<video id="myVideo" ref={node => this.videoNode = node} className="video-js vjs-default-skin" playsInline></video>
</div>
<div>
<Button type="submit" variant="outlined" color="secondary"
className={classes.button}
onClick={this.sendBlob}>
Send
</Button>
</div>
</div>
);
}
}
export default withStyles(styles)(Recorder)
+233
View File
@@ -0,0 +1,233 @@
import React, {Fragment} from 'react';
import { connect } from "react-redux";
import Validator from "validator";
import {FormLabel, FormHelperText,InputLabel, Input,TextField, FormGroup, FormControlLabel, Checkbox, Button, Typography, Link } from '@material-ui/core';
import Visibility from '@material-ui/icons/Visibility';
import VisibilityOff from '@material-ui/icons/VisibilityOff';
import IconButton from '@material-ui/core/IconButton';
import InputAdornment from '@material-ui/core/InputAdornment';
import FormControl from '@material-ui/core/FormControl';
import { withStyles } from '@material-ui/core/styles';
import { registerUserRequest, subscribeToNewsletterRequest } from "../../actions/user"
const styles = theme => ({
container: {
display: 'flex',
flexDirection: 'column',
height: '100%',
},
textField: {
width: '100%'
},
form: {
display: 'flex',
flexDirection: 'column',
},
input50: {
width: '50%',
},
checkboxError:{
color:'red'
}
});
class Register extends React.Component {
state = {
data: {
firstname: '',
lastname: '',
email: '',
password: '',
checkNewsletter: false,
checkCGU: false,
},
errors: {},
loading: false,
showPassword:false
}
validate = data => {
const errors = {};
if (!Validator.isEmail(data.email)) errors.email = "Email invalide";
if (!!!data.password) errors.password = "Requis";
if (!!!data.firstname) errors.firstname = "Requis";
if (!!!data.lastname) errors.lastname = "Requis";
if (!data.checkCGU) errors.checkCGU = "Requis";
return errors;
};
onRegister = e => {
e.preventDefault();
const errors = this.validate(this.state.data);
console.log('onSubmit')
console.log(errors)
this.setState({ errors: errors });
if (Object.keys(errors).length === 0) {
this.setState({ loading: true });
this.props.registerUserRequest(this.state.data)
if (this.state.data.checkNewsletter)
this.props.subscribeToNewsletterRequest({ email: this.state.data.email })
}
};
componentWillReceiveProps(nextProps) {
this.setState({
errors: nextProps.errors,
loading: nextProps.loading
})
}
onChange = e =>
this.setState({
data: { ...this.state.data, [e.target.name]: e.target.value }
});
handleCheckBoxChange = name => event => {
this.setState({data:{ ...this.state.data, [name]: event.target.checked }});
};
handleChangePasswordVisibility = prop => event => {
this.setState({ [prop]: event.target.value });
};
handleClickShowPassword = () => {
this.setState({ showPassword: !this.state.showPassword });
};
render() {
const { classes } = this.props;
const { data, errors } = this.state;
console.log('render errors');
console.log(errors);
console.log(this.state);
return (
<div className={classes.container}>
<form className={classes.form}>
<FormGroup row>
<TextField
value={data.firstname}
className={classes.input50}
onChange={this.onChange}
id="prenom"
name="firstname"
label="Prénom"
margin="normal"
required
error={!!errors.firstname}
/>
<TextField
value={data.lastname}
className={classes.input50}
onChange={this.onChange}
id="nom"
name="lastname"
label="Nom"
margin="normal"
required
error={!!errors.lastname}
/>
</FormGroup>
<TextField
value={data.email}
onChange={this.onChange}
id="emailRegister"
name="email"
label="Email"
margin="normal"
type="email"
required
error={!!errors.email}
autoComplete="username email"
/>
<FormControl>
<InputLabel htmlFor="adornment-password">Password *</InputLabel>
<Input
name="password"
id="adornment-password"
type={this.state.showPassword ? 'text' : 'password'}
value={this.state.password}
onChange={this.onChange}
endAdornment={
<InputAdornment position="end">
<IconButton aria-label="Toggle password visibility" onClick={this.handleClickShowPassword}>
{this.state.showPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
}
autoComplete="current-password"
error={!!errors.password}
/>
</FormControl>
<FormControlLabel
control={
<Checkbox value={data.checkNewsletter}
onChange={this.handleCheckBoxChange('checkNewsletter')}
/>
}
label="Je souhaite recevoir la newsletter de Talents Tube"
/>
<FormControlLabel
name="checkCGU"
className={!!errors.checkCGU&&classes.checkboxError}
control={
<Checkbox
error={!!errors.checkCGU }
value={data.checkCGU}
onChange={this.handleCheckBoxChange('checkCGU')}
/>
}
label="Je déclare avoir pris connaissance et accepte les termes et les CGU*"
required
/>
<Button type="submit" variant="outlined" color="primary" onClick={this.onRegister}>
S'inscrire
</Button>
<Typography
paragraph={true}
align="center"
>Ou</Typography>
</form>
<Button variant="outlined" color="primary" onClick={this.props.linkedInAuth}>
Connexion avec Linkedin
</Button>
<Button variant="outlined" color="primary" onClick={this.props.facebookAuth}>
Connexion avec Facebook
</Button>
<div className={classes.form}>
<Typography
paragraph={true}
align="center"
>Je possède un compte Talents Tube ?
<Link href={"/Login"} className={classes.link}>
Se connecter
</Link>
</Typography>
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
loading: !!state.user.loading,
errors: state.user.errors
};
}
export default withStyles(styles)(connect(mapStateToProps, { registerUserRequest, subscribeToNewsletterRequest })(Register));
@@ -0,0 +1,128 @@
import React, { Component } from 'react'
import { withStyles } from '@material-ui/core/styles';
import Plyr from 'react-plyr';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
const styles = theme => ({
root: {
position: 'relative',
textAlign: 'center',
paddingTop: theme.spacing(20),
justifyContent: 'center',
},
container: {
display: 'flex',
flexDirection: 'column',
position: 'relative',
},
video: {
display: 'flex',
flexDirection: 'column',
},
text: {
position: 'absolute',
},
plyr: {
'.plyr--video .plyr__controls': {
background: null
}
}
});
const videoList = [{ vimeoId: '228345901', title: 'Eurofins', adTitle: 'CDI gestion', link: '/offre?id=22' },
{ vimeoId: '230731700', title: 'MULTIPLAST', adTitle: 'CDI example', link: '/offre?id=24' },
{ vimeoId: '232953887', title: 'Actual', adTitle: 'Chef général', link: '/offre?id=26' }]
class ShortVideoHooker extends Component {
constructor(props) {
super(props);
this.plyrRef = null;
this.setPlyrRef = element => {
this.plyrRef = element;
};
}
state = {
i: 0,
startDate: Date.now()
}
componentDidMount() {
this.timer = setInterval(this.tick.bind(this), 500);
}
componentWillUnmount() {
clearInterval(this.timer);
}
tick() {
// console.log(this.state)
if (new Date() - this.state.startDate >= 8000) {
if (this.state.i == 2)
this.setState({ i: 0, startDate: Date.now() })
else
this.setState({ i: ++this.state.i, startDate: Date.now() })
//Update Plyr
if (this.plyrRef) {
this.plyrRef.hideControls = true;
this.plyrRef.displayDuration = false;
this.plyrRef.updateVideoSource(videoList[this.state.i].vimeoId, 'vimeo')
this.plyrRef.hideControls = true;
this.plyrRef.displayDuration = false;
}
}
}
render() {
let { classes } = this.props;
let videoId = videoList[0].vimeoId;
// console.log(videoId)
return (
<div className={classes.video}>
{/* config at : https://github.com/xDae/react-plyr */}
<Plyr
//autoplay
type="vimeo" // or "vimeo"
videoId={videoId}
//displayDuration={false}
hideControls={true}
clickToPlay={false}
fullscreen={{ enabled: false, fallback: true, iosNative: false }}
disableContextMenu={true}
controls={null}
ref={this.setPlyrRef}
className={classes.plyr}
/>
<Typography gutterBottom
variant="headline"
variant="h6"
component="h4"
align="center"
className={classes.text}>
{videoList[this.state.i].title}
</Typography>
<Typography gutterBottom
variant="headline"
variant="h6"
component="h4"
align="center"
className={classes.text}>
{videoList[this.state.i].adTitle}
</Typography>
<Button variant="outlined">
Voir l'offre
</Button>
</div>
)
}
}
export default withStyles(styles)(ShortVideoHooker);
+125
View File
@@ -0,0 +1,125 @@
import React from 'react';
import PropTypes from "prop-types";
import Router from 'next/router'
import getConfig from 'next/config'
import { withStyles } from '@material-ui/core/styles';
import Avatar from '@material-ui/core/Avatar';
import Card from '@material-ui/core/Card';
import Chip from '@material-ui/core/Chip';
import CardContent from '@material-ui/core/CardContent';
import CardHeader from '@material-ui/core/CardHeader';
import CardMedia from '@material-ui/core/CardMedia';
import Typography from '@material-ui/core/Typography';
const styles = theme => ({
card: {
display: 'flex',
position: 'relative',
height: '60vh',
width: '100%',
[theme.breakpoints.up('md')]: {
width: '30%',
},
[theme.breakpoints.down('md')]: {
width: '40%',
},
[theme.breakpoints.down('xs')]: {
width: '100%',
},
margin: '2vh 3vh 3vh 1vh',
[theme.breakpoints.up('sm')]: {
margin: '1vh 0 1vh 0',
},
borderRadius: '0.2em',
},
details_container: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '8vh 0 0 0',
},
company_title: {
fontSize: '1em',
fontWeight: 'normal',
textTransform: 'uppercase',
},
content: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
flexWrap: 'wrap',
width: '100%',
padding: 0,
},
cover: {
width: '100%',
height: '50%',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
},
logo_container: {
display: 'flex',
alignItems: 'center',
width: 70,
height: 70,
position: 'absolute',
left: '50%',
top: '50%',
transform: 'translate(-50%, -66%)',
backgroundColor: 'white',
boxShadow: '0 8px 6px -6px grey',
border: 'solid 5px white',
borderRadius: '0.5em',
},
logo: {
width: '100%',
height: 'auto',
objectfit: 'contain',
},
chip: {
margin: '0 1vh 0 1vh',
}
});
const { publicRuntimeConfig } = getConfig()
class Tile extends React.Component {
render() {
const { classes, rowData, children } = this.props;
const imgUrl = (rowData.video.thumbnails[0] && rowData.video.thumbnails[0].sizes[4]) ? rowData.video.thumbnails[0].sizes[4].link : publicRuntimeConfig.adListDefaultUrl
const logoUrl = publicRuntimeConfig.logoRootUrl + rowData.company.logo
//rowData._embedded.company.business_name
return (
<Card className={classes.card} onClick={() => Router.push(`/Offre?id=${rowData.id}`)}>
<CardContent className={classes.content}>
<CardMedia
className={classes.cover}
image={imgUrl}
title={rowData.title}
/>
<div className={classes.logo_container}>
<Avatar className={classes.logo} src={logoUrl} />
</div>
{ children }
</CardContent>
</Card>
);
}
}
Tile.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
rowData: PropTypes.object.isRequired
};
export default withStyles(styles, { withTheme: true })(Tile);
@@ -0,0 +1,71 @@
import React, { Fragment } from 'react';
import PropTypes from "prop-types";
import Router from 'next/router'
import getConfig from 'next/config'
import { withStyles } from '@material-ui/core/styles';
import Chip from '@material-ui/core/Chip';
import Typography from '@material-ui/core/Typography';
const styles = theme => ({
details_container: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '8vh 0 0 0',
},
company_title: {
fontSize: '1em',
fontWeight: 'normal',
textTransform: 'uppercase',
},
chip: {
margin: '0 1vh 0 1vh',
}
});
class TileCompany extends React.Component {
render() {
const { classes, tile } = this.props;
return (
<Fragment>
<div className={classes.details_container}>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h4"
align="center"
className={classes.company_title}>
{tile.company.business_name}
</Typography>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h3"
align="center"
className={classes.job_title}>
{tile.title}
</Typography>
</div>
<div>
<Chip label={tile.extra.contract_type} className={classes.chip} />
<Chip label={tile.location.gmap_address.address_components[0].long_name} className={classes.chip} />
</div>
</Fragment>
);
}
}
TileCompany.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
tile: PropTypes.object.isRequired
};
export default withStyles(styles, { withTheme: true })(TileCompany);
+78
View File
@@ -0,0 +1,78 @@
import React, { Fragment } from 'react';
import PropTypes from "prop-types";
import Router from 'next/router'
import getConfig from 'next/config'
import { withStyles } from '@material-ui/core/styles';
import Chip from '@material-ui/core/Chip';
import Typography from '@material-ui/core/Typography';
import Icon from '@material-ui/core/Icon';
import IconText from './../atoms/IconText';
const styles = theme => ({
details_container: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '8vh 0 0 0',
},
company_title: {
fontSize: '0.8em',
fontWeight: 'normal',
},
job_title: {
fontSize: '1em',
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
},
chip: {
margin: '0 1vh 0 1vh',
}
});
class TileOffre extends React.Component {
render() {
const { classes, tile } = this.props;
return (
<Fragment>
<section className={classes.details_container}>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h4"
align="center"
className={classes.company_title}>
{tile.company.business_name}
</Typography>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h3"
align="center"
className={classes.job_title}>
{tile.title}
</Typography>
</section>
<section>
<Chip label={tile.extra.contract_type} className={classes.chip} />
<Chip label={tile.location.gmap_address.address_components[0].long_name} className={classes.chip} />
<IconText />
<Icon>add_circle</Icon>
</section>
</Fragment>
);
}
}
TileOffre.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
tile: PropTypes.object.isRequired
};
export default withStyles(styles, { withTheme: true })(TileOffre);
+4 -1
View File
@@ -1,6 +1,7 @@
import Link from 'next/link'
import { withStyles } from '@material-ui/core/styles'
import BottomToolbar from '../organisms/BottomToolbar';
import { Fragment } from 'react';
const styles = theme => ({
root: {
@@ -12,7 +13,9 @@ const styles = theme => ({
function Footer(props) {
const { classes } = props;
return (
<BottomToolbar/>
<Fragment>
</Fragment>
);
+48 -29
View File
@@ -1,12 +1,15 @@
import Griddle from "griddle-react";
import Griddle, { utils } from "griddle-react";
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from "react-redux";
import fetch from 'isomorphic-unfetch'
import api from '../../data/api'
import OffreRow from "../organisms/OffreRow"
import GriddleCustomTable from "../organisms/GriddleCustomTableComponent";
//insights
//
//https://codesandbox.io/s/pw9zy43v1m?module=%2FGrid.js
const CustomTableBody = ({ rowIds, Row, style, className }) => (
<div style={style} className={className}>
@@ -27,66 +30,80 @@ class Grid extends Component {
};
async componentDidMount() {
try {
let data = await api.ads.fetchAds(10);
this.setState({ data });
} catch (error) {
console.log(error);
}
this.props.dataFetcher(
{
offset: this.state.currentPage,
limit: this.state.pageSize
}
);
}
componentWillReceiveProps(nextProps) {
//this.setState({ data: nextProps.games });
// this.setState({ currentPage: nextProps.currentPage });
// this.setState({ recordCount: nextProps.recordCount });
this.setState({ data: nextProps.data });
this.setState({ currentPage: nextProps.currentPage });
this.setState({ recordCount: nextProps.recordCount });
}
_onNext = () => {
const { currentPage, pageSize, filterText } = this.state;
//this.props.fetchUserGamesRequest(currentPage + 1, pageSize, filterText);
console.debug(`-- _onNext -- ${0} -- ${1} -- ${2} --`, currentPage, pageSize, filterText)
this.props.dataFetcher({ offset: currentPage * pageSize, limit: pageSize, keyword: filterText })
};
_onPrevious = () => {
const { currentPage, pageSize, filterText } = this.state;
//this.props.fetchUserGamesRequest(currentPage - 1, pageSize, filterText);
this.props.dataFetcher({ offset: (currentPage - 2) * pageSize + 1, limit: pageSize, keyword: filterText });
};
_onGetPage = pageNumber => {
const { pageSize, filterText } = this.state;
// this.props.fetchUserGamesRequest(pageNumber, pageSize, filterText);
this.props.dataFetcher({ offset: (pageNumber - 1) * pageSize + 1, limit: pageSize, keyword: filterText });
};
_onFilter = filterText => {
this.setState({ currentPage: 1 });
const { currentPage, pageSize } = this.state;
this.setState({ filterText });
//this.props.fetchUserGamesRequest(currentPage, pageSize, filterText);
this.props.dataFetcher({ offset: (currentPage - 1) * pageSize + 1, limit: pageSize, keyword: filterText });
};
render() {
const style = {
styles: {
TableBody: { display: "flex", flexWrap: "wrap", justifyContent: "space-around" },
}
}
const { data, currentPage, pageSize, recordCount } = this.state;
// console.debug("-- render -- ")
// console.debug(data)
const NewLayout = ({ Table, Pagination, Filter }) => (
<div>
<Filter />
<Pagination />
<Table />
</div>
);
const rowDataSelector = (state, { griddleKey }) =>
state
const rowDataSelector = (state, { griddleKey }) => {
// console.debug("rowDataSelector")
// console.debug(state)
return state
.get("data")
.find(rowMap => rowMap.get("griddleKey") === griddleKey)
.toJSON();
.toJSON()
}
const enhancedWithRowData = connect((state, props) => ({
const enhancedWithRowData = utils.connect((state, props) => ({
// rowData will be available into MyCustomComponent
rowData: rowDataSelector(state, props),
}));
return (
<div>
<Griddle
data={data}
@@ -97,16 +114,17 @@ class Grid extends Component {
}}
components={{
Layout: NewLayout,
Row: enhancedWithRowData(this.props.CustomRowComponent),
Row: this.props.CustomRowComponent,
TableContainer: GriddleCustomTable,
TableBody: CustomTableBody
}}
events={{
// onNext: this._onNext,
// onPrevious: this._onPrevious,
// onGetPage: this._onGetPage,
// onFilter: this._onFilter
onNext: this._onNext,
onPrevious: this._onPrevious,
onGetPage: this._onGetPage,
onFilter: this._onFilter
}}
styleConfig={style}
/>
</div>
)
@@ -115,8 +133,9 @@ class Grid extends Component {
}
Grid.propTypes = {
//dataFetcher: PropTypes.func.isRequired,
CustomRowComponent: PropTypes.func.isRequired,
dataFetcher: PropTypes.func.isRequired,
CustomRowComponent: PropTypes.any.isRequired,
data: PropTypes.any
}
export default Grid;
-26
View File
@@ -1,26 +0,0 @@
import Link from 'next/link'
import PropTypes from "prop-types";
import { withStyles } from '@material-ui/core/styles'
import PSAB from '../organisms/PrimarySearchAppBar'
const styles = theme => ({
root: {
position: 'relative',
height: '10vh'
},
});
function Header(props) {
return (
<PSAB backLink={props.backLink}/>
);
}
Header.defaultProps = {
backLink : ""
}
Header.propTypes = {
backLink : PropTypes.string
}
export default withStyles(styles)(Header)
+3 -8
View File
@@ -1,6 +1,5 @@
import { withStyles } from '@material-ui/core/styles'
import Header from './Header'
import Footer from './Footer'
import Header from '../organisms/Header'
const styles = theme => ({
root: {
@@ -50,17 +49,13 @@ function Layout(props) {
<div className={classes.root}>
<div id="H" className={classes.head}>
<div className={classes.inner}>
<Header />
<Header searchBar={true}/>
</div>
</div>
<div id="C" className={classes.content}>
{props.children}
</div>
<div id="T" className={classes.foot}>
<div className={classes.inner}>
<Footer />
</div>
</div>
</div>
)
}
@@ -1,63 +0,0 @@
import PropTypes from "prop-types";
import { withStyles } from '@material-ui/core/styles'
import DetailAppBar from '../organisms/DetailAppBar'
const styles = theme => ({
root: {
height: '100%'
},
head: {
width: '100%',
height: '56px',
background: 'silver',
position: 'fixed',
[theme.breakpoints.up('sm')]: {
height: '64px'
}
},
content: {
top: '56px',
height: 'calc(100vh - 56px)',
[theme.breakpoints.up('sm')]: {
top: '64px',
height: 'calc(100vh - 64px)',
},
position: 'relative',
overflow: 'auto',
}
});
function LayoutDetail(props) {
const { classes } = props;
return (
<div className={classes.root}>
<div id="H" className={classes.head}>
<div className={classes.inner}>
<DetailAppBar backLink={props.backLink} logo={props.logo}/>
</div>
</div>
<div id="C" className={classes.content}>
{props.children}
</div>
</div>
)
}
LayoutDetail.defaultProps = {
backLink:"/",
logo: "default.svg"
}
LayoutDetail.propTypes = {
backLink : PropTypes.string,
logo: PropTypes.string,
}
export default withStyles(styles)(LayoutDetail)
+1 -1
View File
@@ -1,7 +1,7 @@
import PropTypes from "prop-types";
import { withStyles } from '@material-ui/core/styles'
import Header from './Header'
import Header from '../organisms/Header'
const styles = theme => ({
root: {
@@ -0,0 +1,81 @@
import { withStyles } from '@material-ui/core/styles'
import Header from '../organisms/Header'
import { Button } from '@material-ui/core';
import Router from 'next/router';
import ButtonBase from "@material-ui/core/ButtonBase";
import ArrowLeft from '@material-ui/icons/keyboardArrowLeft';
const styles = theme => ({
root: {
height: '100%'
},
foot: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
position: 'fixed',
[theme.breakpoints.up('sm')]: {
height: '64px'
},
},
content: {
height: 'calc(100vh - 56px)',
[theme.breakpoints.up('sm')]: {
height: 'calc(100vh - 64px)',
},
position: 'relative',
overflow: 'auto',
},
back:
{
position: 'absolute',
zIndex:10,
color : 'white',
backgroundColor: 'grey',
border: 'none',
color: 'white',
padding: '10px',
textAlign: 'center',
textDecoration: 'none',
display: 'inlineBlock',
fontSize: '38px',
margin:' 10px 16px',
borderRadius: '50%',
}
})
function Layout(props) {
const { classes } = props;
return (
<div className={classes.root}>
<ButtonBase name='back'
focusRipple
className={classes.back}
focusVisibleClassName={classes.focusVisible}
onClick={() => Router.back()}>
<ArrowLeft></ArrowLeft>
</ButtonBase>
<div id="C" className={classes.content}>
{props.children}
</div>
<div id="F" className={classes.foot}>
{/* <div className={classes.inner}>
<div className={classes.grow} /> */}
<Button variant="outlined" color="secondary" >Postuler</Button>
{/* <div className={classes.grow} />
</div> */}
</div>
</div>
)
}
export default withStyles(styles)(Layout)
+101
View File
@@ -0,0 +1,101 @@
import React from 'react'
export default class extends React.Component {
render() {
if (this.props.fullscreen) {
return (
<React.Fragment>
<style jsx global>{`
.circle-loader {
position: absolute;
top: 50%;
left: 50%;
width: 50%;
z-index: 100;
text-align: center;
transform: translate(-50%, -50%);
}
.circle-loader .circle {
fill: transparent;
stroke: rgba(0,0,0,0.2);
stroke-width: 4px;
animation: dash 2s ease infinite, rotate 2s linear infinite;
}
@keyframes dash {
0% {
stroke-dasharray: 1,95;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 85,95;
stroke-dashoffset: -25;
}
100% {
stroke-dasharray: 85,95;
stroke-dashoffset: -93;
}
}
@keyframes rotate {
0% {transform: rotate(0deg); }
100% {transform: rotate(360deg); }
}
`}</style>
<span className="circle-loader">
<svg className="circle" width="60" height="60" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="30" cy="30" r="15"/>
</svg>
</span>
</React.Fragment>
)
} else {
return (
<React.Fragment>
<style jsx global>{`
.circle-loader {
display: block;
text-center;
padding-left: 50%;
}
.circle-loader .circle {
position: relative;
left: -30px;
fill: transparent;
stroke: rgba(0,0,0,0.2);
stroke-width: 4px;
animation: dash 2s ease infinite, rotate 2s linear infinite;
}
@keyframes dash {
0% {
stroke-dasharray: 1,95;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 85,95;
stroke-dashoffset: -25;
}
100% {
stroke-dasharray: 85,95;
stroke-dashoffset: -93;
}
}
@keyframes rotate {
0% {transform: rotate(0deg); }
100% {transform: rotate(360deg); }
}
`}</style>
<span className="circle-loader">
<svg className="circle" width="60" height="60" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="30" cy="30" r="15"/>
</svg>
</span>
</React.Fragment>
)
}
}
}
+42 -48
View File
@@ -1,53 +1,47 @@
import fetch from 'isomorphic-unfetch'
import axios from "axios";
//TODO: 'isomorphic-unfetch' :how to set default headers ?
// var obj = {
// method: 'GET',
// mode: 'no-cors',
// // headers: {
// // 'Access-Control-Request-Headers': 'Authorization',
// // 'Authorization': 'Basic amFzcGVyYWRtaW46amFzcGVyYWRtaW4=',
// // 'Content-Type': 'application/json',
// // 'Origin': ''
// // },
// credentials: 'include'
// };
//axios.defaults.headers.common = { 'X-Requested-With': 'XMLHttpRequest' }
axios.defaults.baseURL = (process.env.NODE_ENV !== 'production') ? 'http://localhost/app_dev.php/' : ''
export default {
ads: {
fetchAd: async (id) => {
const res = await fetch(`http://localhost/app_dev.php/api/ads/${id}`)
const offre = await res.json()
return { offre: offre.data }
user: {
login: credentials =>
axios.post("/api/login_check", { username: credentials.email, password: credentials.password }).then(res => res.data),
loginOauth: ({token,type}) =>
axios.post("/api/login_check_oauth", {'oauth-token':token,'oauth-type':type}),
fetchUser: () =>{
console.log("axios /api/user")
return axios.get("/api/user").then(res => {console.log(res); return res.data})},
subscribeToNewsletter: (data) =>
{
console.log(data)
return axios.post("http://localhost:3000/NewsletterSubscription", data).then(res => {console.log(res); return res})
},
fetchAds: async (limit = "", order = "", keyword = "", offset = 1) => {
var obj = {
method: 'GET',
//mode : 'no-cors',
headers: {
// 'Access-Control-Request-Headers': 'Authorization',
// 'Authorization': 'Basic amFzcGVyYWRtaW46amFzcGVyYWRtaW4=',
'Content-Type': 'application/json',
'Origin': ''
},
credentials: 'include'
};
let url = `http://localhost/app_dev.php/api/ads?offset=${offset}`;
if (limit != "") {
url = url + `&limit=${limit}`;
}
if (order != "") {
url = url + `&order=${order}`;
}
if (keyword != "") {
url = url + `&keyword=${keyword}`;
}
const res = await fetch(url, obj);
const show = await res.json();
return show.data;
}
register: (data) => {
console.log(data)
return axios.post("/api/register", { data}).then(res => res)
},
},
ads: {
fetchAd: (id) => {
console.debug("--- fetchAd")
console.debug(id)
return axios.get(`api/ads/${id}`).then(res => res.data)
},
//offset is the index position of the first element to start requesting at
// use 0|1 for isPromoted
fetchAds: ({ limit = null, order = "", keyword = "", offset = 1, status='PUBLISHED', isPromoted=null}) => {
console.debug("--- fetchAds" + offset, limit, order, keyword)
return axios.get('api/ads', { params: { offset, limit, order, keyword, status, isPromoted } })
.then(res => res.data)
},
},
companies: {
fetchCompany: id =>
axios.get(`api/companies/${id}`).then(res => res.data),
fetchCompanies: (limit = "", order = "", keyword = "", offset = 1) =>
axios.get('api/companies', { params: { offset, limit, order, keyword } }).then(res => res.data)
}
}
};
+9
View File
@@ -0,0 +1,9 @@
import axios from "axios";
export default (token = null) => {
if (token) {
axios.defaults.headers.common.authorization = `Bearer ${token}`;
} else {
delete axios.defaults.headers.common.authorization;
}
};
Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

+74
View File
@@ -0,0 +1,74 @@
/**
*
*
*
**/
// Load environment variables from a .env file if one exists
require('dotenv').load()
const nextAuthProviders = require('./next-auth.providers')
const nextAuthFunctions = require('./next-auth.functions')
// If we want to pass a custom session store then we also need to pass an
// instance of Express Session along with it.
const expressSession = require('express-session')
const MongoStore = require('connect-mongo')(expressSession)
// If no store set, NextAuth defaults to using Express Sessions in-memory
// session store (the fallback is intended as fallback for testing only).
let sessionStore
if (process.env.MONGO_URI) {
sessionStore = new MongoStore({
url: process.env.MONGO_URI,
autoRemove: 'interval',
autoRemoveInterval: 10, // Removes expired sessions every 10 minutes
collection: 'sessions',
stringify: false
})
}
module.exports = () => {
// We connect to the User DB before we define our functions.
// next-auth.functions.js returns an async method that does that and returns
// an object with the functions needed for authentication.
return nextAuthFunctions()
.then(functions => {
return new Promise((resolve, reject) => {
// This is the config block we return, ready to be passed to NextAuth
resolve({
// Define a port (if none passed, will not start Express)
// port: process.env.PORT || 3000,
// Secret used to encrypt session data on the server.
sessionSecret: 'fkjpeozr',
// Maximum Session Age in ms (optional, default is 7 days).
// The expiry time for a session is reset every time a user revisits
// the site or revalidates their session token. This is the maximum
// idle time value.
sessionMaxAge: 60000 * 60 * 24 * 7,
// Session Revalidation in X ms (optional, default is 60 seconds).
// Specifies how often a Single Page App should revalidate a session.
// Does not impact the session life on the server, but causes clients
// to refetch session info (even if it is in a local cache) after N
// seconds has elapsed since it was last checked so they always display
// state correctly.
// If set to 0 will revalidate a session before rendering every page.
sessionRevalidateAge: 60000,
// Canonical URL of the server (optiona, but recommended).
// e.g. 'http://localhost:3000' or 'https://www.example.com'
// Used in callbak URLs and email sign in links. It will be auto
// generated if not specified, which may cause problems if your site
// uses multiple aliases (e.g. 'example.com and 'www.examples.com').
serverUrl: process.env.SERVER_URL || null,
// Add an Express Session store.
expressSession: expressSession,
sessionStore: sessionStore,
// Define oAuth Providers
providers: nextAuthProviders(),
// Define functions for manging users and sending email.
functions: functions,
sessionResave : true
})
})
})
}
+273
View File
@@ -0,0 +1,273 @@
/**
* next-auth.functions.js Example
*
* This file defines functions NextAuth to look up, add and update users.
*
* It returns a Promise with the functions matching these signatures:
*
* {
* find: ({
* id,
* email,
* emailToken,
* provider,
* poviderToken
* } = {}) => {},
* update: (user) => {},
* insert: (user) => {},
* remove: (id) => {},
* serialize: (user) => {},
* deserialize: (id) => {}
* }
*
* Each function returns Promise.resolve() - or Promise.reject() on error.
*
* This specific example supports both MongoDB and NeDB, but can be refactored
* to work with any database.
*
* Environment variables for this example:
*
* MONGO_URI=mongodb://localhost:27017/my-database
* EMAIL_FROM=username@gmail.com
* EMAIL_SERVER=smtp.gmail.com
* EMAIL_PORT=465
* EMAIL_USERNAME=username@gmail.com
* EMAIL_PASSWORD=p4ssw0rd
*
* If you wish, you can put these in a `.env` to seperate your environment
* specific configuration from your code.
**/
// Load environment variables from a .env file if one exists
require('dotenv').load()
// This config file uses MongoDB for User accounts, as well as session storage.
// This config includes options for NeDB, which it defaults to if no DB URI
// is specified. NeDB is an in-memory only database intended here for testing.
const MongoClient = require('mongodb').MongoClient
const NeDB = require('nedb')
const MongoObjectId = (process.env.MONGO_URI) ? require('mongodb').ObjectId : (id) => { return id }
// Use Node Mailer for email sign in
const nodemailer = require('nodemailer')
const nodemailerSmtpTransport = require('nodemailer-smtp-transport')
const nodemailerDirectTransport = require('nodemailer-direct-transport')
// Send email direct from localhost if no mail server configured
let nodemailerTransport = nodemailerDirectTransport()
if (process.env.EMAIL_SERVER && process.env.EMAIL_USERNAME && process.env.EMAIL_PASSWORD) {
nodemailerTransport = nodemailerSmtpTransport({
host: process.env.EMAIL_SERVER,
port: process.env.EMAIL_PORT || 25,
secure: process.env.EMAIL_SECURE || true,
auth: {
user: process.env.EMAIL_USERNAME,
pass: process.env.EMAIL_PASSWORD
}
})
}
module.exports = () => {
return new Promise((resolve, reject) => {
if (process.env.MONGO_URI) {
// Connect to MongoDB Database and return user connection
MongoClient.connect(process.env.MONGO_URI, (err, mongoClient) => {
if (err) return reject(err)
const dbName = process.env.MONGO_URI.split('/').pop().split('?').shift()
const db = mongoClient.db(dbName)
return resolve(db.collection('users'))
})
} else {
// If no MongoDB URI string specified, use NeDB, an in-memory work-a-like.
// NeDB is not persistant and is intended for testing only.
let collection = new NeDB({ autoload: true })
collection.loadDatabase(err => {
if (err) return reject(err)
resolve(collection)
})
}
})
.then(usersCollection => {
return Promise.resolve({
// If a user is not found find() should return null (with no error).
find: ({id, email, emailToken, provider} = {}) => {
let query = {}
// Find needs to support looking up a user by ID, Email, Email Token,
// and Provider Name + Users ID for that Provider
if (id) {
query = { _id: MongoObjectId(id) }
} else if (email) {
query = { email: email }
} else if (emailToken) {
query = { emailToken: emailToken }
} else if (provider) {
query = { [`${provider.name}.id`]: provider.id }
}
return new Promise((resolve, reject) => {
usersCollection.findOne(query, (err, user) => {
if (err) return reject(err)
return resolve(user)
})
})
},
// The user parameter contains a basic user object to be added to the DB.
// The oAuthProfile parameter is passed when signing in via oAuth.
//
// The optional oAuthProfile parameter contains all properties associated
// with the users account on the oAuth service they are signing in with.
//
// You can use this to capture profile.avatar, profile.location, etc.
insert: (user, oAuthProfile) => {
return new Promise((resolve, reject) => {
usersCollection.insert(user, (err, response) => {
if (err) return reject(err)
// Mongo Client automatically adds an id to an inserted object, but
// if using a work-a-like we may need to add it from the response.
if (!user._id && response._id) user._id = response._id
return resolve(user)
})
})
},
// The user parameter contains a basic user object to be added to the DB.
// The oAuthProfile parameter is passed when signing in via oAuth.
//
// The optional oAuthProfile parameter contains all properties associated
// with the users account on the oAuth service they are signing in with.
//
// You can use this to capture profile.avatar, profile.location, etc.
update: (user, profile) => {
return new Promise((resolve, reject) => {
usersCollection.update({_id: MongoObjectId(user._id)}, user, {}, (err) => {
if (err) return reject(err)
return resolve(user)
})
})
},
// The remove parameter is passed the ID of a user account to delete.
//
// This method is not used in the current version of next-auth but will
// be in a future release, to provide an endpoint for account deletion.
remove: (id) => {
return new Promise((resolve, reject) => {
usersCollection.remove({_id: MongoObjectId(id)}, (err) => {
if (err) return reject(err)
return resolve(true)
})
})
},
// Seralize turns the value of the ID key from a User object
serialize: (user) => {
// Supports serialization from Mongo Object *and* deserialize() object
if (user.id) {
// Handle responses from deserialize()
return Promise.resolve(user.id)
} else if (user._id) {
// Handle responses from find(), insert(), update()
return Promise.resolve(user._id)
} else {
return Promise.reject(new Error("Unable to serialise user"))
}
},
// Deseralize turns a User ID into a normalized User object that is
// exported to clients. It should not return private/sensitive fields,
// only fields you want to expose via the user interface.
deserialize: (id) => {
return new Promise((resolve, reject) => {
usersCollection.findOne({ _id: MongoObjectId(id) }, (err, user) => {
if (err) return reject(err)
// If user not found (e.g. account deleted) return null object
if (!user) return resolve(null)
return resolve({
id: user._id,
name: user.name,
email: user.email,
emailVerified: user.emailVerified,
admin: user.admin || false
})
})
})
},
// Email Sign In
//
// Accounts are created automatically, as when signing in via oAuth.
// Users are sent one-time use sign in tokens in links. This avoids
// storing user supplied passwords anywhere, preventing password re-use.
//
// To disable this option, do not set sendSignInEmail (or set it to null).
sendSignInEmail: ({email, url, req}) => {
nodemailer
.createTransport(nodemailerTransport)
.sendMail({
to: email,
from: process.env.EMAIL_FROM,
subject: 'Sign in link',
text: `Use the link below to sign in:\n\n${url}\n\n`,
html: `<p>Use the link below to sign in:</p><p>${url}</p>`
}, (err) => {
if (err) {
console.error('Error sending email to ' + email, err)
}
})
if (process.env.NODE_ENV === 'development') {
console.log('Generated sign in link ' + url + ' for ' + email)
}
},
// Credentials Sign In
//
// If you use this you will need to define your own way to validate
// credentials. Unlike with oAuth or Email Sign In, accounts are not
// created automatically so you will need to provide a way to create them.
//
// This feature is intended for strategies like Two Factor Authentication.
//
// To disable this option, do not set signin (or set it to null).
/*
signIn: ({form, req}) => {
return new Promise((resolve, reject) => {
// Should validate credentials (e.g. hash password, compare 2FA token
// etc) and return a valid user object from a database.
return usersCollection.findOne({
email: form.email
}, (err, user) => {
if (err) return reject(err)
if (!user) return resolve(null)
// Check credentials - e.g. compare bcrypt password hashes
if (form.password === "test1234") {
// If valid, return user object - e.g. { id, name, email }
return resolve(user)
} else {
// If invalid, return null
return resolve(null)
}
})
})
},
*/
// Session Object (optional)
//
// The session object that gets returned to the client. You don't need to
// specify this function here unless you want to override or extend the
// default (e.g. with any other properties you have added to req.session)
//
// Note: The object returned will be stored in localStorage and visible
// client side so do not return data you would not want the user to see.
/*
session: (session, req) => {
if (req.session && req.session.someCustomProperty)
session.someCustomProperty = req.session.someCustomProperty
session.someOtherCustomProperty = "Example custom property"
return session
}
*/
})
})
}
+77
View File
@@ -0,0 +1,77 @@
/**
* next-auth.providers.js Example
*
* This file returns a simple array of oAuth Provider objects for NextAuth.
*
* This example returns an array based on what environment variables are set,
* with explicit support for Facebook, Google and Twitter, but it can be used
* to add strategies for other oAuth providers.
*
* Environment variables for this example:
*
* FACEBOOK_ID=
* FACEBOOK_SECRET=
* GOOGLE_ID=
* GOOGLE_SECRET=
* TWITTER_KEY=
* TWITTER_SECRET=
*
* If you wish, you can put these in a `.env` to seperate your environment
* specific configuration from your code.
**/
// Load environment variables from a .env file if one exists
require('dotenv').load()
module.exports = () => {
let providers = []
if (process.env.FACEBOOK_ID && process.env.FACEBOOK_SECRET) {
providers.push({
providerName: 'Facebook',
providerOptions: {
scope: ['email', 'public_profile']
},
Strategy: require('passport-facebook').Strategy,
strategyOptions: {
clientID: process.env.FACEBOOK_ID,
clientSecret: process.env.FACEBOOK_SECRET,
profileFields: ['id', 'displayName', 'email', 'link']
},
getProfile(profile) {
// Normalize profile into one with {id, name, email} keys
return {
id: profile.id,
name: profile.displayName,
email: profile._json.email
}
}
})
}
if (process.env.LINKEDIN_ID && process.env.LINKEDIN_SECRET) {
providers.push({
providerName: 'Linkedin',
providerOptions: {
scope: ['r_emailaddress', 'r_basicprofile']
},
Strategy: require('@sokratis/passport-linkedin-oauth2').Strategy,
strategyOptions: {
clientID: process.env.LINKEDIN_ID,
clientSecret: process.env.LINKEDIN_SECRET,
profileFields: ['r_emailaddress', 'r_basicprofile']
},
getProfile(profile) {
console.log(profile);
// Normalize profile into one with {id, name, email} keys
return {
id: profile.id,
// name: profile.displayName,
// email: profile._json.email
}
}
})
}
return providers
}
+88 -4
View File
@@ -1,12 +1,96 @@
// next.config.js
const withPlugins = require('next-compose-plugins');
const optimizedImages = require('next-optimized-images');
const withPlugins = require('next-compose-plugins')
const optimizedImages = require('next-optimized-images')
const webpack = require("webpack")
const withCSS = require('@ostai/next-css')
const withOffline = require('next-offline')
const { ANALYZE, DEV } = process.env
module.exports = withPlugins([
[withCSS],
[optimizedImages, {
/* config for next-optimized-images */
}],
[withOffline, {
dontAutoRegisterSw: DEV ? true : false,
workboxOpts: {
globPatterns: ['static/**/*'],
globDirectory: '.',
runtimeCaching: [
// { urlPattern: /.*auth.*/, handler: 'networkOnly' },
// { urlPattern: /.*account.*/, handler: 'networkOnly' },
{ urlPattern: /^https?.*/, handler: 'networkFirst' },
{ urlPattern: /\.(?:png|jpg|jpeg|svg|webp)$/,
handler: "cacheFirst",
options: {
cacheName: "images",
expiration: {
maxEntries: 100
}
}}
],
importScripts:
['/static/js/firebase-messaging-sw.js',
'/static/js/backgroundSync-sw.js'
]
},
// your other plugins here
}],
]);
[{
publicRuntimeConfig: {
adListDefaultUrl: "https://www.talentstube.com/img/default_picture_company.svg",
logoRootUrl: 'https://www.talentstube.com/media/cache/profile_thumb/uploads/img/'
}
}]],
{
webpack: (config, { isServer }) => {
if (ANALYZE) {
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
config.plugins.push(new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerPort: isServer ? 8888 : 8889,
openAnalyzer: true
}))
}
const videojsPlugin = new webpack.ProvidePlugin({
videojs: "video.js/dist/video.cjs.js",
RecordRTC: "recordrtc",
MediaStreamRecorder: ["recordrtc", "MediaStreamRecorder"]
});
const videojsAlias = {
videojs: "video.js",
WaveSurfer: "wavesurfer.js",
RecordRTC: "recordrtc"
};
config.resolve.alias = { ...config.resolve.alias, ...videojsAlias };
config.plugins.push(videojsPlugin);
// config.module.rules.push(
// {
// test: /\.css$/,
// loader: 'style-loader!css-loader',
// include: [/node_modules/]
// },
// )
console.log(config);
return config
}
},
{
generateBuildId: async () => {
// For example get the latest git commit hash here
return 'v0.1.0'
}
},
);
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../acorn/bin/acorn" "$@"
ret=$?
else
node "$basedir/../acorn/bin/acorn" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\acorn\bin\acorn" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\acorn\bin\acorn" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../ansi-html/bin/ansi-html" "$@"
ret=$?
else
node "$basedir/../ansi-html/bin/ansi-html" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\ansi-html\bin\ansi-html" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\ansi-html\bin\ansi-html" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../atob/bin/atob.js" "$@"
ret=$?
else
node "$basedir/../atob/bin/atob.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\atob\bin\atob.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\atob\bin\atob.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../bin-version-check/cli.js" "$@"
ret=$?
else
node "$basedir/../bin-version-check/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\bin-version-check\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\bin-version-check\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../browserslist/cli.js" "$@"
ret=$?
else
node "$basedir/../browserslist/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\browserslist\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\browserslist\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../color-support/bin.js" "$@"
ret=$?
else
node "$basedir/../color-support/bin.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\color-support\bin.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\color-support\bin.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../cwebp-bin/cli.js" "$@"
ret=$?
else
node "$basedir/../cwebp-bin/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\cwebp-bin\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\cwebp-bin\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../errno/cli.js" "$@"
ret=$?
else
node "$basedir/../errno/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\errno\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\errno\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../eslint/bin/eslint.js" "$@"
ret=$?
else
node "$basedir/../eslint/bin/eslint.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\eslint\bin\eslint.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\eslint\bin\eslint.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../esprima/bin/esparse.js" "$@"
ret=$?
else
node "$basedir/../esprima/bin/esparse.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\esprima\bin\esparse.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\esprima\bin\esparse.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../esprima/bin/esvalidate.js" "$@"
ret=$?
else
node "$basedir/../esprima/bin/esvalidate.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\esprima\bin\esvalidate.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\esprima\bin\esvalidate.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../executable/cli.js" "$@"
ret=$?
else
node "$basedir/../executable/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\executable\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\executable\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../find-versions/cli.js" "$@"
ret=$?
else
node "$basedir/../find-versions/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\find-versions\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\find-versions\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../gifsicle/cli.js" "$@"
ret=$?
else
node "$basedir/../gifsicle/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\gifsicle\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\gifsicle\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../he/bin/he" "$@"
ret=$?
else
node "$basedir/../he/bin/he" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\he\bin\he" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\he\bin\he" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../image-size/bin/image-size.js" "$@"
ret=$?
else
node "$basedir/../image-size/bin/image-size.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\image-size\bin\image-size.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\image-size\bin\image-size.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../is-ci/bin.js" "$@"
ret=$?
else
node "$basedir/../is-ci/bin.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\is-ci\bin.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\is-ci\bin.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../js-yaml/bin/js-yaml.js" "$@"
ret=$?
else
node "$basedir/../js-yaml/bin/js-yaml.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\js-yaml\bin\js-yaml.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\js-yaml\bin\js-yaml.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../jsesc/bin/jsesc" "$@"
ret=$?
else
node "$basedir/../jsesc/bin/jsesc" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\jsesc\bin\jsesc" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\jsesc\bin\jsesc" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../json5/lib/cli.js" "$@"
ret=$?
else
node "$basedir/../json5/lib/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\json5\lib\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\json5\lib\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../jsonlint/lib/cli.js" "$@"
ret=$?
else
node "$basedir/../jsonlint/lib/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\jsonlint\lib\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\jsonlint\lib\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../loose-envify/cli.js" "$@"
ret=$?
else
node "$basedir/../loose-envify/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\loose-envify\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\loose-envify\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../lpad-align/cli.js" "$@"
ret=$?
else
node "$basedir/../lpad-align/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\lpad-align\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\lpad-align\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../miller-rabin/bin/miller-rabin" "$@"
ret=$?
else
node "$basedir/../miller-rabin/bin/miller-rabin" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\miller-rabin\bin\miller-rabin" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\miller-rabin\bin\miller-rabin" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../mime/cli.js" "$@"
ret=$?
else
node "$basedir/../mime/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\mime\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\mime\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../mkdirp/bin/cmd.js" "$@"
ret=$?
else
node "$basedir/../mkdirp/bin/cmd.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\mkdirp\bin\cmd.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\mkdirp\bin\cmd.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../mozjpeg/cli.js" "$@"
ret=$?
else
node "$basedir/../mozjpeg/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\mozjpeg\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\mozjpeg\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../next/dist/bin/next" "$@"
ret=$?
else
node "$basedir/../next/dist/bin/next" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\next\dist\bin\next" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\next\dist\bin\next" %*
)

Some files were not shown because too many files have changed in this diff Show More