onNotificationOpenedApp & getInitialNotification don't fire anymore on IOS (expo) - reactjs

async function onMessageReceived({ title, body, orderId }: { title: string; body: string; orderId?: string }) {
await notifee.createChannel({
id: "main",
name: "Main",
sound: "default",
vibration: false,
importance: AndroidImportance.HIGH,
});
await notifee.displayNotification({
title,
body,
android: {
channelId: "main",
badgeCount: 0,
},
ios: {
badgeCount: 0,
sound: "default",
},
});
notifee.onBackgroundEvent(({ type, detail }) => {
if (type === EventType.PRESS && orderId && isAuthenticated) {
navigate("order", { id: Number(orderId) });
}
});
}
React.useEffect(() => {
messaging().onNotificationOpenedApp(async (remoteMessage) => {
Alert.alert("Notification caused app to open from background state:", JSON.stringify(remoteMessage));
});
messaging().getInitialNotification().then(async (remoteMessage) => {
Alert.alert("Notification caused app to open from background state:", JSON.stringify(remoteMessage));
});
const unsubscribe = messaging().onMessage(async (remoteMessage) => {
// console.log({ remoteMessage });
// Alert.alert("A new FCM message arrived!", JSON.stringify(remoteMessage));
await onMessageReceived({
title: remoteMessage.notification?.title ?? "",
body: remoteMessage.notification?.body ?? "",
orderId: remoteMessage.data?.orderId,
});
});
return () => {
unsubscribe();
};
}, []);
This is my logic for handling the events
This is my code for the setBackgroundMessageHandler:
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
console.log("Message handled in the background!", remoteMessage);
// you could do things like incrementing badge count, doesnt work tho
await notifee.incrementBadgeCount();
});
It appears the setBackgroundMessageHandler doesn't fire.
On android the onNotificationOpenedApp & getInitialNotification works perfect but on ios it stopped working. It worked before, but now i can't get it working anymore.

Related

How to use PATCH method in react.js and typescript using react-query

I want to use the PATCH method to update a list of items instead of PUT. I have be able to remove any CORS blockers. The issue is the response i receive when i update is null and all the forms are then replaced.
task.service.ts
const update = async (id: any, { TaskName, TaskDescription, TaskOwner, TaskStatus, Skills, InitiativeLink, InitiativeName, TimeCommitment }: Task) => {
const response = await apiClient.patch<any>(`/tasks/${id}`, { TaskName, TaskDescription, TaskOwner, TaskStatus, Skills, InitiativeLink, InitiativeName, TimeCommitment });
return response.data;
};
OwnerHome.tsx
const { isLoading: isUpdatingTask, mutate: updateTask } = useMutation(
(putId: string) => {
return TaskService.update(
putId,
{
TaskName: putName,
InitiativeName: putInitiativeName,
TaskDescription: putDescription,
TaskOwner: putOwner,
InitiativeLink: putInitiativeLink,
Skills: putSkills,
TimeCommitment: putTimeCommitment,
TaskStatus: putStatus,
});
},
{
onSuccess: (res) => {
setPutResult(fortmatResponse(res));
},
onError: (err: any) => {
setPutResult(fortmatResponse(err.response?.data || err));
},
},
);
useEffect(() => {
if (isUpdatingTask) setGetResult('updating...');
}, [isUpdatingTask]);
function putData() {
if (selectedItems[0]) {
try {
updateTask(selectedItems[0].ID);
// setVisible(true);
} catch (err) {
setPutResult(fortmatResponse(err));
}
}
}

Why does not cypress alias work on Github CI?

I have a problem in github ci, it cannot find the alias, and think it even doesn't define that, but all is well on local. I tested on both cypress:open and cypress:run
this is the command I defiend:
Cypress.Commands.add("byPassLogin", () => {
const url = Cypress.env("api_url");
const token = "...";
cy.saveToLocalStorage("auth_token", token);
cy.intercept("POST", url, (req) => {
if (req.body.operationName === "me") {
req.reply({
statusCode: 200,
body: {
data: {
me: { id: "1", email: "test#email.com" },
},
},
});
}
}).as("byPassLogin");
});
and then I used it on beforeEach like this
describe("test account functionality", () => {
const URL = Cypress.env("api_url");
beforeEach(() => {
cy.visit("/");
cy.byPassLogin();
});
it.only("should logout when click on nav bar", () => {
cy.intercept("POST", URL, (req) => {
if (req.body.operationName === "signOut") {
req.reply({
statusCode: 200,
body: {
data: { updateUser: { errors: null, user: { id: "1" } } },
},
});
}
}).as("signOut");
cy.wait("#byPassLogin").then(() => {
cy.url().should("include", "/app");
cy.get("#account").click();
cy.get("#logout").click();
cy.wait("#signOut").then(() => {
cy.url().should("include", "/login");
});
});
});
});
I used another approach, it works on local but still not work on CI
Cypress.Commands.add("byPassLogin", () => {
const url = Cypress.env("api_url");
const token = "...";
cy.intercept("POST", url, (req) => {
req.reply({
statusCode: 200,
body: {
data: {
login: { user: { id: "1", email: "test#email.com" }, token },
},
},
});
}).as("byPassLogin");
cy.visit("/").then(() => {
cy.get("#email").type("test#email.com");
cy.get("#password").type("123456");
cy.get("button[type=submit]").click();
cy.wait("#byPassLogin").then(() => {
cy.url().should("include", "/app");
});
});
and used it like this
describe("test account functionality", () => {
const URL = Cypress.env("api_url");
beforeEach(() => {
cy.byPassLogin();
});
it.only("should logout when click on nav bar", () => {
cy.intercept("POST", URL, (req) => {
if (req.body.operationName === "signOut") {
req.reply({
statusCode: 200,
body: {
data: { updateUser: { errors: null, user: { id: "1" } } },
},
});
}
}).as("signOut");
cy.get("#account").click();
cy.get("#logout").click();
cy.wait("#signOut").then(() => {
cy.url().should("include", "/login");
});
});
error:
CypressError: Timed out retrying after 5000ms: cy.wait() timed out waiting 5000ms for the 1st request to the route: byPassLogin. No request ever occurred.
any help would be appreciated
cypress version: 8.4.1
react: 18
It seems that you should reverse the order of commands in the beforeEach()
beforeEach(() => {
cy.byPassLogin();
cy.visit("/");
})
There is nothing in the command flow between cy.intercept(...).as("byPassLogin") and cy.wait("#byPassLogin") except the signOut intercept.
As you probably know cy.intercept() is a command to set up a listener on the network requests, but it does not trigger any event in the app.
The sequence for intercepting is
set up the intercept listener
trigger the request (e.g cy.visit() or .click())
wait for the alias
Thanks to #fody I succeed to manage the issue, to find the issue I used a workflow similar to this to record my testing in dashboard.cypress.io, then I found it does not post form data to the correct endpoint URL, actually since the URL has been defined in env I needed to define it in CI as well.
That's it.
It was working since I had the env in local.

props becomes undefined on page refresh which resist socket re-establishment

I have implemented the socket, which was not able to established after pressing F5 button,
when users logged into the app, socket has been establishes successfully, when I hit F5, page refreshes but socketConnection is not invoked because props is undefined due to which conditional statement has been failed to execute.
After inspecting I have found that, I invoked the main socket creation function inside App.js, it takes props as as argument and one conditional statement. I have found that the props itself is undefined due to which the socket i not able t re-established.
App.js
import React, { useEffect } from 'react';
import './App.scss';
import Routes from './Routes';
import { connect } from 'react-redux';
import socketConnection from '#Hoc/SocketComponent';
const App = () => {
useEffect((props) => {
if (props?.session?.user?.extraDetails?.extensionNo) {
socketConnection(props);
}
}, []);
return (
<div>
<Routes />
</div>
);
};
const mapStateToProps = (state) => ({
session: state.session
});
export default connect(mapStateToProps)(App);
SocketComponent
export default function socketConnection(socketEvent) {
if (!window?.socket)
sessionService.loadUser().then((currentUser) => {
if (
currentUser?.extraDetails?.extensionNo &&
currentUser?.params?.AgentID
)
socket = window.socket = io(REACT_APP_SOCKET_URL, {
query: {
agentId: currentUser.params.AgentID,
extensionNo: currentUser.extraDetails.extensionNo,
},
});
socket.on("connect", (data) => {
console.info(data);
});
socket.on("EventEstablished", (data) => {
eventEstablished(data, currentUser, socketEvent);
});
socket.on("EventAgentLogout", () => {
notification.error({
message: "Softphone loggedout, please re-login",
duration: 0,
});
socketEvent.history.push("/home");
});
socket.on("EventPropertiesChanged", (data) => {
manualGeocode(data);
});
socket.on("EventAttachedDataChanged", (data) => {
if (data.data?.incidentNumber) {
store.dispatch({
type: SET_LIVE_CALL_DATA,
payLoad: { psapReferenceId: data?.data?.incidentNumber },
});
}
if (data.data?.updateLocation && data.data?.isRetransmit) {
let functionCall = "retransmit" ;
// if (data.data?.isRetransmit) {
// functionCall = "retransmit" ;
// }
getCallData( functionCall );
}
// manualGeocode(data);
});
socket.on("EventDestinationBusy", (data) => {
console.log("EventDestinationBusy", data);
});
socket.on("EventAbandoned", (data) => {
notification.error({
message: "Call abandoned",
description: "The caller abandoned the call before it was answered",
duration: 0,
});
});
socket.on("EventDNOutOfService", (data) => {
notification.error({
message: "Extension Out of Service !",
description:
"This extension is out of service and cannot make or receive calls. ",
duration: 0,
});
});
socket.on("EventAgentReady", (data) => {
console.log("EventAgentReady", data);
});
socket.on("EventAgentNotReady", (data) => {
console.log("EventAgentNotReady", data);
});
socket.on("EventReleased", (data) => {
eventReleased(data);
});
socket.on("EventPartyDeleted", (data) => {
eventPartyDeleted(data);
});
socket.on("EventInvite", (data) => {
console.log(data);
if (
!store?.getState()?.secondAgent?.secondAgent?.isSecondAgent &&
socketEvent.history.location.pathname === "/waiting"
) {
eventInvite(data, currentUser, socketEvent);
}
});
socket.on("disconnect", (data) => {
console.log(data);
});
socket.on("workflow", (data) => {
store.dispatch({ type: SET_WORKFLOW_DATA, payLoad: data });
});
socket.on("workflowUpdatedComponent", (data) => {
store.dispatch({ type: SET_WORKFLOW_OPTIONS, payLoad: data });
});
socket.on("gather-info", (data) => {
console.log(data);
if (data?.data?.extensionNo != currentUser.extraDetails.extensionNo) {
store.dispatch({
type: SET_GATHER_INFO,
payLoad: data?.data?.gatherInfo,
});
}
});
socket.on("geoCodeSession", (data) => {
console.log(data);
if (data?.data?.extensionNo != currentUser.extraDetails.extensionNo) {
if (data?.data?.updateLocation) {
store.dispatch({
type: SET_MANUAL_GEOCODE,
payLoad: { updateLocation: true },
});
}
// let timeFrame = new Date(data.data.timestamp);
// timestamp = timeFrame.toLocaleDateString() + ' ' + timeFrame.toLocaleTimeString();
store.dispatch({
type: SET_MANUAL_GEOCODE,
payLoad: {
status: true,
latitude: data?.data?.latitude,
longitude: data?.data?.longitude,
address: data?.data?.address,
country: data?.data?.country,
region: data?.data?.region,
timestamp: data?.data?.timestamp,
},
});
}
});
socket.on("EventSessionInfo", (data) => {
if (data?.data?.extensionNo !== currentUser?.extraDetails.extensionNo) {
if (data.data.sessionStatus === "Over") {
store.dispatch({
type: SET_SECOND_AGENT,
payLoad: { status: "Disconnected", isSecondAgent: false },
});
} else if (
data.data.sessionStatus === "Alive" &&
data.data.agentNameChat
) {
store.dispatch({
type: SET_SECOND_AGENT,
payLoad: {
isSecondAgent: true,
status: "Connected",
anotherAgent: data.data.messageText,
isSecondAgent: true,
},
});
} else if (
data.data.sessionStatus === "Alive" &&
!data.data.messageText.includes("Leaving ChatRoom..") &&
!data.data.messageText.includes("Join Chat Session")
) {
chatStore(data);
}
}
});
});
}
I am not able to figured it out what went wrong, however I am trying to load when props are there but not able to do the same.
PROBLEM
It seems like props are not loaded while execution of `useEffect
Solution might be require some kind of delay to useEffect, so once props properly loaded form localstorage

problems in request in unit test the status is undefined

I am trying to do a unit test to an action in my react application but apparently everything works fine, I get a message that I am not understanding when making the request and the status is undefined, I don't have any specific variable with the status name so I assume it must be a problem when making the promise. How can I solve this problem?
error : undefined | TypeError: Cannot read property 'status' of
undefined
at request (C:\Users\amils\OneDrive\Documentos\Bootcamp - Training\Project\tracking-tool-webapp\src\api\utilities\fetch.js:45:26)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at Object.getAll (C:\Users\amils\OneDrive\Documentos\Bootcamp -
Training\Project\tracking-tool-webapp\src\api\utilities\provider.js:18:9)
console log result:
console.log
[
{
title: 'Candidates',
errorMessages: [],
candidates: [],
reports: null,
loading: false,
programsInProgress: [],
programVersions: [],
statusType: []
},
{ onLoadCandidates: [Function: onLoadCandidates] }
]
The code:
it('Should get all candidates', async () => {
const mockResponse = {
candidates: [
{
id: '4fffc534-1d83-14d5-b264-1e17f2abd322',
name: 'Homer Simpson',
status: 'InProgress',
},
{
id: '4fffc535-1d83-14d5-b264-1e17f2abd322',
name: 'Junior Santos',
status: 'InProgress',
},
],
};
global.fetch = jest.fn(() => {
Promise.resolve({
status: 200,
json: () => Promise.resolve(mockResponse),
});
});
const result = await customRenderHook();
const actions = result.current[1];
console.log(result);
await act(async () => {
actions.onLoadCandidates();
});
const state = result.current[0];
expect(state.candidates).toEqual(mockResponse);
});
code customRenderHook:
const customRenderHook = () => {
const wrapper = ({ children }) => <CandidatesDataProvider>{children}</CandidatesDataProvider>;
const { result } = renderHook(() => useCandidatesContext(), { wrapper });
return result;
};
I find the problem, currently, I cant execure my promise without a tokes 'Bearer', now the problem here is how can I create a mock of token:
function onLoadCandidates(dispatch) {
dispatch({ type: CandidatesActionTypes.loading, payload: true });
const token = localStorage.getItem('token');
apiCandidate
.getAll(token)
.then((response) => {
dispatch({ type: CandidatesActionTypes.loading, payload: response.data });
})
.catch((err) => {
dispatch({ type: CandidatesActionTypes.Error, payload: err.message });
LoggerService.error(err);
})
.finally(() => {
dispatch({ type: CandidatesActionTypes.loading, payload: false });
});
}
You could mock localStorage.getItem to return a token in the format required by apiCandidate.getAll(token):
localStorage.getItem = jest.fn().mockReturnValue('your-token');

useState does not support a second callBack, what could be the easy fix?

This is my useEffect
useEffect(() => {
let pageId =
props.initialState.content[props.location.pathname.replace(/\/+?$/, "/")]
.Id;
if (props.initialState.currentContent.Url !== props.location.
setCurrentContent({ currentContent: { Name: "", Content: "" } }, () => {
fetch(`/umbraco/surface/rendercontent/byid/${pageId}`, {
credentials: "same-origin"
})
.then(response => {
if (response.ok) {
return response.json();
}
return Promise.reject(response);
})
.then(result => {
setCurrentContent({
currentContent: { Name: result.Name, Content: result.Content }
});
});
});
}
}, []);
I have tried things like useCallback/useMemo but yet no luck, I'm sure this is a simple fix but I must be missing the bigger picture, thanks in advance.
What you can do is write an effect that checks if the currentContent state is changed and empty and takes the necessary action. You would however need to ignore the initial render. Also unline setState in class components you don't pass on the state value as object instead just pass the updated state
const ContentPage = props => {
const [currentContent, setCurrentContent] = useState({
Name: props.initialState.currentContent.Name,
Content: props.initialState.currentContent.Content
});
const initialRender = useRef(true);
useEffect(() => {
let pageId =
props.initialState.content[props.location.pathname.replace(/\/+?$/,
"/")]
.Id;
if (
initialRender.current &&
currentContent.Name == "" &&
currentContent.Content == ""
) {
initialRender.current = false;
fetch(`/umbraco/surface/rendercontent/byid/${pageId}`, {
credentials: "same-origin"
})
.then(response => {
if (response.ok) {
return response.json();
}
return Promise.reject(response);
})
.then(result => {
setCurrentContent({ Name: result.Name, Content: result.Content });
});
}
}, [currentContent]);
useEffect(() => {
if (props.initialState.currentContent.Url !== props.location) {
setCurrentContent({ Name: "", Content: "" });
}
}, []);
...
};
export default ContentPage;

Resources