From b563f22a32d69ca2bed58ac22d5c28008cdf1038 Mon Sep 17 00:00:00 2001 From: Nuwan Date: Sun, 14 Jan 2024 13:32:15 +0530 Subject: [PATCH] wip: profile edit --- .../components/dashboard/JKDashboardMain.js | 3 + jam-ui/src/components/page/JKEditProfile.js | 654 ++++++++++++++++++ jam-ui/src/helpers/rest.js | 37 + jam-ui/src/i18n/config.js | 4 + jam-ui/src/i18n/locales/en/profile.json | 3 + jam-ui/src/i18n/locales/es/profile.json | 3 + 6 files changed, 704 insertions(+) create mode 100644 jam-ui/src/components/page/JKEditProfile.js create mode 100644 jam-ui/src/i18n/locales/en/profile.json create mode 100644 jam-ui/src/i18n/locales/es/profile.json diff --git a/jam-ui/src/components/dashboard/JKDashboardMain.js b/jam-ui/src/components/dashboard/JKDashboardMain.js index dcd7b1c50..ba780ee43 100644 --- a/jam-ui/src/components/dashboard/JKDashboardMain.js +++ b/jam-ui/src/components/dashboard/JKDashboardMain.js @@ -32,6 +32,8 @@ import JKMusicSessions from '../page/JKMusicSessions'; import JKNewMusicSession from '../page/JKNewMusicSession'; import JKMusicSessionsLobby from '../page/JKMusicSessionsLobby'; +import JKEditProfile from '../page/JKEditProfile'; + //import loadable from '@loadable/component'; //const DashboardRoutes = loadable(() => import('../../layouts/JKDashboardRoutes')); //const PublicRoutes = loadable(() => import('../../layouts/JKPublicRoutes')) @@ -195,6 +197,7 @@ function JKDashboardMain() { + {/*Redirect*/} diff --git a/jam-ui/src/components/page/JKEditProfile.js b/jam-ui/src/components/page/JKEditProfile.js new file mode 100644 index 000000000..a1b606507 --- /dev/null +++ b/jam-ui/src/components/page/JKEditProfile.js @@ -0,0 +1,654 @@ +import React, { useRef, useEffect, useState, useReducer } from 'react'; +import { Card, CardBody, Col, Row, CardHeader, Form, FormGroup, Label, Input, Button } from 'reactstrap'; +import Select from 'react-select'; +import FalconCardHeader from '../common/FalconCardHeader'; +import { useTranslation } from 'react-i18next'; +import JKCurrentUserAvatar from '../navbar/JKCurrentUserAvatar'; +import { useAuth } from '../../context/UserAuth'; +import { useForm, Controller } from 'react-hook-form'; +import { + getPersonById, + getInstruments, + getGenres, + updateUser, + getCountries, + getRegions, + getCities +} from '../../helpers/rest'; +import { set } from 'lodash'; + +function JKEditProfile() { + const { t } = useTranslation(); + const { currentUser } = useAuth(); + const [musicInstruments, setMusicInstruments] = useState([]); + const [genres, setGenres] = useState([]); + const [instrumentsInitialLoadingDone, setInstrumentsInitialLoadingDone] = useState(false); + const [genreInitialLoadingDone, setGenreInitialLoadingDone] = useState(false); + const [countries, setCountries] = useState([]); + const [regions, setRegions] = useState([]); + const [cities, setCities] = useState([]); + + const [_, forceUpdate] = useReducer(x => x + 1, 0); + + const saveTimeoutRef = useRef(null); + const cityRef = useRef(null); + const regionRef = useRef(null); + + const PROFICIENCIES = [ + { value: '1', label: 'Beginner' }, + { value: '2', label: 'Intermediate' }, + { value: '3', label: 'Advanced' } + ]; + + const { register, control, handleSubmit, setValue, getValues } = useForm({ + defaultValues: { + firstName: '', + lastName: '', + country: '', + state: '', + city: '', + biography: '', + subscribeEmail: false, + virtualBand: false, + traditionalBand: false, + cowriting: false, + instruments: [], + genres: [] + } + }); + + useEffect(() => { + if (currentUser) { + fetchCurentUser().then(userData => { + console.log('_DEBUG userData', userData); + fetchInstruments(); + fetchGenres(); + fetchCountries(); + }); + } + }, [currentUser]); + + const fetchCurentUser = () => { + return new Promise((resolve, reject) => { + getPersonById(currentUser.id) + .then(response => { + if (response.ok) { + return response.json(); + } + }) + .then(data => { + setValue('firstName', data.first_name); + setValue('lastName', data.last_name); + setValue('country', data.country); + setValue('state', data.state); + setValue('city', data.city); + setValue('biography', data.biography); + setValue('subscribeEmail', data.subscribe_email); + setValue('virtualBand', data.virtual_band); + setValue('traditionalBand', data.traditional_band); + setValue('cowriting', data.cowriting); + setValue('instruments', data.instruments); + setValue('genres', data.genres); + if (data.country) { + fetchRegions(data.country); + } + if (data.country && data.state) { + fetchCities(data.country, data.state); + } + resolve(getValues()); + }) + .catch(error => reject(error)); + }); + }; + + const fetchInstruments = () => { + getInstruments() + .then(response => { + if (response.ok) { + return response.json(); + } + }) + .then(data => { + setMusicInstruments(data); + }) + .catch(error => console.log(error)); + }; + + useEffect(() => { + if (!musicInstruments.length || !getValues('instruments') || instrumentsInitialLoadingDone) return; + const updatedMusicInstruments = musicInstruments.map(musicInstrument => { + const instrument = getValues('instruments').find(instrument => instrument.instrument_id === musicInstrument.id); + if (instrument) { + musicInstrument.proficiency_level = instrument.proficiency_level; + musicInstrument.checked = true; + musicInstrument.instrument_id = instrument.instrument_id; + } else { + musicInstrument.proficiency_level = null; + musicInstrument.checked = false; + musicInstrument.instrument_id = null; + } + return musicInstrument; + }); + setMusicInstruments(updatedMusicInstruments); + setInstrumentsInitialLoadingDone(true); + }, [musicInstruments, getValues('instruments')]); + + const fetchGenres = () => { + getGenres() + .then(response => { + if (response.ok) { + return response.json(); + } + }) + .then(data => { + setGenres(data); + }) + .catch(error => { + console.log(error); + }); + }; + + useEffect(() => { + if (!genres.length || !getValues('genres') || genreInitialLoadingDone) return; + const updatedGenres = genres.map(genre => { + const userGenre = getValues('genres').find(userGenre => userGenre.genre_id === genre.id); + if (userGenre) { + genre.checked = true; + } else { + genre.checked = false; + } + genre.genre_id = genre.id; + return genre; + }); + setGenres(updatedGenres); + setGenreInitialLoadingDone(true); + }, [genres, getValues('genres')]); + + const fetchCountries = () => { + getCountries() + .then(response => { + if (response.ok) { + return response.json(); + } + }) + .then(data => { + setCountries(data.countriesx); + }) + .catch(error => console.log(error)); + }; + + const fetchRegions = countryCode => { + getRegions(countryCode) + .then(response => { + if (response.ok) { + return response.json(); + } + }) + .then(data => { + setRegions(data.regions); + }) + .catch(error => console.log(error)); + }; + + const fetchCities = (country, region) => { + getCities(country, region) + .then(response => { + if (response.ok) { + return response.json(); + } + }) + .then(data => { + setCities(data.cities); + }) + .catch(error => console.log(error)); + }; + + const onSubmit = data => console.log(data); + + const handleInstrumentSelect = (e, musicInstrument) => { + //alert(e.target.checked) + if (e.target.checked) { + const userInstruments = getValues('instruments'); + const thisInstrument = userInstruments.find( + instrument => instrument.instrument_id === musicInstrument.instrument_id + ); + if (thisInstrument) return; + const { id } = musicInstrument; + const updatedInstruments = [...userInstruments, { ...musicInstrument, instrument_id: id }]; + setValue('instruments', updatedInstruments); + } else { + const updatedInstruments = getValues('instruments').filter( + instrument => instrument.instrument_id !== musicInstrument.instrument_id + ); + setValue('instruments', updatedInstruments); + } + + const updatedMusicInstruments = musicInstruments.map(instrument => { + if (instrument.id === musicInstrument.id) { + instrument.checked = e.target.checked; + } else { + instrument.checked = instrument.checked; + } + return instrument; + }); + + setMusicInstruments(updatedMusicInstruments); + handleChange(); + }; + + const handleInstrumentProficiencyChange = (option, musicInstrument) => { + const userInstrument = getValues('instruments').find(instrument => instrument.instrument_id === musicInstrument.id); + if (!userInstrument) return; + userInstrument.proficiency_level = option.value; + forceUpdate(); + handleChange(); + }; + + const handleGenreChange = (e, genre) => { + if (e.target.checked) { + const userGenres = getValues('genres'); + const thisGenre = userGenres.find(userGenre => userGenre.genre_id === genre.genre_id); + if (thisGenre) return; + const updatedGenres = [...userGenres, { ...genre }]; + setValue('genres', updatedGenres); + } else { + const updatedGenres = getValues('genres').filter(userGenre => userGenre.genre_id !== genre.genre_id); + setValue('genres', updatedGenres); + } + + const updatedGenres = genres.map(genreItem => { + if (genreItem.genre_id === genre.genre_id) { + genreItem.checked = e.target.checked; + } else { + genreItem.checked = genreItem.checked; + } + return genreItem; + }); + + setGenres(updatedGenres); + handleChange(); + }; + + const handleTextInputChage = () => { + clearTimeout(saveTimeoutRef.current); + saveTimeoutRef.current = setTimeout(() => { + handleChange(); + }, 2000); + }; + + const skipRegionChange = useRef(false); + + const handleCountryChange = selectedOpt => { + const country = selectedOpt.value; + setValue('country', country); + setValue('state', null); + setValue('city', null); + setRegions([]); + skipRegionChange.current = true; + regionRef.current.select.clearValue(); + setCities([]); + cityRef.current.select.clearValue(); + fetchRegions(country.value); + forceUpdate(); + handleChange(); + }; + + const handleRegionChange = selectedOpt => { + if (skipRegionChange.current) { + skipRegionChange.current = false; + return; + } + const state = selectedOpt.value; + const country = getValues('country'); + setValue('state', state); + setValue('city', null); + setCities([]); + cityRef.current.select.clearValue(); + fetchCities(country, state); + handleChange(); + }; + + const handleChange = () => { + const params = getValues(); + const data = { + first_name: params.firstName, + last_name: params.lastName, + country: params.country, + state: params.state, + city: params.city, + biography: params.biography, + subscribe_email: params.subscribeEmail, + virtual_band: params.virtualBand, + traditional_band: params.traditionalBand, + cowriting: params.cowriting, + instruments: params.instruments, + genres: params.genres + }; + console.log('_DEBUG data', data); + // updateUser(currentUser.id, data).then(response => { + // if (response.ok) { + // return response.json(); + // } + // }).then(data => { + // console.log('_DEBUG data', data); + // } + // ).catch(error => console.log(error)); + }; + + return ( + + + +
+ + + + +
Basics
+
+ + + + + + ( + { + onChange(e); + handleTextInputChage(); + }} + /> + )} + /> + + + + + + ( + { + onChange(e); + handleTextInputChage(); + }} + /> + )} + /> + + + +
+
+ +
+ +
+ +
+ + + + + {countries.length > 0 && ( + { + const country = countries.find(country => country.countrycode === value); + return ( + { + return { value: region.region, label: region.region }; + })} + /> + ); + }} + /> + )} + + + + + + ( + { + onChange(e); + handleTextInputChage(); + }} + /> + )} + /> + + + ( + { + onChange(e); + handleChange(); + }} + /> + )} + /> + + +
+
+ + + +
Interests
+
+ + + ( + { + onChange(e); + handleChange(); + }} + type="checkbox" + /> + )} + /> + + + + ( + { + onChange(e); + handleChange(); + }} + type="checkbox" + /> + )} + /> + + + + ( + { + onChange(e); + handleChange(); + }} + type="checkbox" + /> + )} + /> + + + +
+ + + + +
Instruments
+
+ + + {instrumentsInitialLoadingDone && + musicInstruments.map((musicInstrument, index) => { + return ( + + + { + handleInstrumentSelect(e, musicInstrument); + }} + type="checkbox" + checked={musicInstrument.checked} + /> + + + + + { + handleGenreChange(e, genre); + }} + type="checkbox" + checked={genre.checked} + /> + + + + ); + })} + + +
+ +
+
+
+
+ ); +} + +export default JKEditProfile; diff --git a/jam-ui/src/helpers/rest.js b/jam-ui/src/helpers/rest.js index 586ea2a30..f6ec11d3d 100644 --- a/jam-ui/src/helpers/rest.js +++ b/jam-ui/src/helpers/rest.js @@ -182,3 +182,40 @@ export const getLobbyChatMessages = (options = {}) => { .catch(error => reject(error)) }) } + + +export const updateUser = (userId, options) => { + return new Promise((resolve, reject) => { + apiFetch(`/users/${userId}`, { + method: 'PATCH', + body: JSON.stringify(options) + }) + .then(response => resolve(response)) + .catch(error => reject(error)) + }) +} + + +export const getCountries = () => { + return new Promise((resolve, reject) => { + apiFetch(`/countries`) + .then(response => resolve(response)) + .catch(error => reject(error)) + }) +} + +export const getRegions = (countryId) => { + return new Promise((resolve, reject) => { + apiFetch(`/regions?country=${countryId}`) + .then(response => resolve(response)) + .catch(error => reject(error)) + }) +} + +export const getCities = (countryId, regionId) => { + return new Promise((resolve, reject) => { + apiFetch(`/cities?country=${countryId}®ion=${regionId}`) + .then(response => resolve(response)) + .catch(error => reject(error)) + }) +} \ No newline at end of file diff --git a/jam-ui/src/i18n/config.js b/jam-ui/src/i18n/config.js index 8d6c08072..56c791242 100644 --- a/jam-ui/src/i18n/config.js +++ b/jam-ui/src/i18n/config.js @@ -7,6 +7,7 @@ import peopleTranslationsEN from './locales/en/people.json' import authTranslationsEN from './locales/en/auth.json' import sessTranslationsEN from './locales/en/sessions.json' import unsubscribeTranslationsEN from './locales/en/unsubscribe.json' +import profileEN from './locales/en/profile.json' import commonTranslationsES from './locales/es/common.json' import homeTranslationsES from './locales/es/home.json' @@ -14,6 +15,7 @@ import peopleTranslationsES from './locales/es/people.json' import authTranslationsES from './locales/es/auth.json' import sessTranslationsES from './locales/es/sessions.json' import unsubscribeTranslationsES from './locales/es/unsubscribe.json' +import profileES from './locales/es/profile.json' i18n.use(initReactI18next).init({ fallbackLng: 'en', @@ -27,6 +29,7 @@ i18n.use(initReactI18next).init({ auth: authTranslationsEN, sessions: sessTranslationsEN, unsubscribe: unsubscribeTranslationsEN, + profile: profileEN }, es: { //translations: require('./locales/es/translations.json') @@ -36,6 +39,7 @@ i18n.use(initReactI18next).init({ auth: authTranslationsES, sessions: sessTranslationsES, unsubscribe: unsubscribeTranslationsES, + profile: profileES } }, //ns: ['translations'], diff --git a/jam-ui/src/i18n/locales/en/profile.json b/jam-ui/src/i18n/locales/en/profile.json new file mode 100644 index 000000000..2eade7bb7 --- /dev/null +++ b/jam-ui/src/i18n/locales/en/profile.json @@ -0,0 +1,3 @@ +{ + "page_title": "Profile" +} diff --git a/jam-ui/src/i18n/locales/es/profile.json b/jam-ui/src/i18n/locales/es/profile.json new file mode 100644 index 000000000..2eade7bb7 --- /dev/null +++ b/jam-ui/src/i18n/locales/es/profile.json @@ -0,0 +1,3 @@ +{ + "page_title": "Profile" +}