Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix routing
Browse files Browse the repository at this point in the history
* fix routing
* fix pagewrapper
* remove previous protected route features
  and reimplement (was defective)
* implement redirection feature (
  when you try to visit a protected route,
  you get redirected to the login page
  instead of the pagenotfound error,
  and after logging in you get redirected
  back to the protected page you initially
  wanted to visit)

Issue: #1127
Signed-off-by: Ndibe Raymond Olisaemeka <[email protected]>
Ndibe Raymond Olisaemeka committed May 18, 2024
1 parent f4abd0c commit ee7e64f
Showing 13 changed files with 610 additions and 1,374 deletions.
426 changes: 48 additions & 378 deletions zubhub_frontend/zubhub/src/App.js

Large diffs are not rendered by default.

151 changes: 47 additions & 104 deletions zubhub_frontend/zubhub/src/api/api.js
Original file line number Diff line number Diff line change
@@ -11,8 +11,8 @@ class API {
*/
this.domain =
process.env.REACT_APP_NODE_ENV === 'production'
? process.env.REACT_APP_BACKEND_PRODUCTION_URL + '/api/'
: process.env.REACT_APP_BACKEND_DEVELOPMENT_URL + '/api/';
? `${process.env.REACT_APP_BACKEND_PRODUCTION_URL}/api/`
: `${process.env.REACT_APP_BACKEND_DEVELOPMENT_URL}/api/`;
}

/**
@@ -26,13 +26,7 @@ class API {
* @param {string} content_type - content type to be used for the request
* @returns {Promise<>}
*/
request = ({
url = '/',
method = 'GET',
token,
body,
content_type = 'application/json',
}) => {
request = ({ url = '/', method = 'GET', token, body, content_type = 'application/json' }) => {
if (method === 'GET' && !token) {
return fetch(this.domain + url, {
method,
@@ -52,14 +46,14 @@ class API {
withCredentials: 'true',
headers: content_type
? new Headers({
Authorization: `Token ${token}`,
'Content-Type': content_type,
'Accept-Language': `${i18next.language},en;q=0.5`,
})
Authorization: `Token ${token}`,
'Content-Type': content_type,
'Accept-Language': `${i18next.language},en;q=0.5`,
})
: new Headers({
Authorization: `Token ${token}`,
'Accept-Language': `${i18next.language},en;q=0.5`,
}),
Authorization: `Token ${token}`,
'Accept-Language': `${i18next.language},en;q=0.5`,
}),
body,
});
} else if (token) {
@@ -124,9 +118,6 @@ class API {
* @todo - describe method's signature
*/
logout = token => {
const initialUrl = window.location.href
sessionStorage.setItem('initialUrl', initialUrl)

const url = 'rest-auth/logout/';
const method = 'POST';
return this.request({ url, method, token }).then(res => res.json());
@@ -138,17 +129,7 @@ class API {
*
* @todo - describe method's signature
*/
signup = ({
username,
email,
phone,
dateOfBirth,
user_location,
password1,
password2,
bio,
subscribe,
}) => {
signup = ({ username, email, phone, dateOfBirth, user_location, password1, password2, bio, subscribe }) => {
const url = 'creators/register/';
const method = 'POST';
const body = JSON.stringify({
@@ -296,7 +277,7 @@ class API {
const url = `creators/${groupname}/remove-member/${username}/`;
const method = 'DELETE';
if (token) {
return this.request({ url, method ,token }).then(res => res.json());
return this.request({ url, method, token }).then(res => res.json());
} else {
return this.request({ url, method }).then(res => res.json());
}
@@ -312,7 +293,7 @@ class API {
const url = `creators/${groupname}/toggle-follow/${username}/`;
const method = 'GET';
if (token) {
return this.request({ url, method ,token }).then(res => res.json());
return this.request({ url, method, token }).then(res => res.json());
} else {
return this.request({ url, method }).then(res => res.json());
}
@@ -328,7 +309,7 @@ class API {
const url = `creators/${groupname}/members/`;
const method = 'GET';
if (token) {
return this.request({ url, method ,token }).then(res => res.json());
return this.request({ url, method, token }).then(res => res.json());
} else {
return this.request({ url, method }).then(res => res.json());
}
@@ -340,7 +321,7 @@ class API {
*
* @todo - describe method's signature
*/
teamMembersId = ( id ) => {
teamMembersId = id => {
const url = `creators/id/${id}/`;
const method = 'GET';
return this.request({ url, method }).then(res => res.json());
@@ -356,7 +337,7 @@ class API {
const url = `creators/${groupname}/delete-group/`;
const method = 'DELETE';
if (token) {
return this.request({ url, method ,token }).then(res => res.json());
return this.request({ url, method, token }).then(res => res.json());
} else {
return this.request({ url, method }).then(res => res.json());
}
@@ -372,7 +353,7 @@ class API {
const url = `creators/${groupname}/group-followers/`;
const method = 'GET';
if (token) {
return this.request({ url, method ,token }).then(res => res.json());
return this.request({ url, method, token }).then(res => res.json());
} else {
return this.request({ url, method }).then(res => res.json());
}
@@ -388,7 +369,7 @@ class API {
const url = `creators/groups/${username}/`;
const method = 'GET';
if (token) {
return this.request({ url, method ,token }).then(res => res.json());
return this.request({ url, method, token }).then(res => res.json());
} else {
return this.request({ url, method }).then(res => res.json());
}
@@ -404,7 +385,7 @@ class API {
const url = `creators/teams/`;
const method = 'GET';
if (token) {
return this.request({ url, method ,token }).then(res => res.json());
return this.request({ url, method, token }).then(res => res.json());
} else {
return this.request({ url, method }).then(res => res.json());
}
@@ -422,7 +403,7 @@ class API {
const content_type = false;
const body = data;
if (token) {
return this.request({ url, method ,token, body, content_type }).then(res => res.json());
return this.request({ url, method, token, body, content_type }).then(res => res.json());
} else {
return this.request({ url, method }).then(res => res.json());
}
@@ -439,7 +420,7 @@ class API {
const method = 'POST';
const content_type = 'application/json';
const body = JSON.stringify(data);

if (token) {
return this.request({ url, method, token, body, content_type }).then(res => res.json());
} else {
@@ -459,7 +440,7 @@ class API {
const content_type = 'application/json';
const body = JSON.stringify(data);
if (token) {
return this.request({ url, method ,token, body, content_type }).then(res => res.json());
return this.request({ url, method, token, body, content_type }).then(res => res.json());
} else {
return this.request({ url, method }).then(res => res.json());
}
@@ -474,14 +455,14 @@ class API {
*/
getUserProjects = ({ username, page, limit, token, project_to_omit }) => {
let url = `creators/${username}/projects`;
let queryParams = sanitizeObject({ page, limit, project_to_omit })
const queryParams = sanitizeObject({ page, limit, project_to_omit });
const searchParams = new URLSearchParams(queryParams);
url = `${url}?${searchParams}`;
return this.request({ url, token }).then(res => res.json());
};

getUserActivity = (username, page) => {
let url = `activitylog/${username}/?page=${page}`;
const url = `activitylog/${username}/?page=${page}`;

return this.request({ url }).then(res => res.json());
};
@@ -574,9 +555,7 @@ class API {
* @todo - describe method's signature
*/
getFollowers = ({ page, username }) => {
const url = page
? `creators/${username}/followers/?${page}`
: `creators/${username}/followers/`;
const url = page ? `creators/${username}/followers/?${page}` : `creators/${username}/followers/`;

return this.request({ url }).then(res => res.json());
};
@@ -588,9 +567,7 @@ class API {
* @todo - describe method's signature
*/
getFollowing = ({ page, username }) => {
const url = page
? `creators/${username}/following/?${page}`
: `creators/${username}/following/`;
const url = page ? `creators/${username}/following/?${page}` : `creators/${username}/following/`;

return this.request({ url }).then(res => res.json());
};
@@ -614,8 +591,7 @@ class API {
* @todo - describe method's signature
*/
editUserProfile = props => {
const { token, username, email, phone, dateOfBirth, bio, user_location } =
props;
const { token, username, email, phone, dateOfBirth, bio, user_location } = props;

const url = 'creators/edit-creator/';
const method = 'PUT';
@@ -663,9 +639,7 @@ class API {
* @todo - describe method's signature
*/
getMembers = ({ page, username }) => {
const url = page
? `creators/${username}/members/?${page}`
: `creators/${username}/members/`;
const url = page ? `creators/${username}/members/?${page}` : `creators/${username}/members/`;

return this.request({ url }).then(res => res.json());
};
@@ -681,9 +655,7 @@ class API {
const method = 'POST';
const content_type = false;
const body = data;
return this.request({ url, method, token, body, content_type }).then(res =>
res.json(),
);
return this.request({ url, method, token, body, content_type }).then(res => res.json());
};

/**
@@ -731,18 +703,7 @@ class API {
*
* @todo - describe method's signature
*/
createProject = ({
token,
title,
description,
video,
images,
materials_used,
category,
tags,
publish,
activity,
}) => {
createProject = ({ token, title, description, video, images, materials_used, category, tags, publish, activity }) => {
const url = 'projects/create/';
const method = 'POST';
const body = JSON.stringify({
@@ -765,18 +726,7 @@ class API {
*
* @todo - describe method's signature
*/
updateProject = ({
token,
id,
title,
description,
video,
images,
materials_used,
category,
tags,
publish,
}) => {
updateProject = ({ token, id, title, description, video, images, materials_used, category, tags, publish }) => {
const url = `projects/${id}/update/`;
const method = 'PATCH';

@@ -830,9 +780,7 @@ class API {
const method = 'PATCH';
const body = JSON.stringify({});
return this.request({ url, method, token, body }).then(res =>
Promise.resolve(
res.status === 200 ? res.json() : { details: 'unknown error' },
),
Promise.resolve(res.status === 200 ? res.json() : { details: 'unknown error' }),
);
};

@@ -862,11 +810,11 @@ class API {
};

/**
* @method getActivity
* @author Yaya Mamoudou <[email protected]>
*
* @todo - describe method's signature
*/
* @method getActivity
* @author Yaya Mamoudou <[email protected]>
*
* @todo - describe method's signature
*/
getActivity = ({ token, id }) => {
const url = `activities/${id}`;
return this.request({ token, url }).then(res => res.json());
@@ -912,9 +860,7 @@ class API {
* @todo - describe method's signature
*/
getStaffPick = ({ token, page, id }) => {
const url = page
? `projects/staff-picks/${id}/?page=${page}`
: `projects/staff-picks/${id}`;
const url = page ? `projects/staff-picks/${id}/?page=${page}` : `projects/staff-picks/${id}`;

return this.request({ token, url }).then(res => res.json());
};
@@ -1024,10 +970,10 @@ class API {
};

/**
* @method getChallenge
* @author Suchakra Sharma <[email protected]>
*
*/
* @method getChallenge
* @author Suchakra Sharma <[email protected]>
*
*/
getChallenge = () => {
const url = `challenge/`;

@@ -1065,9 +1011,7 @@ class API {
* @todo - describe method's signature
*/
getAmbassadors = ({ token, page }) => {
const url = page
? `ambassadors/?page=${page}`
: `ambassadors`;
const url = page ? `ambassadors/?page=${page}` : `ambassadors`;

return this.request({ token, url }).then(res => res.json());
};
@@ -1079,7 +1023,7 @@ class API {
* @returns the user's notifications
*/
getNotifications = (page, token) => {
const url = 'notifications/?' + new URLSearchParams({ page }).toString();
const url = `notifications/?${new URLSearchParams({ page }).toString()}`;

return this.request({ url, token }).then(res => res.json());
};
@@ -1127,7 +1071,7 @@ class API {

const body = JSON.stringify(args);
return this.request({ url, method, token, body });
//.then(res => res.json());
// .then(res => res.json());
};

deleteActivity = ({ token, id }) => {
@@ -1136,9 +1080,8 @@ class API {
return this.request({ url, method, token });
};

getActivities = (params) => {

let queryParams = sanitizeObject(params)
getActivities = params => {
const queryParams = sanitizeObject(params);
const searchParams = new URLSearchParams(queryParams);
let url = `activities`;
url = `${url}?${searchParams}`;
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { colors } from "../../../colors";
import { colors } from '../../../colors';

const styles = theme => ({
childrenContainer: { padding: '0' },
childrenContainer: {
padding: '0',
minHeight: '90vh',
},
navBarStyle: {
backgroundColor: 'var(--primary-color1)',
},
@@ -133,7 +136,7 @@ const styles = theme => ({
username: {
color: `${colors.white} !important`,
marginBottom: `${0} !important`,
textTransform: 'capitalize'
textTransform: 'capitalize',
},

searchFormSubmitStyle: {
@@ -166,7 +169,7 @@ const styles = theme => ({
navActionStyle: {
display: 'flex',
alignItems: 'center',
gap: 20
gap: 20,
},
avatarStyle: {
cursor: 'pointer',
141 changes: 62 additions & 79 deletions zubhub_frontend/zubhub/src/assets/js/utils/scripts.js
Original file line number Diff line number Diff line change
@@ -21,12 +21,11 @@ export const doConfig = {
*
* @todo - describe function's signature
*/
export const cloudinaryFactory = window => {
return window.cloudinary.Cloudinary.new({
export const cloudinaryFactory = window =>
window.cloudinary.Cloudinary.new({
cloud_name: 'zubhub',
secure: true,
});
};

/**
* @function buildVideoThumbnailURL
@@ -36,7 +35,7 @@ export const cloudinaryFactory = window => {
*/

export const videoOrUrl = video_url => {
let regex =
const regex =
/^((http[s]?:\/\/)?(www\.)?youtube\.com)?((http[s]?:\/\/)?(www\.)?vimeo\.com)?((http[s]?:\/\/)?(www\.)?drive.google\.com)?/gm;
return video_url.match(regex)[0] !== '' ? false : true;
};
@@ -61,7 +60,7 @@ export const buildVideoThumbnailURL = video_url => {
return video_url;
}
} else {
return video_url + '.jpg';
return `${video_url}.jpg`;
}
};

@@ -71,15 +70,13 @@ export const buildVideoThumbnailURL = video_url => {
*
* @todo - describe function's signature
*/
export const getPlayerOptions = (window, video_url) => {
return {
posterOptions: { publicId: buildVideoThumbnailURL(video_url) },
hideContextMenu: true,
logoImageUrl: logo,
logoOnclickUrl: window.location.origin,
showLogo: true,
};
};
export const getPlayerOptions = (window, video_url) => ({
posterOptions: { publicId: buildVideoThumbnailURL(video_url) },
hideContextMenu: true,
logoImageUrl: logo,
logoOnclickUrl: window.location.origin,
showLogo: true,
});

/**
* @object s3
@@ -113,9 +110,7 @@ const shouldSetImages = (compressed, images, state, handleSetState) => {
*
* @todo - describe function's signature
*/
export const slugify = str => {
return str.replace(/[^a-z0-9]/g, '-').replace(/-+/g, '-');
};
export const slugify = str => str.replace(/[^a-z0-9]/g, '-').replace(/-+/g, '-');

/**
* @function recursiveCountComments
@@ -124,10 +119,10 @@ export const slugify = str => {
* @todo - describe function's signature
*/
const recursiveCountComments = (comments, countArr) => {
for (let comment of comments) {
comments.forEach(comment => {
countArr['count'] += 1;
recursiveCountComments(comment['replies'], countArr);
}
});
};

/**
@@ -149,11 +144,12 @@ export const countComments = comments => {
* @todo - describe function's signature
*/
export const Compress = (images, state, handleSetState) => {
let compressed = [];
const compressed = [];
for (let index = 0; index < images.length; index += 1) {
let image = images[index];
const image = images[index];

if (image && image.type.split('/')[1] !== 'gif') {
// eslint-disable-next-line no-new
new Compressor(image, {
quality: 0.6,
convertSize: 100000,
@@ -188,42 +184,42 @@ export const dFormatter = str => {
let interval = seconds / 31536000;

if (interval > 1) {
let result = Math.round(interval);
const result = Math.round(interval);
return { value: result, key: result > 1 ? 'years' : 'year' };
}
interval = seconds / 2592000;
if (interval > 1) {
let result = Math.round(interval);
const result = Math.round(interval);
return { value: result, key: result > 1 ? 'months' : 'month' };
}
interval = seconds / 86400;
if (interval > 1) {
let result = Math.round(interval);
const result = Math.round(interval);
return { value: result, key: result > 1 ? 'days' : 'day' };
}
interval = seconds / 3600;
if (interval > 1) {
let result = Math.round(interval);
const result = Math.round(interval);
return { value: result, key: result > 1 ? 'hours' : 'hour' };
}
interval = seconds / 60;
if (interval > 1) {
let result = Math.round(interval);
const result = Math.round(interval);
return { value: result, key: result > 1 ? 'minutes' : 'minute' };
}
let result = Math.round(interval);
const result = Math.round(interval);
return { value: result, key: result > 1 ? 'seconds' : 'second' };
};

export function nFormatter(num) {
if (num >= 1000000000) {
return (num / 1000000000).toFixed(1).replace(/\.0$/, '') + 'G';
return `${(num / 1000000000).toFixed(1).replace(/\.0$/, '')}G`;
}
if (num >= 1000000) {
return (num / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';
return `${(num / 1000000).toFixed(1).replace(/\.0$/, '')}M`;
}
if (num >= 1000) {
return (num / 1000).toFixed(1).replace(/\.0$/, '') + 'K';
return `${(num / 1000).toFixed(1).replace(/\.0$/, '')}K`;
}
return num;
}
@@ -235,20 +231,18 @@ export function nFormatter(num) {
* @todo - describe function's signature
*/
export const parseComments = comments => {
for (let each_comment of comments) {
comments.forEach(each_comment => {
const mentions = each_comment.text.match(/\B@[a-z0-9_.-]+/gi);
if (Array.isArray(mentions)) {
for (let mention of mentions) {
mentions.forEach(mention => {
each_comment.text = each_comment.text.replace(
mention,
`<a href="/creators/${
mention.split('@')[1]
}" class="mention">${mention}</a>`,
`<a href="/creators/${mention.split('@')[1]}" class="mention">${mention}</a>`,
);
}
});
}
parseComments(each_comment['replies']);
}
});
};

/**
@@ -258,14 +252,13 @@ export const parseComments = comments => {
* @todo - describe function's signature
*/
export const tempAddComment = (comment, comments, parent_id) => {
for (let each_comment of comments) {
comments.forEach(each_comment => {
if (each_comment.id === parent_id) {
each_comment.replies.unshift(comment);
break;
} else {
tempAddComment(comment, each_comment['replies'], parent_id);
}
}
});
};

/**
@@ -275,7 +268,7 @@ export const tempAddComment = (comment, comments, parent_id) => {
* @todo - describe function's signature
*/
export const tempDeleteComment = (comments, comment_id) => {
for (let index = 0; index < comments.length; index++) {
for (let index = 0; index < comments.length; index += 1) {
if (Number(comments[index].id) === Number(comment_id)) {
comments.splice(index, 1);
break;
@@ -293,19 +286,11 @@ export const tempDeleteComment = (comments, comment_id) => {
*/
export const calculateLabelWidth = (text, document) => {
if (text?.length) {
let label = document.evaluate(
`//label[text()='${text}']`,
document,
null,
0,
null,
);
let label = document.evaluate(`//label[text()='${text}']`, document, null, 0, null);
label = label?.iterateNext();

let label_width = label?.offsetWidth;
const label_width = label?.offsetWidth;
return label_width ? label_width : text?.length;
} else {
return;
}
};

@@ -317,40 +302,36 @@ export const calculateLabelWidth = (text, document) => {
* @param {String} tag - name of tag.
* @returns {boolean}
*/
export const isBaseTag = tag => {
return BASE_TAGS.includes(tag);
};

export const getRouteFieldIndex = str => {
let arr = str.split('.');
let { route, index } = getRouteAndIndex(arr[0]);
return arr.length > 1
? { route: route, field: arr[1], index: index }
: { field: route, index: index };
};
export const isBaseTag = tag => BASE_TAGS.includes(tag);

export const getRouteAndIndex = str => {
let arr = str.split('[');
const arr = str.split('[');
return arr.length > 1
? { route: arr[0], index: parseInt(arr[1].split('')[0]) }
? { route: arr[0], index: parseInt(arr[1].split('')[0], 10) }
: { route: arr[0], index: parseInt('-1', 10) };
};

export const getRouteFieldIndex = str => {
const arr = str.split('.');
const { route, index } = getRouteAndIndex(arr[0]);
return arr.length > 1 ? { route, field: arr[1], index } : { field: route, index };
};

export const getIndexFromFieldName = fieldName => {
let arr = fieldName.split('[');
return arr.length > 1 ? parseInt(arr[1].split('')[0]) : parseInt('-1', 10);
const arr = fieldName.split('[');
return arr.length > 1 ? parseInt(arr[1].split('')[0], 10) : parseInt('-1', 10);
};

export const getFieldAndIndex = str => {
let arr = str.split('[');
const arr = str.split('[');
return arr.length > 1
? { field: arr[0], index: parseInt(arr[1].split('')[0]) }
? { field: arr[0], index: parseInt(arr[1].split('')[0], 10) }
: { field: arr[0], index: parseInt('-1', 10) };
};

export const getBase64ImageFromURL = (url, field, index) => {
return new Promise((resolve, reject) => {
var img = new Image();
export const getBase64ImageFromURL = (url, field, index) =>
new Promise((resolve, reject) => {
const img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
// function draw(img) {
// var buffer = document.createElement('canvas');
@@ -378,27 +359,29 @@ export const getBase64ImageFromURL = (url, field, index) => {
// draw(img);
// };
img.onload = () => {
var canvas = document.createElement('canvas');
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext('2d');
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#FFF';
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL('image/jpeg');
index >= 0
? resolve({ [`${field}${index}image`]: dataURL })
: resolve({ [field]: dataURL });
const dataURL = canvas.toDataURL('image/jpeg');
index >= 0 ? resolve({ [`${field}${index}image`]: dataURL }) : resolve({ [field]: dataURL });
};
img.onerror = error => {
reject(error);
};

img.src = url;
});
};

export const capitalize = str => {
let newStr = str.toString().toLowerCase();
const newStr = str.toString().toLowerCase();
return newStr.charAt(0).toUpperCase() + newStr.slice(1);
};

export const getRedirectPath = url => {
url = url.split('redirect=');
return url.length > 1 ? url[1] : '';
};
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import React from 'react'
import React from 'react';
import { Navigate } from 'react-router-dom';

const ProtectedRoute = props => {
const { wrapper: Wrapper, component, ...rest } = props;
const ProtectedRoute = props =>
props.auth?.token ? props.children : <Navigate to={`/login?redirect=${props.location?.pathname}`} replace />;

return props.auth?.token ? <Wrapper component={component} {...rest} /> : <Navigate to="/login" replace />;
};

export default ProtectedRoute
export default ProtectedRoute;
414 changes: 188 additions & 226 deletions zubhub_frontend/zubhub/src/store/actions/authActions.js

Large diffs are not rendered by default.

82 changes: 30 additions & 52 deletions zubhub_frontend/zubhub/src/views/PageWrapper.jsx
Original file line number Diff line number Diff line change
@@ -37,7 +37,7 @@ import commonStyles from '../assets/js/styles';
import languageMap from '../assets/js/languageMap.json';
import DashboardLayout from '../layouts/DashboardLayout/DashboardLayout';
import Navbar from '../components/Navbar/Navbar';
import NotFoundPage from './not_found/NotFound';
import { ProtectedRoute } from '../components';

const useStyles = makeStyles(styles);
const useCommonStyles = makeStyles(commonStyles);
@@ -52,17 +52,9 @@ function PageWrapper(props) {
const backToTopEl = useRef(null);
const [prevScrollPos, setPrevScrollPos] = useState(window.pageYOffset);
const [isVisible, setIsVisible] = useState(false);
const navigate = useNavigate();
const classes = useStyles();
const common_classes = useCommonStyles();
const trigger = useScrollTrigger();
const params = useParams();
const location = useLocation();
const routeProps = {
location,
params,
navigate,
};

const [state, setState] = React.useState({
loading: false,
@@ -107,14 +99,18 @@ function PageWrapper(props) {
}, [trigger]);

const { loading } = state;
const { t } = props;
const { t, Component } = props;
const { zubhub, hero } = props.projects;

// TODO: remove childrenRenderer and use children directly. this will likely mean having useNavigate, useParams,
// useLocation in every component that needs them.
// React.cloneElement makes our code brittle: see https://react.dev/reference/react/cloneElement
const childrenRenderer = () =>
React.Children.map(props.children, child => React.cloneElement(child, { ...props, ...routeProps }));
const navigate = useNavigate();
const params = useParams();
const location = useLocation();
const routeProps = {
location,
params,
navigate,
};

return (
<>
<ToastContainer />
@@ -124,44 +120,26 @@ function PageWrapper(props) {
<Navbar {...props} {...routeProps} />

<Container className={classes.childrenContainer} maxWidth="lg">
{props.auth?.token ? <DashboardLayout>{loading ? <LoadingPage /> : childrenRenderer()}</DashboardLayout> : null}
{!props.auth?.token &&
![
'/',
'/signup',
'/login',
'/projects/:id',
'/ambassadors',
'/creators/:username',
'/privacy_policy',
'/terms_of_use',
'/about',
'/challenge',
'/password-reset',
'/email-confirm',
'/password-reset-confirm',
].includes(location?.pathname) && (
<div style={{ minHeight: '80vh' }}>
<NotFoundPage />
</div>
)}
{loading ? (
<LoadingPage />
) : props.auth?.token ? (
<DashboardLayout>
<React.Suspense fallback={<LoadingPage />}>
<Component {...props} {...routeProps} />
</React.Suspense>
</DashboardLayout>
) : props.protected ? (
<ProtectedRoute {...props} {...routeProps}>
<React.Suspense fallback={<LoadingPage />}>
<Component {...props} {...routeProps} />
</React.Suspense>
</ProtectedRoute>
) : (
<React.Suspense fallback={<LoadingPage />}>
<Component {...props} {...routeProps} />
</React.Suspense>
)}
</Container>
{!props.auth?.token &&
[
'/',
'/signup',
'/login',
'/password-reset',
'/projects/:id',
'/ambassadors',
'/creators/:username',
'/privacy_policy',
'/terms_of_use',
'/about',
'/challenge',
'/email-confirm',
'/password-reset-confirm',
].includes(location?.pathname) && <div style={{ minHeight: '90vh' }}>{childrenRenderer()}</div>}

<footer className={clsx('footer-distributed', classes.footerStyle)}>
<Box>
118 changes: 27 additions & 91 deletions zubhub_frontend/zubhub/src/views/login/Login.jsx
Original file line number Diff line number Diff line change
@@ -25,18 +25,14 @@ import {
FormControl,
} from '@mui/material';

import {
validationSchema,
handleClickShowPassword,
handleMouseDownPassword,
login,
} from './loginScripts';

import { withFormik } from 'formik';

import { validationSchema, handleClickShowPassword, handleMouseDownPassword, login } from './loginScripts';

import CustomButton from '../../components/button/Button';
import * as AuthActions from '../../store/actions/authActions';
import styles from '../../assets/js/styles/views/login/loginStyles';

const useStyles = makeStyles(styles);

/**
@@ -75,33 +71,15 @@ function Login(props) {
noValidate="noValidate"
onSubmit={e => handleSetState(login(e, props))}
>
<Typography
gutterBottom
variant="h5"
component="h2"
color="textPrimary"
className={classes.titleStyle}
>
<Typography gutterBottom variant="h5" component="h2" color="textPrimary" className={classes.titleStyle}>
{t('login.welcomeMsg.primary')}
</Typography>
<Typography
className={classes.descStyle}
variant="body2"
color="textSecondary"
component="p"
>
<Typography className={classes.descStyle} variant="body2" color="textSecondary" component="p">
{t('login.welcomeMsg.secondary')}
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box
component="p"
className={
props.status &&
props.status['non_field_errors'] &&
classes.errorBox
}
>
<Box component="p" className={props.status && props.status['non_field_errors'] && classes.errorBox}>
{props.status && props.status['non_field_errors'] && (
<Box component="span" className={classes.error}>
{props.status['non_field_errors']}
@@ -121,10 +99,7 @@ function Login(props) {
(props.touched['username'] && props.errors['username'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="username"
>
<InputLabel className={classes.customLabelStyle} htmlFor="username">
{t('login.inputs.username.label')}
</InputLabel>
<OutlinedInput
@@ -136,16 +111,11 @@ function Login(props) {
onBlur={props.handleBlur}
label={t('login.inputs.username.label')}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
<FormHelperText className={classes.fieldHelperTextStyle} error>
{(props.status && props.status['username']) ||
(props.touched['username'] &&
props.errors['username'] &&
t(
`login.inputs.username.errors.${props.errors['username']}`,
))}
t(`login.inputs.username.errors.${props.errors['username']}`))}
</FormHelperText>
</FormControl>
</Grid>
@@ -162,10 +132,7 @@ function Login(props) {
(props.touched['password'] && props.errors['password'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="password"
>
<InputLabel className={classes.customLabelStyle} htmlFor="password">
{t('login.inputs.password.label')}
</InputLabel>
<OutlinedInput
@@ -179,32 +146,21 @@ function Login(props) {
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={() =>
handleSetState(handleClickShowPassword(state))
}
onClick={() => handleSetState(handleClickShowPassword(state))}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{show_password ? (
<Visibility />
) : (
<VisibilityOff />
)}
{show_password ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
}
label={t('login.inputs.password.label')}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
<FormHelperText className={classes.fieldHelperTextStyle} error>
{(props.status && props.status['password']) ||
(props.touched['password'] &&
props.errors['password'] &&
t(
`login.inputs.password.errors.${props.errors['password']}`,
))}
t(`login.inputs.password.errors.${props.errors['password']}`))}
</FormHelperText>
</FormControl>
</Grid>
@@ -226,36 +182,22 @@ function Login(props) {
<Grid item xs={12}>
<Box className={classes.center}>
<Divider className={classes.divider} />
<Typography
className={classes.dividerText}
variant="body2"
color="textSecondary"
component="p"
>
<Typography className={classes.dividerText} variant="body2" color="textSecondary" component="p">
{t('login.notAMember')}
</Typography>
<Divider className={classes.divider} />
</Box>
</Grid>
<Grid item xs={12}>
<Link to="/signup" className={classes.textDecorationNone}>
<CustomButton
variant="outlined"
size="large"
secondaryButtonStyle
customButtonStyle
fullWidth
>
<Link to={`/signup${props.location.search}`} className={classes.textDecorationNone}>
<CustomButton variant="outlined" size="large" secondaryButtonStyle customButtonStyle fullWidth>
{t('login.signup')}
</CustomButton>
</Link>
</Grid>
<Grid item xs={12}>
<Box className={classes.center}>
<Link
to="/password-reset"
className={classes.secondaryLink}
>
<Link to="/password-reset" className={classes.secondaryLink}>
{t('login.forgotPassword')}
</Link>
</Box>
@@ -275,22 +217,16 @@ Login.propTypes = {
login: PropTypes.func.isRequired,
};

const mapStateToProps = state => {
return {
auth: state.auth,
};
};
const mapStateToProps = state => ({
auth: state.auth,
});

const mapDispatchToProps = dispatch => {
return {
setAuthUser: auth_user => {
dispatch(AuthActions.setAuthUser(auth_user));
},
login: args => {
return dispatch(AuthActions.login(args));
},
};
};
const mapDispatchToProps = dispatch => ({
setAuthUser: auth_user => {
dispatch(AuthActions.setAuthUser(auth_user));
},
login: args => dispatch(AuthActions.login(args)),
});

export default connect(
mapStateToProps,
38 changes: 18 additions & 20 deletions zubhub_frontend/zubhub/src/views/login/loginScripts.js
Original file line number Diff line number Diff line change
@@ -30,26 +30,24 @@ export const handleMouseDownPassword = e => {
export const login = (e, props) => {
e.preventDefault();
props.setFieldTouched('username', true);
return props
.login({ values: props.values, navigate: props.navigate })
.catch(error => {
const messages = JSON.parse(error.message);
if (typeof messages === 'object') {
const server_errors = {};
Object.keys(messages).forEach(key => {
if (key === 'non_field_errors') {
server_errors['non_field_errors'] = messages[key][0];
} else {
server_errors[key] = messages[key][0];
}
});
props.setStatus({ ...server_errors });
} else {
props.setStatus({
non_field_errors: props.t('login.errors.unexpected'),
});
}
});
return props.login({ values: props.values, navigate: props.navigate, location: props.location }).catch(error => {
const messages = JSON.parse(error.message);
if (typeof messages === 'object') {
const server_errors = {};
Object.keys(messages).forEach(key => {
if (key === 'non_field_errors') {
server_errors['non_field_errors'] = messages[key][0];
} else {
server_errors[key] = messages[key][0];
}
});
props.setStatus({ ...server_errors });
} else {
props.setStatus({
non_field_errors: props.t('login.errors.unexpected'),
});
}
});
};

/**
178 changes: 66 additions & 112 deletions zubhub_frontend/zubhub/src/views/profile/Profile.jsx
Original file line number Diff line number Diff line change
@@ -6,43 +6,34 @@ import { Link } from 'react-router-dom';
import { connect } from 'react-redux';

import { toast } from 'react-toastify';
import API from '../../api';
import { TEAM_ENABLED } from '../../utils.js';

import { makeStyles } from '@mui/styles';
import ShareIcon from '@mui/icons-material/Share';
import MoreVertIcon from '@mui/icons-material/MoreVert';
import {
Tooltip,
Badge,
Avatar,
Grid,
Box,
Container,
Paper,
Card,
CardContent,
Menu,
MenuItem,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Fab,
Typography,
OutlinedInput,
InputLabel,
FormControl,
Divider,
} from '@mui/material';

import API from '../../api';
import { TEAM_ENABLED } from '../../utils.js';
import {
getUserProfile,
copyProfileUrl,
// copyProfileUrl,
updateProjects,
toggleFollow,
sortTags,
handleMoreMenuOpen,
handleMoreMenuClose,
handleToggleDeleteAccountModal,
deleteAccount,
getUserTeams,
@@ -57,7 +48,6 @@ import ErrorPage from '../error/ErrorPage';
import LoadingPage from '../loading/LoadingPage';
import Project from '../../components/project/Project';
import Comments from '../../components/comments/Comments';
import Team from '../../views/team/Team';
import { parseComments, isBaseTag } from '../../assets/js/utils/scripts';

import styles from '../../assets/js/styles/views/profile/profileStyles';
@@ -81,7 +71,6 @@ function Profile(props) {
const username = props.params.username || props.auth.username;
const [page, setPage] = useState(1);
const [userActivity, setUserActivity] = useState([]);
const [scrollPosition, setScrollPosition] = useState(0);
const [nextPage, setNextPage] = useState(false);
const [teams, setTeams] = useState([]);
const [state, setState] = React.useState({
@@ -95,9 +84,21 @@ function Profile(props) {
badge_tags: [],
});

const handleSetTeams = newTeams => {
newTeams && setTeams(teams => [...teams, ...newTeams]);
};

const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState(state => ({ ...state, ...obj }));
});
}
};

React.useEffect(() => {
try {
let activitylogObj = new API();
const activitylogObj = new API();
const promises = [getUserProfile(props), getUserTeams(props), activitylogObj.getUserActivity(username, page)];
if (username === props.auth.username) {
promises.push(
@@ -133,30 +134,8 @@ function Profile(props) {
}
}, [page]);

const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState(state => ({ ...state, ...obj }));
});
}
};

const handleSetTeams = newTeams => {
newTeams && setTeams(teams => [...teams, ...newTeams]);
};
const { results: projects, profile, loading, open_delete_account_modal, dialog_error, drafts, badge_tags } = state;

const {
results: projects,
profile,
loading,
open_delete_account_modal,
dialog_error,
more_anchor_el,
drafts,
badge_tags,
} = state;

const more_menu_open = Boolean(more_anchor_el);
const { t } = props;

const handleScroll = e => {
@@ -269,8 +248,8 @@ function Profile(props) {
{profile.bio
? profile.bio
: !profile.members_count
? t('profile.about.placeholder1')
: t('profile.about.placeholder2')}
? t('profile.about.placeholder1')
: t('profile.about.placeholder2')}
</Paper>

<Paper className={classes.badgeBox}>
@@ -308,28 +287,23 @@ function Profile(props) {
</div>
</Paper>

{TEAM_ENABLED== true ? (<Paper className= {classes.profileLowerStyle}>
<Typography
gutterBottom
component="h2"
variant="h6"
color="textPrimary"
className= {classes.titleStyle}
>
{t('Teams')}
<CustomButton
className={classes.teamButton}
variant="contained"
margin="normal"
primaryButtonStyle
onClick={() => props.navigate('/create-team')}
>
{t('profile.createteam')}
</CustomButton>
</Typography>
<Grid container spacing={2}>
{TEAM_ENABLED === true ? (
<Paper className={classes.profileLowerStyle}>
<Typography gutterBottom component="h2" variant="h6" color="textPrimary" className={classes.titleStyle}>
{t('Teams')}
<CustomButton
className={classes.teamButton}
variant="contained"
margin="normal"
primaryButtonStyle
onClick={() => props.navigate('/create-team')}
>
{t('profile.createteam')}
</CustomButton>
</Typography>
<Grid container spacing={2}>
{teams.map(team => (
<Grid item xs={12} sm={6} md={6} className={classes.projectGridStyle} align="center">
<Grid key={team.id} item xs={12} sm={6} md={6} className={classes.projectGridStyle} align="center">
<Link to={`/teams/${team.groupname}`} className={classes.textDecorationNone}>
<Card>
<CardContent className={classes.mediaBoxStyle}>
@@ -393,7 +367,15 @@ function Profile(props) {
<Grid container spacing={3}>
{Array.isArray(projects) &&
projects.map(project => (
<Grid item xs={12} sm={6} md={4} className={classes.projectGridStyle} align="center">
<Grid
key={project.id}
item
xs={12}
sm={6}
md={4}
className={classes.projectGridStyle}
align="center"
>
<Project
project={project}
key={project.id}
@@ -453,7 +435,7 @@ function Profile(props) {
</CustomButton>
<CustomButton
variant="contained"
onClick={e => handleSetState(deleteAccount(username_el, props, state))}
onClick={() => handleSetState(deleteAccount(username_el, props, state))}
dangerButtonStyle
customButtonStyle
>
@@ -483,54 +465,26 @@ Profile.propTypes = {
toggleSave: PropTypes.func.isRequired,
};

const mapStateToProps = state => {
return {
auth: state.auth,
};
};
const mapStateToProps = state => ({
auth: state.auth,
});

const mapDispatchToProps = dispatch => {
return {
setAuthUser: auth_user => {
dispatch(AuthActions.setAuthUser(auth_user));
},
getUserProfile: args => {
return dispatch(UserActions.getUserProfile(args));
},
getUserTeams: args => {
return dispatch(UserActions.getUserTeams(args));
},
toggleTeamFollow: args => {
return dispatch(UserActions.toggleTeamFollow(args));
},
suggestCreators: args => {
return dispatch(UserActions.suggestCreators(args));
},
addComment: args => {
return dispatch(UserActions.addComment(args));
},
unpublishComment: args => {
return dispatch(ProjectActions.unpublishComment(args));
},
deleteComment: args => {
return dispatch(ProjectActions.deleteComment(args));
},
deleteAccount: args => {
return dispatch(AuthActions.deleteAccount(args));
},
logout: args => {
return dispatch(AuthActions.logout(args));
},
toggleFollow: args => {
return dispatch(UserActions.toggleFollow(args));
},
toggleLike: args => {
return dispatch(ProjectActions.toggleLike(args));
},
toggleSave: args => {
return dispatch(ProjectActions.toggleSave(args));
},
};
};
const mapDispatchToProps = dispatch => ({
setAuthUser: auth_user => {
dispatch(AuthActions.setAuthUser(auth_user));
},
getUserProfile: args => dispatch(UserActions.getUserProfile(args)),
getUserTeams: args => dispatch(UserActions.getUserTeams(args)),
toggleTeamFollow: args => dispatch(UserActions.toggleTeamFollow(args)),
suggestCreators: args => dispatch(UserActions.suggestCreators(args)),
addComment: args => dispatch(UserActions.addComment(args)),
unpublishComment: args => dispatch(ProjectActions.unpublishComment(args)),
deleteComment: args => dispatch(ProjectActions.deleteComment(args)),
deleteAccount: args => dispatch(AuthActions.deleteAccount(args)),
logout: args => dispatch(AuthActions.logout(args)),
toggleFollow: args => dispatch(UserActions.toggleFollow(args)),
toggleLike: args => dispatch(ProjectActions.toggleLike(args)),
toggleSave: args => dispatch(ProjectActions.toggleSave(args)),
});

export default connect(mapStateToProps, mapDispatchToProps)(Profile);
66 changes: 24 additions & 42 deletions zubhub_frontend/zubhub/src/views/profile/profileScripts.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
import { BASE_TAGS } from '../../assets/js/utils/constants';
import { getUserDrafts } from '../../store/actions/projectActions';

/**
* @function getUserProfile
* @author Raymond Ndibe <ndiberaymond1@gmail.com>
*
* @todo - describe function's signature
*/ export const getUserProfile = props => {
let username = props.params.username;

if (!username) {
username = props.auth.username;
} else if (props.auth.username === username) props.navigate('/profile', { replace: true });
*/
export const getUserProfile = props => {
const username = props.params.username || props.auth.username;
if (props.auth.username === username) props.navigate('/profile', { replace: true });
return props.getUserProfile({
username,
token: props.auth.token,
t: props.t,
});
};

export const followTeam = (groupname, username,props) => {
let token=props.auth.token;
props.toggleTeamFollow({groupname, username, token})
export const followTeam = (groupname, username, props) => {
const token = props.auth.token;
props.toggleTeamFollow({ groupname, username, token });
};

/**
* @function getUserTeams
* @author Hemant <hks@iamhks.com>
*
* @todo - describe function's signature
*/ export const getUserTeams = props => {
*/
export const getUserTeams = props => {
let username = props.params.username;

if (!username) {
@@ -69,18 +67,14 @@ export const copyProfileUrl = (profile, props, toast) => {
*
* @todo - describe function's signature
*/
export const updateProjects = (res, projects, props, toast) => {
return res
export const updateProjects = (res, projects, props, toast) =>
res
.then(res => {
if (res.project && res.project.title) {
if (projects[0]) {
projects = projects.map(project =>
project.id === res.project.id ? res.project : project,
);
projects = projects.map(project => (project.id === res.project.id ? res.project : project));
} else {
projects = projects.results.map(project =>
project.id === res.project.id ? res.project : project,
);
projects = projects.results.map(project => (project.id === res.project.id ? res.project : project));
}
return { results: projects };
} else {
@@ -98,21 +92,18 @@ export const updateProjects = (res, projects, props, toast) => {
}
return { loading: false };
});
};

/**
* @function updateProjects
* @author Raymond Ndibe <ndiberaymond1@gmail.com>
*
* @todo - describe function's signature
*/
export const updateDrafts = (res, projects, props, toast) => {
return res
export const updateDrafts = (res, projects, props, toast) =>
res
.then(res => {
if (res.project && res.project.title) {
projects = projects.map(project =>
project.id === res.project.id ? res.project : project,
);
projects = projects.map(project => (project.id === res.project.id ? res.project : project));
return { drafts: projects };
} else {
res = Object.keys(res)
@@ -129,7 +120,6 @@ export const updateDrafts = (res, projects, props, toast) => {
}
return { loading: false };
});
};

/**
* @function toggleFollow
@@ -158,10 +148,10 @@ export const toggleFollow = (id, props) => {
* @param {Array} tags - an array containing tag strings
* @returns {Array} - sorted array of tags.
*/
export const sortTags = tags => {
return tags.sort((a, b) => {
export const sortTags = tags =>
tags.sort((a, b) => {
if (BASE_TAGS.includes(a) && BASE_TAGS.includes(b)) {
//standard reverse sort.
// standard reverse sort.
if (a > b) {
return -1;
} else {
@@ -171,36 +161,28 @@ export const sortTags = tags => {
return -1;
} else if (BASE_TAGS.includes(b)) {
return 1;
} else if (a > b) {
return 1;
} else {
//standard sort.
if (a > b) {
return 1;
} else {
return -1;
}
return -1;
}
});
};

/**
* @function handleMoreMenuOpen
* @author Raymond Ndibe <ndiberaymond1@gmail.com>
*
* @todo - describe function's signature
*/
export const handleMoreMenuOpen = e => {
return { more_anchor_el: e.currentTarget };
};
export const handleMoreMenuOpen = e => ({ more_anchor_el: e.currentTarget });

/**
* @function handleMoreMenuClose
* @author Raymond Ndibe <ndiberaymond1@gmail.com>
*
* @todo - describe function's signature
*/
export const handleMoreMenuClose = () => {
return { more_anchor_el: null };
};
export const handleMoreMenuClose = () => ({ more_anchor_el: null });

/**
* @function handleToggleDeleteAccountModal
285 changes: 66 additions & 219 deletions zubhub_frontend/zubhub/src/views/signup/Signup.jsx

Large diffs are not rendered by default.

63 changes: 23 additions & 40 deletions zubhub_frontend/zubhub/src/views/signup/signupScripts.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as Yup from 'yup';
import countryMap from '../../assets/js/countryMap.json';
import intlTelInput from 'intl-tel-input';
import { calculateLabelWidth } from '../../assets/js/utils/scripts';
import { toast } from 'react-toastify';

import countryMap from '../../assets/js/countryMap.json';
import { calculateLabelWidth } from '../../assets/js/utils/scripts';

/**
* @constant vars
* @author Raymond Ndibe <ndiberaymond1@gmail.com>
@@ -14,8 +15,7 @@ export const vars = {
phone_field_touched: undefined,
email_field_touched: undefined,
iti: undefined,
utils_scripts_url:
'https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.13/js/utils.min.js',
utils_scripts_url: 'https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.13/js/utils.min.js',
preferred_countries: ['in', 'us'],
};

@@ -35,9 +35,7 @@ export const handleMouseDownPassword = e => {
*
* @todo - describe function's signature
*/
export const getLocations = props => {
return props.getLocations({ t: props.t });
};
export const getLocations = props => props.getLocations({ t: props.t });

/**
* @function signup
@@ -71,6 +69,7 @@ export const signup = (e, props) => {
phone: vars.iti.getNumber(),
},
navigate: props.navigate,
location: props.location,
})
.catch(error => {
const messages = JSON.parse(error.message);
@@ -104,19 +103,15 @@ export const signup = (e, props) => {
*
* @todo - describe function's signature
*/
export const handleTooltipOpen = () => {
return { tool_tip_open: true };
};
export const handleTooltipOpen = () => ({ tool_tip_open: true });

/**
* @function handleTooltipClose
* @author Raymond Ndibe <ndiberaymond1@gmail.com>
*
* @todo - describe function's signature
*/
export const handleTooltipClose = () => {
return { tool_tip_open: false };
};
export const handleTooltipClose = () => ({ tool_tip_open: false });

/**
* @function handleToggleSubscribeBox
@@ -125,7 +120,7 @@ export const handleTooltipClose = () => {
* @todo - describe function's signature
*/
export const handleToggleSubscribeBox = (e, props, state) => {
let subscribe_box_checked = !state.subscribe_box_checked;
const subscribe_box_checked = !state.subscribe_box_checked;
props.setFieldValue('subscribe', subscribe_box_checked);
return { subscribe_box_checked };
};
@@ -137,11 +132,7 @@ export const handleToggleSubscribeBox = (e, props, state) => {
* @todo - describe function's signature
*/
export const handleLocationChange = (e, props) => {
if (
vars.iti?.setCountry &&
e.target.value &&
vars.iti.getSelectedCountryData().iso2 !== countryMap[e.target.value]
) {
if (vars.iti?.setCountry && e.target.value && vars.iti.getSelectedCountryData().iso2 !== countryMap[e.target.value]) {
vars.iti.setCountry(countryMap[e.target.value]);
}
props.handleChange(e);
@@ -156,8 +147,8 @@ export const handleLocationChange = (e, props) => {
export const setLocationWithTelCountry = props => {
if (vars.iti?.getSelectedCountryData) {
let country_name;
let keys = Object.keys(countryMap);
for (let i = 0; i < keys.length; i++) {
const keys = Object.keys(countryMap);
for (let i = 0; i < keys.length; i += 1) {
if (countryMap[keys[i]] === vars.iti.getSelectedCountryData().iso2) {
country_name = keys[i];
break;
@@ -182,9 +173,7 @@ export const initIntlTelInput = (props, refs) => {
preferredCountries: vars.preferred_countries,
utilsScript: vars.utils_scripts_url,
});
refs.phone_el.current.firstChild.addEventListener('countrychange', () =>
setLocationWithTelCountry(props),
);
refs.phone_el.current.firstChild.addEventListener('countrychange', () => setLocationWithTelCountry(props));

setTimeout(() => setLocationWithTelCountry(props), 1000);
}
@@ -217,23 +206,17 @@ export const validationSchema = Yup.object().shape({
username: Yup.string().required('required'),
email: Yup.string()
.email('invalid')
.test('email_is_empty', 'phoneOrEmail', function (value) {
return vars.email_field_touched && !value && !this.parent.phone
? false
: true;
}),
.test('email_is_empty', 'phoneOrEmail', value =>
vars.email_field_touched && !value && !this.parent.phone ? false : true,
),
phone: Yup.string()
.test('phone_is_invalid', 'invalid', function () {
return vars.iti.isValidNumber() || !vars.iti.getNumber() ? true : false;
})
.test('phone_is_empty', 'phoneOrEmail', function () {
return vars.phone_field_touched &&
!vars.iti.getNumber() &&
!this.parent.email
? false
: true;
}),
dateOfBirth: Yup.date().max(new Date(new Date().getFullYear() - 12, 1, 1), 'oldEnough').required('required'),
.test('phone_is_invalid', 'invalid', () => (vars.iti.isValidNumber() || !vars.iti.getNumber() ? true : false))
.test('phone_is_empty', 'phoneOrEmail', () =>
vars.phone_field_touched && !vars.iti.getNumber() && !this.parent.email ? false : true,
),
dateOfBirth: Yup.date()
.max(new Date(new Date().getFullYear() - 12, 1, 1), 'oldEnough')
.required('required'),
user_location: Yup.string().min(1, 'min').required('required'),
password1: Yup.string().min(8, 'min').required('required'),
password2: Yup.string()

0 comments on commit ee7e64f

Please sign in to comment.