unable to read from new table in Amplify Studio - reactjs

I am new to React so forgive my basic questions...
I inherited a piece of code that connects to an amplify studio set of tables and that works fine. Now i added a new table via schema.graphql, schema.js, index.js and index.d.ts (is that the right way?).
i duplicated the code which is used to read from another table and am pretty sure that its correct, however when i try to get the data into a pull down menu, i get an error which is unable to retrieve the data.
this is the retrieve code:
import { DataStore } from '#aws-amplify/datastore';
import { InverterTechnicalData as InverterTechnicalDataAmplify } from 'models/index';
import { useQuery, UseQueryResult } from 'react-query';
import { showToaster } from 'slices/layout/toastLayoutSlice';
import { useDispatch } from 'src/store/hooks';
import { ToastActions } from 'types/toasterTypes';
const InverterTechnicalDataCacheKey = 'InverterTechnicalDataCacheKey';
export const useGetInverterTechnicalData = (): UseQueryResult<InverterTechnicalDataAmplify[], string | Error> => {
const dispatch = useDispatch();
return useQuery([InverterTechnicalDataCacheKey], async () => {
try {
const result = await DataStore.query(InverterTechnicalDataAmplify);
return result;
} catch (error) {
dispatch(
showToaster({
message: 'Unable to retrieve data, try again',
key: Math.random(),
action: ToastActions.Dismiss,
}),
);
}
});
};
I assume it has to do with the generation of the table in amplify, but i dont know enough about it so if anybody has any pointers that would be great.
thanks,

Related

Redux-Saga axios api call get request with access_token does not work. Why is that?

This is a react project using axios, redux, and redux-sagas.
I am getting the following exception when trying to fetch all records from a table that are guarded. I am using JWT on my laravel backend. Login token is properly set inside local storage, I am guessing, it does not get passed properly.
TypeError: Cannot read properties of null (reading 'authService')
at getAll (PostService.js:11:1)
at runCallEffect (redux-saga-core.esm.js:524:1)
at runEffect (redux-saga-core.esm.js:1204:1)
at digestEffect (redux-saga-core.esm.js:1271:1)
at next (redux-saga-core.esm.js:1161:1)
at proc (redux-saga-core.esm.js:1108:1)
at redux-saga-core.esm.js:585:1
at immediately (redux-saga-core.esm.js:56:1)
at runForkEffect (redux-saga-core.esm.js:584:1)
at runEffect (redux-saga-core.esm.js:1204:1)
This is my page where I want to fetch every record from a table:
import { useEffect } from "react";
import { getAllPostsAction } from "../../store/posts/slice";
import { useSelector, useDispatch } from "react-redux";
import { makeSelectPosts } from "../../store/posts/selector";
export const PostsPage = () => {
const posts = useSelector(makeSelectPosts);
const dispatch = useDispatch();
useEffect(() => {
dispatch(getAllPostsAction());
}, [dispatch]);
console.log(posts);
return <h1>PostsPage</h1>;
};
Saga:
import { call, put, all, fork, takeEvery } from "redux-saga/effects";
import { postService } from "../../services/PostService";
import { setAllPostsAction } from "./slice";
import { setSinglePostAction } from "./slice";
function* getPosts() {
try {
const response = yield call(postService.getAll);
yield put(setAllPostsAction(response.data));
} catch (err) {
console.error(err);
}
}
function* getPostsSagaWatcher() {
yield takeEvery("posts/getAllPostsAction", getPosts);
}
...
// I forked every watcher from a file down bellow in a file
This is how I fetch everything with axios:
import { authService } from "./AuthService";
import axios from "axios";
class PostService {
constructor() {
this.authService = authService;
}
async getAll() {
return await axios.get("http://127.0.0.1:8000/api/posts", {
headers: this.authService.getHeaders(),
});
}
...
getHeaders() looks like this:
getHeaders() {
return {
Authorization: `Bearer ${window.localStorage.getItem("loginToken")}`,
};
}
I've tried to fetch every record in a table and setting it to component state (useState hook) on component mount which worked like a charm. So the issue is most likely the way I dispatch sagas.
yield call(postService.getAll);
Since you havn't specified what the value of this should be, postService.getAll gets called using undefined for this. So when the function tries to access this.authService, it throws an error.
call has several alternate ways you can use it to specify the value of this. All of the following will work:
yield call([postService, postService.getAll])
// or
yield call([postService, 'getAll'])
// or
yield call({ context: postService, fn: postService.getAll })
See also: https://redux-saga.js.org/docs/api/#callfn-args

React Native Unable to fetch multiple documents data from Firebase firestore

App.js File this is App.js file, Please check the below code and correct me I don't have any idea how to solve this issue. Thank you in advance.
.doc("2E3kDAa0QzqoQuoBK1T9", "vROxKUSgcNWwlt7cDEKV") on this line I get the issue.
import React, { useState, useEffect } from "react";
import { View, Text } from 'react-native';
import firestore from '#react-native-firebase/firestore';
function App() {
const [myData, setMyData] = useState(null);
useEffect(() => {
getDatabase();
}, []);
const getDatabase = async () => {
try {
const data = await firestore()
.collection('myCollection')
.doc("2E3kDAa0QzqoQuoBK1T9", "vROxKUSgcNWwlt7cDEKV")
.get();
setMyData(data._data)
} catch (err) {
console.log(err);
}
};
return (
<View>
<Text>First:-{myData ? myData.name : 'Loading...'}</Text>
<Text>Second:-{myData ? myData.secondData : 'Loading...'}</Text>
</View>
);
}
export default App;
This doesn't work:
.doc("2E3kDAa0QzqoQuoBK1T9", "vROxKUSgcNWwlt7cDEKV")
If you check the API docs for CollectionReference.doc it expects:
doc(documentPath?: undefined | string): DocumentReference<>;
So you can pass in a single document ID or path, not multiple.
If you want to return multiple documents by their ID, you can use th in query operator on the FieldPath.documentId() to do so for up to 10 values. If you have more values, you'll need to retrieve them in batches of up to 10 and merge them in your application code.

Type missinng in React Typescript Axios Response

I'm trying to write an API service in a React app, using Axios and Typescript.
Below is my code:
Interface for Helper API Class
import { AxiosResponse } from 'axios'
export interface PlatformResponse {
platform: {
id: string
image: string
name: string
}[]
}
export interface Platform {
getPlatformResponse: () => Promise<AxiosResponse<PlatformResponse>>
}
My Platform Class
import { AxiosResponse } from 'axios'
class Platforms implements Platform {
async getPlatformResponse(): Promise<AxiosResponse<PlatformResponse>> {
const path = 'http://localhost:8080/api/platforms'
const method = 'get'
const result = await httpRequest({ path, method })
return result
}
}
const PlatformsAPI = new Platforms()
export default PlatformsAPI
I'm using the react-query library for fetching data, and the code below
const useGetPlatforms = () => {
console.log('sdfd')
return useQuery('platform', PlatformsAPI.getPlatformResponse)
}
export default useGetPlatforms
And the Code for my component as below
import { useGetVehicleBrands } from '../../../hooks/RQHooks'
function VehicleBrands() {
const { data, isLoading } = useGetVehicleBrands()
console.log('data', data.platform)
return (
<>
<div>
{data.platform.map((item) =><h1>{item}</h1>)}
</div>
</>
)
}
export default PlatformComponent
The error I'm getting in my above code is that I couldn't access the platform property from the data. Typescript throwing error saying that the platform property not found. Only the property from the AxiosResponse is shown. How to accomplish that the typescript know that data is the type of PlatformResponse. Kindly help to accomplish it.
you get a data property from react-query that contains the unwrapped promise from whatever your queryFn returns.
an AxiosResponse contains what you're seeing in your screenshot - data, headers, statusText etc.
Your actual data is inside the data property, so you'd need:
data.data.platform
The first data being the one from react-query, the second one being the one from axios.
If you don't need to store request meta-data like headers in your queryCache, it is best to unwrap it inside the queryFn:
useQuery(
'platform',
() => PlatformsAPI.getPlatformResponse().then(response => response.data))
)
you can also do that inside your PlatformsAPI if you want.

Using graphql-tools, apollo-link-schema, and react-hooks always returning undefined when mocking

I'm new to using GraphQL in React and have been moving a project from a REST API to a new GraphQL one. As part of this, I wanted to setup mock data to work on the application independent of the GQL API being completed. I've spent a bunch of time trying to follow the Apollo and GraphQL Tools docs but no matter what, I can't seem to get the mock resolvers to work properly. For context, I am using this in a NextJS/React app, and here's a minimum example of what I'm trying to do:
Setup App.js
import React from 'react';
import ApolloClient from 'apollo-client';
import { ApolloProvider } from 'react-apollo';
import { SchemaLink } from 'apollo-link-schema';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { makeExecutableSchema } from '#graphql-tools/schema';
import { addMocksToSchema } from '#graphql-tools/mock';
export default function App() {
const schema = makeExecutableSchema({typeDefs:`
type Query {
getPerson: Person!
}
type Person {
name: String!
}
`});
const mocks = {
Query: () => ({
getPerson: () => ({
name: () => "Name"
})
})
}
addMocksToSchema({ mocks, schema });
const link = new SchemaLink({ schema });
const client = new ApolloClient({
link,
cache: new InMemoryCache(),
connectToDevTools: true
});
return (
<ApolloProvider client={client}>
<Person />
</ApolloProvider>
)
}
Person.js
import React from 'react';
import { useQuery } from '#apollo/react-hooks';
import gql from 'graphql-tag';
export default function Person() {
const { loading, error, data } = useQuery(gql`
query PersonQuery {
getPerson {
name
}
}
`, {
errorPolicy: 'all'
});
console.log(data);
if (loading) return "Loading...";
if (error) console.log(error);
return (
<h1>{data.getPerson.name}<h1>
)
}
Looking at the console.log(error) result yields the error Cannot return null for non-nullable field Query.getPerson and making it a nullable field just returns { getPerson: null } of course. I've tried returning the resolver results as objects vs functions. Logging within the resolvers shows the Query part is being executed but nothing nested within that.
Am I setting something up incorrectly? I also tried not passing in custom mocks as suggested should be possible based on the graphql-tools docs, but to no avail. I also saw this issue from the apollo hooks GitHub that said the newest version of hooks broke the usage of addMocksToSchema, so I tried using the suggested 3.1.3 version but again no luck. Any help would be greatly appreciated!
You need to provide the mock to the client, not the plain schema.
const schemaWithMocks = addMocksToSchema({
schema,
mocks: {},
preserveResolvers: false,
});
const client = new ApolloClient({
// link: new SchemaLink({ schema }); < -- REPLACE THIS
link: (new SchemaLink({ schema: schemaWithMocks }) as unknown) as ApolloLink, // https://github.com/apollographql/apollo-link/issues/1258
cache: new InMemoryCache(),
connectToDevTools: true,
});
Now console.log(data) prints
{"getPerson": {"__typename": "Person", "name": "Name"}} 🎉

Why does one of my sagas fire, but not the other (set up the same way...I think)

I am new to redux-saga and have been searching for a solution to my issue for a couple days now so I figured I'd ask here since I've come up empty.
I am making edits to the microsoft botframework-webchat library for a project I am working on. Instead of using direct line, I am trying to make the botframework-webchat library compatible with signalR. Specifically, I am making changes to the core and component packages. My goal is to mimic the direct line redux flow so signalR works in context of the botframework-webchat library.
The basic flow starts at my root project, a simple React web app.
rootproject/WebChat.js
import ReactWebChat from 'botframework-webchat';
render() {
...
<ReactWebChat
className={`${className || ''} web-chat`}
signalR={this.signalRConnection}
//directLine={this.createDirectLine(token)}
store={store}
styleSet={styleSet}
/>
}
For my purposes, I send either a signalR connection or directLine connection object. Then within 'botframework-webchat' in the component package, ReactWebChat goes through a series of hand offs and eventually gets here:
rootproject/botframework-webchat/botframework-webchat-component/Composer.js
useEffect(() => {
if (signalR) {
console.log("Dispatch signalR");
dispatch(
connectSignalRAction({
signalR
})
);
}
else {
dispatch(
createConnectAction({
directLine,
userID,
username
})
);
}
return () => {
dispatch(disconnect());
};
}, [dispatch, signalR, userID, username]);
Both when sending a directline or signalr connection object, this correctly dispatches the corresponding action. Then comes intercepting this action. This is done in the botframework-webchat core package. I'll showcase this flow working through directline first.
rootproject/botframework-webchat/botframework-webchat-component/botframework-webchat-core/connect.js
const CONNECT = 'DIRECT_LINE/CONNECT';
const CONNECT_FULFILLED = `${CONNECT}_FULFILLED`;
const CONNECT_FULFILLING = `${CONNECT}_FULFILLING`;
const CONNECT_PENDING = `${CONNECT}_PENDING`;
const CONNECT_REJECTED = `${CONNECT}_REJECTED`;
const CONNECT_STILL_PENDING = `${CONNECT}_STILL_PENDING`;
export default function connect({ directLine, userID, username }) {
return {
type: CONNECT,
payload: {
directLine,
userID,
username
}
};
}
export { CONNECT, CONNECT_FULFILLED, CONNECT_FULFILLING, CONNECT_PENDING, CONNECT_REJECTED, CONNECT_STILL_PENDING };
This fires CONNECT and is picked up here:
rootproject/botframework-webchat/botframework-webchat-component/botframework-webchat-core/connectionStatusToNotificationSaga.js
/* eslint no-magic-numbers: ["error", { "ignore": [0, 1, 2, 3, 4] }] */
import { call, put, takeLatest } from 'redux-saga/effects';
import { CONNECT } from '../actions/connect';
import createPromiseQueue from '../createPromiseQueue';
import setNotification from '../actions/setNotification';
const CONNECTIVITY_STATUS_NOTIFICATION_ID = 'connectivitystatus';
function subscribeToPromiseQueue(observable) {
const { push, shift } = createPromiseQueue();
const subscription = observable.subscribe({ next: push });
return {
shift,
unsubscribe() {
subscription.unsubscribe();
}
};
}
function* connectionStatusToNotification({ payload: { directLine } }) {
const { shift, unsubscribe } = subscribeToPromiseQueue(directLine.connectionStatus$);
console.log("subscribe connection status: " + directLine.connectionStatus$);
try {
let reconnecting;
for (;;) {
const value = yield call(shift);
switch (value) {
case 0:
case 1:
yield put(
setNotification({
id: CONNECTIVITY_STATUS_NOTIFICATION_ID,
level: 'info',
message: reconnecting ? 'reconnecting' : 'connecting'
})
);
break;
case 2:
reconnecting = 1;
yield put(
setNotification({
id: CONNECTIVITY_STATUS_NOTIFICATION_ID,
level: 'success',
message: 'connected'
})
);
break;
case 3:
case 4:
reconnecting = 1;
yield put(
setNotification({
id: CONNECTIVITY_STATUS_NOTIFICATION_ID,
level: 'error',
message: 'failedtoconnect'
})
);
break;
default:
break;
}
}
} finally {
unsubscribe();
}
}
export default function*() {
yield takeLatest(CONNECT, connectionStatusToNotification);
}
I was able to set breakpoints in the project and step through to the above code so this is where it goes first. For reference, here is the store and sagas.
rootproject/botframework-webchat/botframework-webchat-component/botframework-webchat-core/createStore.ts
// This is for the racing between sagaMiddleware and store
/* eslint no-use-before-define: "off" */
import { applyMiddleware, createStore } from 'redux';
import createSagaMiddleware from 'redux-saga';
import reducer from './reducer';
import sagaError from './actions/sagaError';
import sagas from './sagas';
export default function createWebChatStore(initialState, ...middlewares):any {
const sagaMiddleware = createSagaMiddleware({
onError: (...args) => {
const [err] = args;
console.error(err);
store.dispatch(sagaError());
}
});
const store = createStore(
reducer,
initialState || {},
applyMiddleware(...middlewares, sagaMiddleware)
);
sagaMiddleware.run(sagas);
return store;
}
rootproject/botframework-webchat/botframework-webchat-component/botframework-webchat-core/sagas.js
import { fork } from 'redux-saga/effects';
import clearSuggestedActionsOnPostActivitySaga from './sagas/clearSuggestedActionsOnPostActivitySaga';
import connectionStatusToNotificationSaga from './sagas/connectionStatusToNotificationSaga';
import connectionStatusUpdateSaga from './sagas/connectionStatusUpdateSaga';
import connectSaga from './sagas/connectSaga';
import connectSignalRSaga from './sagas/connectSignalRSaga';
import detectSlowConnectionSaga from './sagas/detectSlowConnectionSaga';
import emitTypingIndicatorToPostActivitySaga from './sagas/emitTypingIndicatorToPostActivitySaga';
import incomingActivitySaga from './sagas/incomingActivitySaga';
import markAllAsSpokenOnStopSpeakActivitySaga from './sagas/markAllAsSpokenOnStopSpeakActivitySaga';
import postActivitySaga from './sagas/postActivitySaga';
import sendEventToPostActivitySaga from './sagas/sendEventToPostActivitySaga';
import sendFilesToPostActivitySaga from './sagas/sendFilesToPostActivitySaga';
import sendMessageBackToPostActivitySaga from './sagas/sendMessageBackToPostActivitySaga';
import sendMessageToPostActivitySaga from './sagas/sendMessageToPostActivitySaga';
import sendPostBackToPostActivitySaga from './sagas/sendPostBackToPostActivitySaga';
import sendTypingIndicatorOnSetSendBoxSaga from './sagas/sendTypingIndicatorOnSetSendBoxSaga';
import speakActivityAndStartDictateOnIncomingActivityFromOthersSaga from './sagas/speakActivityAndStartDictateOnIncomingActivityFromOthersSaga';
import startDictateOnSpeakCompleteSaga from './sagas/startDictateOnSpeakCompleteSaga';
import startSpeakActivityOnPostActivitySaga from './sagas/startSpeakActivityOnPostActivitySaga';
import stopDictateOnCardActionSaga from './sagas/stopDictateOnCardActionSaga';
import stopSpeakingActivityOnInputSaga from './sagas/stopSpeakingActivityOnInputSaga';
import submitSendBoxSaga from './sagas/submitSendBoxSaga';
import submitSendBoxSagaSignalR from './sagas/submitSendBoxSagaSignalR';
import postActivitySagaSignalR from './sagas/postActivitySagaSignalR';
import sendMessageBackToPostActivitySagaSignalR from './sagas/sendMessageToPostActivitySagaSignalR';
import testSaga from './sagas/TestSaga';
export default function* sagas() {
// TODO: [P2] Since fork() silently catches all exceptions, we need to find a way to console.error them out.
yield fork(testSaga);
yield fork(clearSuggestedActionsOnPostActivitySaga);
yield fork(connectionStatusToNotificationSaga);
yield fork(connectionStatusUpdateSaga);
yield fork(connectSaga);
yield fork(connectSignalRSaga);
yield fork(detectSlowConnectionSaga);
yield fork(emitTypingIndicatorToPostActivitySaga);
yield fork(incomingActivitySaga);
yield fork(markAllAsSpokenOnStopSpeakActivitySaga);
yield fork(postActivitySaga);
yield fork(sendEventToPostActivitySaga);
yield fork(sendFilesToPostActivitySaga);
yield fork(sendMessageBackToPostActivitySaga);
yield fork(sendMessageToPostActivitySaga);
yield fork(sendPostBackToPostActivitySaga);
yield fork(sendTypingIndicatorOnSetSendBoxSaga);
yield fork(speakActivityAndStartDictateOnIncomingActivityFromOthersSaga);
yield fork(startDictateOnSpeakCompleteSaga);
yield fork(startSpeakActivityOnPostActivitySaga);
yield fork(stopDictateOnCardActionSaga);
yield fork(stopSpeakingActivityOnInputSaga);
yield fork(submitSendBoxSaga);
yield fork(submitSendBoxSagaSignalR);
yield fork(postActivitySagaSignalR);
yield fork(sendMessageBackToPostActivitySagaSignalR);
}
The flow works when using directline, but then when I send over a signalR connection object which dispatches
dispatch(
connectSignalRAction({
signalR
})
the action is dispatched but not picked up by the saga. Specifically, here is the action and saga:
rootproject/botframework-webchat/botframework-webchat-component/botframework-webchat-core/connectSignalR.js
const CONNECT_SIGNALR = 'SIGNALR/CONNECT';
const CONNECT_SIGNALR_FULFILLED = `${CONNECT_SIGNALR}_FULFILLED`;
const CONNECT_SIGNALR_FULFILLING = `${CONNECT_SIGNALR}_FULFILLING`;
const CONNECT_SIGNALR_PENDING = `${CONNECT_SIGNALR}_PENDING`;
const CONNECT_SIGNALR_REJECTED = `${CONNECT_SIGNALR}_REJECTED`;
const CONNECT_SIGNALR_STILL_PENDING = `${CONNECT_SIGNALR}_STILL_PENDING`;
export default function connectSignalR({ signalR }) {
return {
type: CONNECT_SIGNALR,
payload: {
signalR
}
};
}
export { CONNECT_SIGNALR, CONNECT_SIGNALR_FULFILLED, CONNECT_SIGNALR_FULFILLING, CONNECT_SIGNALR_PENDING, CONNECT_SIGNALR_REJECTED, CONNECT_SIGNALR_STILL_PENDING };
rootproject/botframework-webchat/botframework-webchat-component/botframework-webchat-core/connectSignalRSaga.js
/* eslint no-magic-numbers: ["error", { "ignore": [0, 10] }] */
import { call, cancel, cancelled, fork, put, race, take, takeEvery, takeLatest } from 'redux-saga/effects';
import { CONNECT_SIGNALR, CONNECT_SIGNALR_PENDING } from '../actions/connectSignalR';
function* workerSaga() {
console.log("Hello from worker saga");
yield put({ type: CONNECT_SIGNALR_PENDING });
}
export default function*() {
// for (;;) {
// const {
// payload: { signalR }
// } = yield takeEvery(CONNECT_SIGNALR);
// const {
// payload: { signalR }
// } = yield takeEvery(CONNECT_SIGNALR, workerSaga);
yield takeLatest(CONNECT_SIGNALR, workerSaga);
}
I have tried a few different approaches in 'connectSignalRSaga.js' but cannot seem to get workerSaga() to run which makes me believe the default function never yields. I have tried using a breakpoints and debugger statement and it does not stop in that function (but breakpoints and debugger statements have not been working for the most part anyway for some reason).
So my questions are:
Do you have any idea why when using directline, the 'CONNECT' action is picked up, but when using signalr the 'CONNECT_SIGNALR' action is not picked up?
Slightly off topic, but I am having trouble setting up Redux DevTools for this project (it is an isomorphic React app). I've followed instructions from https://github.com/zalmoxisus/redux-devtools-extension#usage but the extension keeps telling me "No store found". I've tried wrapping the store with 'redux-devtools-extension' npm package as well as setting compose manually. I presume getting this set up would be helpful in figuring out #1.
Web Chat is built using BotFramework-DirectLineJS which is the actual source of the ConnectionStatus displayed in Web Chat. You can reference the different statuses here and how that enum is utilized throughout directLine.ts.
What is more, the ConnectionStatus is used extensively through Web Chat in connectSaga.js, connectionStatusUpdateSaga.js, and a variety of other files.
My strong suspicion is your SignalR connection doesn't actually issue a connection status that would, otherwise, be picked up in Web Chat (if issued, at all). In addition, based on your SignalR connection status naming convention, many parts of Web Chat probably aren't picking it up unless you have updated those files to also read from the SignalR connection object and recognize the updated connection statuses.
Assuming this is the problem, it may be an easier lift to maintain the connection status naming convention already used and modify what SignalR issues as status names.

Resources