Related
I was following the documentation to implement google map on demand rides and deliveries solution (ODRD) here.
And my Map component in React:
const MapComponent = ({ styles }) => {
const ref = useRef(null);
const tripId = useRef<string>('');
const locationProvider =
useRef<google.maps.journeySharing.FleetEngineTripLocationProvider>();
const [error, setError] = useState<string | undefined>();
const mapOptions = useRef<MapOptionsModel>({
showAnticipatedRoutePolyline: true,
showTakenRoutePolyline: true,
destinationMarker: ICON_OPTIONS.USE_DEFAULT,
vehicleMarker: ICON_OPTIONS.USE_DEFAULT,
});
const [trip, setTrip] = useState<TripModel>({
status: null,
dropOff: null,
waypoints: null,
});
const setTripId = (newTripId: string) => {
tripId.current = newTripId;
if (locationProvider.current) locationProvider.current.tripId = newTripId;
};
const setMapOptions = (newMapOptions: MapOptionsModel) => {
mapOptions.current.showAnticipatedRoutePolyline =
newMapOptions.showAnticipatedRoutePolyline;
mapOptions.current.showTakenRoutePolyline =
newMapOptions.showTakenRoutePolyline;
mapOptions.current.destinationMarker = newMapOptions.destinationMarker;
mapOptions.current.vehicleMarker = newMapOptions.vehicleMarker;
setTripId(tripId.current);
};
const authTokenFetcher = async () => {
const response = await fetch(
`${PROVIDER_URL}/token/consumer/${tripId.current}`
);
const responseJson = await response.json();
return {
token: responseJson.jwt,
expiresInSeconds: 3300,
};
};
useEffect(() => {
locationProvider.current =
new google.maps.journeySharing.FleetEngineTripLocationProvider({
projectId: PROVIDER_PROJECT_ID,
authTokenFetcher,
tripId: tripId.current,
pollingIntervalMillis: DEFAULT_POLLING_INTERVAL_MS,
});
locationProvider.current.addListener(
'error',
(e: google.maps.ErrorEvent) => {
setError(e.error.message);
}
);
locationProvider.current.addListener(
'update',
(
e: google.maps.journeySharing.FleetEngineTripLocationProviderUpdateEvent
) => {
if (e.trip) {
setTrip({
status: e.trip.status,
dropOff: e.trip.dropOffTime,
waypoints: e.trip.remainingWaypoints,
});
setError(undefined);
}
}
);
const mapViewOptions: google.maps.journeySharing.JourneySharingMapViewOptions =
{
element: ref.current as unknown as Element,
locationProvider: locationProvider.current,
anticipatedRoutePolylineSetup: ({ defaultPolylineOptions }) => {
return {
polylineOptions: defaultPolylineOptions,
visible: mapOptions.current.showAnticipatedRoutePolyline,
};
},
takenRoutePolylineSetup: ({ defaultPolylineOptions }) => {
return {
polylineOptions: defaultPolylineOptions,
visible: mapOptions.current.showTakenRoutePolyline,
};
},
destinationMarkerSetup: ({ defaultMarkerOptions }) => {
if (
mapOptions.current.destinationMarker !== ICON_OPTIONS.USE_DEFAULT
) {
defaultMarkerOptions.icon =
mapOptions.current.destinationMarker.icon;
}
return { markerOptions: defaultMarkerOptions };
},
vehicleMarkerSetup: ({ defaultMarkerOptions }) => {
if (mapOptions.current.vehicleMarker !== ICON_OPTIONS.USE_DEFAULT) {
// Preserve some default icon properties.
if (defaultMarkerOptions.icon) {
defaultMarkerOptions.icon = Object.assign(
defaultMarkerOptions.icon,
mapOptions.current.vehicleMarker.icon
);
}
}
return { markerOptions: defaultMarkerOptions };
},
};
const mapView = new google.maps.journeySharing.JourneySharingMapView(
mapViewOptions
);
// Provide default zoom & center so the map loads even if trip ID is bad or stale.
mapView.map.setOptions(DEFAULT_MAP_OPTIONS);
}, []);
return (
<div style={styles.map} ref={ref} />
);
};
And my App component like this:
import React from 'react';
import { Wrapper, Status } from '#googlemaps/react-wrapper';
import MapComponent from './src/components/MapComponent';
import { API_KEY } from './src/utils/consts';
const render = (status: Status) => <Text>{status}</Text>;
const App = () => {
return (
<Wrapper
apiKey={API_KEY}
render={render}
version={'beta'}
// #ts-ignore
libraries={['journeySharing']}
>
<MapComponent />
</Wrapper>
);
};
Everything will works fine but I do not know how to destroy the map when component unmount in React. That's why my App always call API update the trip info.
I was tried to use clean up function in useEffect:
useEffect(() => {
locationProvider.current =
new google.maps.journeySharing.FleetEngineTripLocationProvider({
projectId: PROVIDER_PROJECT_ID,
authTokenFetcher,
tripId: tripId.current,
pollingIntervalMillis: DEFAULT_POLLING_INTERVAL_MS,
});
locationProvider.current.addListener(
'error',
(e: google.maps.ErrorEvent) => {
setError(e.error.message);
}
);
const updateEvent = locationProvider.current.addListener(
'update',
(
e: google.maps.journeySharing.FleetEngineTripLocationProviderUpdateEvent
) => {
if (e.trip) {
setTrip({
status: e.trip.status,
dropOff: e.trip.dropOffTime,
waypoints: e.trip.remainingWaypoints,
});
setError(undefined);
}
}
);
const mapViewOptions: google.maps.journeySharing.JourneySharingMapViewOptions =
{
element: ref.current as unknown as Element,
locationProvider: locationProvider.current,
anticipatedRoutePolylineSetup: ({ defaultPolylineOptions }) => {
return {
polylineOptions: defaultPolylineOptions,
visible: mapOptions.current.showAnticipatedRoutePolyline,
};
},
takenRoutePolylineSetup: ({ defaultPolylineOptions }) => {
return {
polylineOptions: defaultPolylineOptions,
visible: mapOptions.current.showTakenRoutePolyline,
};
},
destinationMarkerSetup: ({ defaultMarkerOptions }) => {
if (
mapOptions.current.destinationMarker !== ICON_OPTIONS.USE_DEFAULT
) {
defaultMarkerOptions.icon =
mapOptions.current.destinationMarker.icon;
}
return { markerOptions: defaultMarkerOptions };
},
vehicleMarkerSetup: ({ defaultMarkerOptions }) => {
if (mapOptions.current.vehicleMarker !== ICON_OPTIONS.USE_DEFAULT) {
// Preserve some default icon properties.
if (defaultMarkerOptions.icon) {
defaultMarkerOptions.icon = Object.assign(
defaultMarkerOptions.icon,
mapOptions.current.vehicleMarker.icon
);
}
}
return { markerOptions: defaultMarkerOptions };
},
};
const mapView = new google.maps.journeySharing.JourneySharingMapView(
mapViewOptions
);
// Provide default zoom & center so the map loads even if trip ID is bad or stale.
mapView.map.setOptions(DEFAULT_MAP_OPTIONS);
return () => {
mapView.map = null // or mapView.map.setmap(null);
google.maps.event.removeListener(updateEvent);
};
}, []);
But it was not working. Hope anyone can help me find out this. Thanks
My code pass in a search term and the promise api call returns one record and the data format is as below:
` json api data
0:
{
id:"aff3b4fa-bdc0-47d1-947f-0163ff5bea06"
keyword: somekeyword
URL:"mypage.html"
}
I need to retrieve the URL value, so I try to get URL by using response.data[0].URL. But I receive the error "Unhandled Rejection (TypeError): response.data[0] is undefined". How do I get the URL value? Thanks.
` autocomplete.js
export class Autocomplete extends Component {
state = {
activeSuggestion: 0,
filteredSuggestions: [],
showSuggestions: false,
userInput: "",
suggestions: [],
results: [],
URL: "",
};
componentDidMount() {
this.GetPrograms();
const { userInput } = this.state;
//this.runSearch();
}
GetPrograms = () => {
axios
.get("https://mydomain/GetPrograms/")
.then((response) => {
this.setState({ suggestions: response.data });
});
};
runSearch = async () => {
const response = await axios.get(
"https://mydomain/api/get",
{
params: {
searchTerm: this.state.userInput,
},
}
);
let results = response.data;
console.log("response", results);
this.setState({ results: results, URL: response.data[0].URL });
window.location.href =
"https://mydomain/" + this.state.URL;
};
onChange = (e) => {
const { suggestions } = this.state; //this.props;
const userInput = e.currentTarget.value;
const filteredSuggestions = suggestions.filter(
(suggestion) =>
suggestion.toLowerCase().indexOf(userInput.toLowerCase()) > -1
);
this.setState({
activeSuggestion: 0,
filteredSuggestions,
showSuggestions: true,
userInput: e.currentTarget.value,
});
};
onClick = (e) => {
this.setState({
activeSuggestion: 0,
filteredSuggestions: [],
showSuggestions: false,
userInput: e.currentTarget.innerText,
});
this.onSearch();
console.log(
"child component clicked and value=" + e.currentTarget.innerText
);
};
onKeyDown = (e) => {
const { activeSuggestion, filteredSuggestions } = this.state;
if (e.keyCode === 13) {
this.setState({
activeSuggestion: 0,
showSuggestions: false,
userInput: filteredSuggestions[activeSuggestion],
});
} else if (e.keyCode === 38) {
if (activeSuggestion === 0) {
return;
}
this.setState({ activeSuggestion: activeSuggestion - 1 });
} else if (e.keyCode === 40) {
if (activeSuggestion - 1 === filteredSuggestions.length) {
return;
}
this.setState({ activeSuggestion: activeSuggestion + 1 });
}
//this.setState({ searchTerm: e.currentTarget.value });
console.log("userinput:" + this.state.userInput);
};
render() {
const {
onChange,
onClick,
onKeyDown,
onKeyPress,
state: {
activeSuggestion,
filteredSuggestions,
showSuggestions,
userInput,
},
} = this;
let suggestionsListComponent;
if (showSuggestions && userInput) {
if (filteredSuggestions.length) {
suggestionsListComponent = (
<ul class="suggestions">
{filteredSuggestions.map((suggestion, index) => {
let className;
if (index === activeSuggestion) {
className = "";
}
return (
<li key={suggestion} onClick={onClick}>
{suggestion}
</li>
);
})}
</ul>
);
} else {
suggestionsListComponent = (
<div class="no-suggestions">
<em>No suggestions</em>
</div>
);
}
}
return (
<div>
<input
id="search-box"
placeholder="Search..."
type="search"
onChange={onChange}
onKeyDown={onKeyDown}
value={userInput}
/>
{suggestionsListComponent}
</div>
);
}
}
export default Autocomplete;
`
The api call returns 0 record that causes the error.
I am new to react context and testing. I have used react context in my application but now I want to test the application but I don't know how to access values from context in test file. I am attaching component and context file.
My component file:
import React, { useContext } from 'react'
import constants, {
parametersEnum,
commandParametersEnum,
commandTypeEnum,
} from '../../../constants'
import Parameters from '../Parameters'
import { OTAFormContext } from '../../utils/Context/OTAFormContext'
export const componentTestId = 'SelectorNetwork'
function OTARequestCommandParameters(props) {
const { formData, updateFormData } = useContext(OTAFormContext)
let command = formData.COMMAND_TYPE
if (!command) return null
const commandObject = constants.OTARequestCommands.choices.find(
(_p) => _p.value === command,
)
console.log('formData==>', formData) //remove later
const supportedParameters = commandObject.parameters
let parameters = supportedParameters.map((parameter) => {
let onChange = null
let options = null
let preFilledValue = null
switch (command) {
case commandTypeEnum.CHANGE_PREFERRED_PLMN: {
if (
parameter.type === parametersEnum.textAreaInput &&
parameter.value === commandParametersEnum.NEW_PREFERRED_PLMN
) {
preFilledValue = formData.CHANGE_PREFERRED_PLMN.NEW_PREFERRED_PLMN
onChange = (e) => {
updateFormData({
...formData,
CHANGE_PREFERRED_PLMN: { NEW_PREFERRED_PLMN: e.target.value, },
})
}
}
break
}
case commandTypeEnum.CHANGE_SMSC_NUMBER: {
if (
parameter.type === parametersEnum.inputTextBox &&
parameter.value === commandParametersEnum.NEW_SMSC_NUMBER
) {
preFilledValue = formData.CHANGE_SMSC_NUMBER.NEW_SMSC_NUMBER
onChange = (e) => {
updateFormData({
...formData,
CHANGE_SMSC_NUMBER: { NEW_SMSC_NUMBER: e.target.value },
})
}
}
break
}
case commandTypeEnum.FORCED_PREFERRED_IMSI_SWITCH: {
if (
parameter.type === parametersEnum.textAreaInput &&
parameter.value === commandParametersEnum.NEW_FULL_PREFERRED_IMSI_FILE
) {
preFilledValue = formData.FORCED_PREFERRED_IMSI_SWITCH.NEW_FULL_PREFERRED_IMSI_FILE
onChange = (e) => {
updateFormData({
...formData,
FORCED_PREFERRED_IMSI_SWITCH: { NEW_FULL_PREFERRED_IMSI_FILE: e.target.value, },
})
}
}
break
}
case commandTypeEnum.MODIFY_PREFERRED_IMSI: {
if (
parameter.type === parametersEnum.textAreaInput &&
parameter.value === commandParametersEnum.NEW_FULL_PREFERRED_IMSI_FILE
) {
preFilledValue = formData.MODIFY_PREFERRED_IMSI.NEW_FULL_PREFERRED_IMSI_FILE
onChange = (e) => {
updateFormData({
...formData,
MODIFY_PREFERRED_IMSI: { NEW_FULL_PREFERRED_IMSI_FILE: e.target.value, },
})
}
}
break
}
case commandTypeEnum.SYNC_AN_IMSI: {
options = parameter.options
if (
parameter.type === parametersEnum.dropdown &&
parameter.value === commandParametersEnum.ACTION_TO_SYNC
) {
preFilledValue = formData.SYNC_AN_IMSI.ACTION_TO_SYNC
onChange = (e, data) => {
updateFormData({
...formData,
SYNC_AN_IMSI: {
...formData.SYNC_AN_IMSI,
ACTION_TO_SYNC: data.value,
},
})
}
}
if (
parameter.type === parametersEnum.dropdown &&
parameter.value === commandParametersEnum.TARGET_IMSI_PROFILE
) {
preFilledValue = formData.SYNC_AN_IMSI.TARGET_IMSI_PROFILE
onChange = (e, data) => {
updateFormData({
...formData,
SYNC_AN_IMSI: {
...formData.SYNC_AN_IMSI,
TARGET_IMSI_PROFILE: data.value,
},
})
}
}
break
}
}
const _arguments = {
parameterName: parameter.type,
onChange,
label: parameter.label,
placeholder: parameter.placeholder,
options,
preFilledValue: preFilledValue,
}
return <Parameters {..._arguments} />
})
return <div data-testid={componentTestId}>{parameters}</div>
}
export default OTARequestCommandParameters
My context file:
import React, { useState, createContext } from 'react'
import constants from '../../../constants'
export const OTAFormContext = createContext()
const OTAFormContextProvider = (props) => {
let defaultFormData = constants.defaultContextFormData
const [formData, setFormData] = useState(defaultFormData)
const updateFormData = (data) => {
setFormData(data)
}
return (
<OTAFormContext.Provider value={{ formData, updateFormData }}>
{props.children}
</OTAFormContext.Provider>
)
}
export default OTAFormContextProvider
Constants.js:
defaultContextFormData: {
COMMAND_TYPE: '',
ICCID: '',
CHANGE_PREFERRED_PLMN: {
NEW_PREFERRED_PLMN: '',
},
CHANGE_SMSC_NUMBER: {
NEW_SMSC_NUMBER: '',
},
FORCED_PREFERRED_IMSI_SWITCH: {
NEW_FULL_PREFERRED_IMSI_FILE: '',
},
MODIFY_PREFERRED_IMSI: {
NEW_FULL_PREFERRED_IMSI_FILE: '',
},
SYNC_AN_IMSI: {
ACTION_TO_SYNC: '',
TARGET_IMSI_PROFILE: '',
},
},
Test:
const _constants = constants.OTARequestCommands
let _network = _constants.choices.map((item) => [item.value, item.label])
test.each(_network)(
'Verify that passing selectedNetwork %j is correctly reflected',
(name) => {
const formData = { COMMAND_TYPE: name }
const component = render(
<OTAFormContext.Provider value={formData}>
<OTARequestCommandSelector />
</OTAFormContext.Provider>,
)
const { queryAllByText } = component
queryAllByText(name).forEach((item) => {
const { getByText } = within(item)
expect(getByText(name)).toBeInTheDocument()
})
},
)
Error:
TypeError: Cannot read property 'COMMAND_TYPE' of undefined
22 | onChange: onCommandChange,
23 | options: options,
> 24 | value: formData.COMMAND_TYPE,
| ^
25 | }
26 | return (
27 | <div className="otaRequestCommandSelector" data-testid={componentTestId}>
How to test OTARequestCommandParameters component? How to test context in the test? I have attached Test and Error.
You just render the context with your component.
const formData = { COMMAND_TYPE: 'Type anything you expect' }
const component = render(
<OTAFormContext.Provider value={{ formData }}>
<OTARequestCommandSelector />
</OTAFormContext.Provider>,
)
See Mocking Context with React Testing Library
I have an issue with my React application (with Redux Saga), I'm getting the console error:
The service worker navigation preload request was cancelled before 'preloadResponse' settled. If you intend to use 'preloadResponse', use waitUntil() or respondWith() to wait for the promise to settle.
I see this error on the console only on Chrome, not in Firefox or Edge.
This error does not affect my application.
The following steps reproduce the error:
1. Main page upload.
2. Go to movie details page.
3. Go back to main page.
Main.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { mainActions } from '../../store/actions/actions';
import './Main.scss';
import { MoviesList, SearchPanel } from '../../components';
const propTypes = {};
const defaultProps = {};
class Main extends Component {
constructor(props) {
super(props);
this.handleSearchTextChange = this.handleSearchTextChange.bind(this);
this.handleLoadMoreButtonClick = this.handleLoadMoreButtonClick.bind(this);
this.handleMovieClick = this.handleMovieClick.bind(this);
this.handleFavoriteMovieClick = this.handleFavoriteMovieClick.bind(this);
}
componentDidMount() {
this.handleComponentDidMount();
}
handleComponentDidMount() {
const { moviesList } = this.props;
if (!moviesList || moviesList.length <= 0) {
this.getMovies(null, false);
}
}
handleLoadMoreButtonClick() {
this.getMovies(null, false);
}
handleMovieClick(e) {
if (e.target.className === 'movie') {
this.props.history.push(`/details/${e.currentTarget.dataset.id}`);
}
}
handleSearchTextChange(e) {
const { pageNumber, favoriteMoviesList } = this.props;
this.props.onSearchTextChange({
searchText: e.target.value,
pageNumber: pageNumber,
favoriteMoviesList: favoriteMoviesList
});
}
handleFavoriteMovieClick(e) {
const { id, name, posterId } = e.currentTarget.dataset;
const { moviesList, favoriteMoviesList } = this.props;
this.props.onUpdateFavoriteMovies({
updatedMovie: { id: id, name: name, posterId: posterId },
favoriteMoviesList: favoriteMoviesList,
moviesList: moviesList
});
}
getMovies(updatedSearchText, isSearchChange) {
const { searchText, pageNumber, favoriteMoviesList } = this.props;
this.props.onLoadMovies({
pageNumber: pageNumber,
favoriteMoviesList: favoriteMoviesList,
updatedSearchText: isSearchChange ? updatedSearchText : searchText,
isSearchChange: isSearchChange
});
}
render() {
const { searchText, isLoadingMoreMovies, isPager, moviesList } = this.props;
return (
<div className="main-area">
<SearchPanel
searchText={searchText}
onSearchTextChange={this.handleSearchTextChange}
/>
<MoviesList
pageName='movies'
moviesList={moviesList}
isLoadingMoreMovies={isLoadingMoreMovies}
isPager={isPager}
onLoadMoreClick={this.handleLoadMoreButtonClick}
onMovieClick={this.handleMovieClick}
onFavoriteMovieClick={this.handleFavoriteMovieClick}
/>
</div>
);
}
}
Main.propTypes = propTypes;
Main.defaultProps = defaultProps;
const mapStateToProps = (state) => {
return {
searchText: state.main.searchText,
pageNumber: state.main.pageNumber,
isLoadingMoreMovies: state.main.isLoadingMoreMovies,
isPager: state.main.isPager,
moviesList: state.main.moviesList,
favoriteMoviesList: state.main.favoriteMoviesList
};
};
const mapDispatchToProps = (dispatch) => {
return {
onLoadMovies: (request) => dispatch(mainActions.loadMovies(request)),
onSearchTextChange: (request) => dispatch(mainActions.searchTextChange(request)),
onUpdateFavoriteMovies: (request) => dispatch(mainActions.updateFavoriteMovies(request))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Main);
Details.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { detailsActions, mainActions } from '../../store/actions/actions';
import './Details.scss';
import { ActorsList, ButtonClick, CrewsList, FeaturesList, PageTitle, ProductionsList, Rating, Trailer } from '../../components';
import movieUtils from '../../utils/movie.utils';
const propTypes = {};
const defaultProps = {};
class Details extends Component {
constructor(props) {
super(props);
this.handleBackClick = this.handleBackClick.bind(this);
this.handleFavoriteMovieClick = this.handleFavoriteMovieClick.bind(this);
this.isFavorite = false;
}
componentDidMount() {
this.handleComponentDidMount();
}
handleComponentDidMount() {
if (this.props.moviesList.length <= 0) {
this.handleBackClick();
return;
}
const movieId = this.props.match.params.id;
if (!movieId) {
this.handleBackClick();
return;
}
this.props.onLoadMovieDetails(movieId);
this.updateIsFavorite(movieId);
}
numberWithCommas(number) {
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
updateIsFavorite(movieId) {
this.isFavorite = this.props.favoriteMoviesList.findIndex(movie => parseInt(movie.id) === parseInt(movieId)) > -1;
}
handleBackClick() {
this.props.history.push(`/`);
}
handleFavoriteMovieClick() {
const { movie, moviesList, favoriteMoviesList } = this.props;
this.props.onUpdateFavoriteMovies({
updatedMovie: { id: movie.id, name: movie.title, posterId: movie.poster_path },
favoriteMoviesList: favoriteMoviesList,
moviesList: moviesList
});
this.updateIsFavorite(movie.id);
}
render() {
const { movie, youtubeKey, credits } = this.props;
if (!movie) {
return null;
}
const { adult, poster_path, budget, genres, homepage, imdb_id, original_language, original_title,
overview, popularity, production_companies, production_countries, release_date, revenue, runtime, spoken_languages,
status, tagline, title, video, vote_average, vote_count } = movie;
const genresText = genres.map(genre => genre.name).join(', ');
const countriesText = production_countries.map(country => country.name).join(', ');
const languagesText = spoken_languages.map(language => language.name).join(', ');
const featuresList = [
{ item: 'Release Date', value: release_date },
{ item: 'Budget', value: `$${this.numberWithCommas(budget)}` },
{ item: 'Revenue', value: `$${this.numberWithCommas(revenue)}` },
{ item: 'Length', value: `${runtime} minutes` },
{ item: 'Popularity', value: popularity },
{ item: 'Original Title', value: original_title },
{ item: 'For Adults', value: adult ? 'Yes' : 'No' },
{ item: 'Original Language', value: original_language },
{ item: 'Spoken Languages', value: languagesText },
{ item: 'Countries', value: countriesText },
{ item: 'Status', value: status },
{ item: 'Is Video', value: video ? 'Yes' : 'No' }
];
const linksList = [];
if (homepage) {
linksList.push({ id: 1, name: 'Homepage', url: homepage });
}
if (imdb_id) {
linksList.push({ id: 2, name: 'IMDB', url: `https://www.imdb.com/title/${imdb_id}` });
}
const actorsList = movieUtils.removeDuplicates(credits ? credits.cast ? credits.cast : null : null, 'name');
const crewsList = movieUtils.removeDuplicates(credits ? credits.crew ? credits.crew : null : null, 'name');
return (
<div>
<section className="details-area">
<PageTitle
pageName='details'
pageTitle='Details'
/>
<ul className="details-content">
<li className="details-left" style={{ backgroundImage: `url('https://image.tmdb.org/t/p/original${poster_path}')` }}></li>
<li className="details-right">
<h2>{title} ({release_date.substr(0, 4)})</h2>
<p className="genres">{genresText}</p>
<p className="description short">{tagline}</p>
<Rating
rating={vote_average}
votesCount={this.numberWithCommas(vote_count)}
/>
<p className="description full">{overview}</p>
<div className="extra">
<FeaturesList
featuresList={featuresList.slice(0, 5)}
linksList={null}
isFavorite={this.isFavorite}
onFavoriteMovieClick={this.handleFavoriteMovieClick}
/>
{youtubeKey && <Trailer
youtubeKey={youtubeKey}
/>}
</div>
</li>
<div className="extra-features">
<FeaturesList
featuresList={featuresList.slice(5, featuresList.length)}
linksList={linksList}
isFavorite={null}
onFavoriteMovieClick={null}
/>
<ProductionsList
productionsList={production_companies}
/>
</div>
</ul>
</section>
<section className="actors-area">
<PageTitle
pageName='actors'
pageTitle='Cast'
/>
<ActorsList
actorsList={actorsList}
/>
</section>
<section className="crew-area">
<PageTitle
pageName='crew'
pageTitle='Crew'
/>
<CrewsList
crewsList={crewsList}
/>
</section>
<ButtonClick
buttonText={'Back'}
buttonTitle={'Back'}
isLoading={false}
onClick={this.handleBackClick}
/>
</div>
);
}
}
Details.propTypes = propTypes;
Details.defaultProps = defaultProps;
const mapStateToProps = (state) => {
return {
movie: state.details.movie,
youtubeKey: state.details.youtubeKey,
credits: state.details.credits,
moviesList: state.main.moviesList,
favoriteMoviesList: state.main.favoriteMoviesList
};
};
const mapDispatchToProps = (dispatch) => {
return {
onLoadMovieDetails: (movieId) => dispatch(detailsActions.loadDetails(movieId)),
onUpdateFavoriteMovies: (request) => dispatch(mainActions.updateFavoriteMovies(request))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Details);
What I already looked in:
Getting The service worker navigation preload request was cancelled before 'preloadResponse' settled
https://learn.microsoft.com/en-us/answers/questions/108004/getting-the-service-worker-navigation-preload-requ.html
https://support.google.com/mail/thread/4055804?hl=en
https://love2dev.com/pwa/service-worker-preload/
I tried to put this on Details.jsx page, but it didn't work:
self.addEventListener('fetch', event => {
event.respondWith(async function () {
// Respond from the cache if we can
const cachedResponse = await caches.match(event.request);
if (cachedResponse) return cachedResponse; // Else, use the preloaded response, if it's there
const response = await event.preloadResponse;
if (response) return response; // Else try the network.
return fetch(event.request);
}());
});
self.addEventListener('activate', event => {
event.waitUntil(async function () {
// Feature-detect
if (self.registration.navigationPreload) { // Enable navigation preloads!
console.log('Enable navigation preloads!');
await self.registration.navigationPreload.enable();
} return;
})();
});
How can I solve this issue? Thanks.
Had same error, even my iframe wasn't loading..whatever video you are using from youtube use nocookie/embed in url. It's working for me.
Try changing https://www.youtube.com/watch?v=i8eBBG46H8A to
https://www.youtube-nocookie.com/embed/i8eBBG46H8A
Hope nocookie & embed helps..!!
I want my bot to send the message when i click on the desired suggestion. i.e. i want the message to be sent - when i click on the suggestion or by selecting the suggestion using arrow keys and then pressing enter . But as of now, if i click or select the suggestion using arrow keys - the suggestion value comes to the text box and then i have to press enter to send the message. I just want to change that.
Any help would be greatly appreciated
My code is as follows,
import React from 'react';
import { DirectLine, ConnectionStatus } from 'botframework-directlinejs';
import ReactWebChat from 'botframework-webchat';
import './ChatComponent.css';
var val;
var apiParameters = [];
var currentFocus = -1;
export default class extends React.Component {
constructor(props) {
super(props);
this.state = {
token: '',
conversationId: '',
directLine: {},
view: false,
feedBack: null,
value: '',
popupContent: '',
storeValue: '',
suggestions: [],
suggestionCallback: '',
suggestionTypedText: "",
typingChecking: "false",
};
this.handleTokenGeneration = this.handleTokenGeneration.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleSaveFeedback = this.handleSaveFeedback.bind(this);
this.handleSuggestion = this.handleSuggestion.bind(this);
this.handleClose = this.handleClose.bind(this);
this.handleSuggestionClick = this.handleSuggestionClick.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.moveHighlight = this.moveHighlight.bind(this);
this.getSuggestionHtml = this.getSuggestionHtml.bind(this);
}
getSuggestionHtml(suggestion) {
const lowerCaseSuggestion = suggestion.toLowerCase();
return {
__html: lowerCaseSuggestion.includes(this.state.suggestionTypedText) ? lowerCaseSuggestion
.replace(this.state.suggestionTypedText, `<b>${this.state.suggestionTypedText}</b>`) : lowerCaseSuggestion
};
}
handleTokenGeneration = async () => {
console.log("11111");
const response = await fetch(`api/TokenGenerationService/GetToken`);
const data = await response.json();
this.setState({ token: data.categoryObject.token, conversationId: data.categoryObject.conversationId });
this.state.directLine = new DirectLine({ token: this.state.token });
this.setState({ view: true });
this.setState({ typingChecking: "true" });
console.log("conversationId");
};
async handleSuggestion(val, store) {
if (val === "") {
this.setState({
suggestions: []
});
}
else {
apiParameters = [];
var valuess = null;
const response = await fetch(`api/TokenGenerationService/GetAzureSearch?myparam1=${val}`);
const data = await response.json();
var values = ["Hello", "yes", "no", "exit", "Welcome", "Thank You", "Approve", "Apply leave", "Reject", "Absence Balance", "Leave Balance", "Upcoming Holidays", "Apply Comp-Off", "Approve Leave", "Raise Incident Tickets", "Project Allocation Info", "Reporting Manager Change", "Reporting Manager Approval", "Approve Isolve Tickets", "My Manager", "My Account Manager", "Generate Salary Certificate", "Isolve Ticket Status", "Internal Job Posting", "My Designation", "My Joining Date", "RM Approval", "RM Change", "Resource Allocation", "ESettlement Approval", "SO Approval", "Cash advance Approval", "Purchase Request Approval", "Referral status", "HR Ticket", "Platinum Support"];
valuess = values.filter(s =>
s.toLocaleLowerCase().startsWith(val.toLowerCase())
);
valuess = valuess.concat(data.az_search);
this.setState({
suggestions: valuess,
suggestionCallback: store,
suggestionTypedText: val.toLowerCase()
});
var totCount = data.az_search;
console.log("kkkkkk" + totCount);
var myNode = document.getElementById('Suggestion1');
}
}
getSuggestionCss(index) {
var HIGHLIGHTED_CSS = "HIGHLIGHTED_CSS";
var SUGGESTION_CSS = "SUGGESTION_CSS";
console.log("jioouu" + this.state.highlightedIndex);
return index === this.state.highlightedIndex ? HIGHLIGHTED_CSS : SUGGESTION_CSS;
}
moveHighlight(event, direction) {
event.preventDefault();
const { suggestions, highlightedIndex=-1 } = this.state;
if (!suggestions.length) return;
let newIndex = (highlightedIndex + direction + suggestions.length) % suggestions.length;
console.log("lokkkk" + direction)
if (newIndex !== highlightedIndex) {
console.log("kkkkkkkkkkkkkkkkkkk")
this.setState({
highlightedIndex: newIndex,
});
}
}
keyDownHandlers = {
ArrowDown(event) {
this.moveHighlight(event, 1);
},
ArrowUp(event) {
this.moveHighlight(event, -1);
},
Enter(event) {
const { suggestions } = this.state;
if (!suggestions.length) {
// menu is closed so there is no selection to accept -> do nothing
return
}
event.preventDefault()
this.applySuggestion(suggestions[this.state.highlightedIndex]);
},
}
handleKeyDown(event)
if (this.keyDownHandlers[event.key])
this.keyDownHandlers[event.key].call(this, event)
}
async handleSuggestionClick(event) {
await this.applySuggestion(event.currentTarget.textContent);
}
async applySuggestion(newValue) {
await this.setState({ typingChecking: "false", suggestions: [], highlightedIndex: 0 });
this.state.suggestionCallback.dispatch({
type: 'WEB_CHAT/SET_SEND_BOX',
payload: {
text: newValue,
}
});
await this.setState({ typingChecking: "true" });
}
handleClose(elmnt) {
var x = document.getElementsByClassName("autocomplete-items");
for (var i = 0; i < x.length; i++) {
if (elmnt !== x[i]) {
x[i].parentNode.removeChild(x[i]);
}
}
}
async componentDidMount() {
try {
await this.handleTokenGeneration();
const store =
window.WebChat.createStore(
{},
({ getState }) => next => action => {
this.state.directLine.connectionStatus$
.subscribe(connectionStatus => {
//console.log("connect" + connectionStatus);
//console.log("LOP" + ConnectionStatus.ExpiredToken);
if (connectionStatus === ConnectionStatus.ExpiredToken) {
console.log("expired");
}
if (action.type === 'WEB_CHAT/SET_SEND_BOX') {
const val = action.payload.text;
if (this.state.typingChecking === "true") {
this.setState({
highlightedIndex: -1,
});
console.log(this.state.typingChecking);
this.handleSuggestion(val, store);
}
}
if (action.type === 'DIRECT_LINE/DISCONNECT_FULFILLED') {
console.log("final" + connectionStatus);
console.log("finalexpired" + ConnectionStatus.ExpiredToken);
console.log("final");
this.handleTokenGeneration();
// fetch('api/TokenGenerationService/GetToken').then(conversation => this.state.directLine.reconnect(conversation))
}
});
return next(action)
}
);
this.setState({ storeValue: store });
} catch (error) {
console.log("error in fetching token");
console.log(error);
}
this.state.directLine.activity$
.filter(activity => activity.type === 'message')
.subscribe(function (activity)
{
//console.log("oooooooooooooooooooooo");
}
// message => console.log("received message ", message.text)
);
}
handleSaveFeedback(ans) {
var userID = "U92656";
var feedbackmsg = this.state.value;
var feedbacktype = this.state.feedBack;
var convId = this.state.conversationId;
fetch('api/Feedback/SaveFeedback',
{
method: "POST",
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ Uid: userID, FeedbackMessage: feedbackmsg, Convid: convId, FeedbackType: feedbacktype })
}).
then(response => response.text())
.then(data => {
console.log(data.getResult);
});
this.setState({ value: '' });
}
feedback(ans) {
this.setState({ feedBack: ans });
if (ans === "Send") {
this.handleSaveFeedback(ans);
}
else if (ans === "Yes") {
this.setState({ popupContent: "How was your experience?" });
// console.log(this.state.value)
}
else if (ans === "No") {
this.setState({ popupContent: "What went wrong?" });
// console.log(this.state.value)
}
}
handleChange = (event) => {
this.setState({ value: event.target.value });
}
render() {
if (!this.state.view) {
return <div />
} else {
const filteredSuggestions = this.state.suggestions.filter(
suggestion =>
suggestion.toLowerCase().indexOf(this.state.suggestionTypedText.toLowerCase()) > -1
);
return (
<div className="react-container webchat" >
<div onKeyDown={this.handleKeyDown.bind(this)}>
<div >
<ReactWebChat directLine={this.state.directLine} webSocket={true} userID='U92656' username='Thomas' store={this.state.storeValue} sendTypingIndicator={true} />
</div>
</div>
<div className="SuggestionParent" id="Suggestion1">
{this.state.suggestions.map((suggestion, index)=> (
<div className={this.getSuggestionCss(index)} key={index} onClick={this.handleSuggestionClick} >
{suggestion
.toLowerCase()
.startsWith(this.state.suggestionTypedText) ? (
<div>
<b>{this.state.suggestionTypedText}</b>
{suggestion
.toLowerCase()
.replace(this.state.suggestionTypedText, "")}
</div>
) : (
<div dangerouslySetInnerHTML={this.getSuggestionHtml(suggestion)} />
)}
</div>
))}
</div>
<footer className="chat-footer" >
<div className="foot-footer">
Was I helpful ?
<span className="feedback" onClick={() => this.feedback("Yes")} >Yes</span><span>|</span><span className="feedback" onClick={() => this.feedback("No")}>No</span>
{
this.state.feedBack === "Yes" || this.state.feedBack === "No" ?
(
<div className="dialog" id="myform">
<div id="textfeedback">
<span id="closeFeedback" onClick={() => this.feedback("Close")}>X</span>
<p>{this.state.popupContent}</p>
<input type="text" id="feedbacktxtbox" required name="textfeedback" placeholder="Pleasure to hear from u!"
onChange={this.handleChange}
value={this.state.value} />
<button type="button" id="btnfeedback" onClick={() => this.feedback("Send")}>send</button>
</div>
</div>
) : null
}
</div>
</footer>
</div>
);
}
}
}