Store Api data to a class react native - react-native

I am getting data from API.I need to push that data to a class.Below is my basic class structure:
Attendance.js
class Attendance{
constructor(SessionDate,SubjectName,Att){
this.SessionDate = SessionDate;
this.SubjectName = SessionDate+'-'+SubjectName;
this.Att = Att;
}
}
export default Attendance ;
Here is my Action class:
attendance.js
import Attendance from "../../models/Attendance";
import {AsyncStorage} from 'react-native';
export const SET_STUDENT_ATTENDANCE = 'SET_SET_STUDENT_ATTENDANCE';
export const fetchStudentAttendance = (newDate) => {
return async (dispatch,getState) =>{
const userData = await AsyncStorage.getItem('userData');
const transformedData = JSON.parse(userData);
const { token } = transformedData;
const Date = newDate;
try{const response = await fetch(
`http://........./api/stud/Get_Stud_Attendance_Details?Date=${Date}`,
{
headers: {
'Content-Type': 'application/json',
'Authorization':token
},
}
);
const resData = await response.json();
console.log(resData);
const loadedStudentAtt = [];
loadedStudentAtt.push(new Attendance(
resData["WeeklyAttendanceList"].SessionDate,
resData["WeeklyAttendanceList"].SubjectAbbr,
resData["WeeklyAttendanceList"].Att,
));
console.log(loadedStudentAtt);
dispatch({type: SET_STUDENT_ATTENDANCE,studentattendance:loadedStudentAtt});
}
catch(err){
console.log(err);
throw err;
};
};
};
Below is the sample API data:
Object {
"Error": null,
"Response": null,
"StartDate": "2020-02-04T00:00:00",
"StudentAttendancePercentList": Array [],
"Successful": true,
"WeeklyAttendanceList": Array [
Object {
"Att": "1",
"SessionDate": "28 Jan 2020",
"SessionDayName": "",
"SessionNo": 1,
"SessionTiming": "09:15 - 10:30",
"SubjectAbbr": "Subject1",
},
Object {
"Att": "0",
"SessionDate": "28 Jan 2020",
"SessionDayName": "",
"SessionNo": 1,
"SessionTiming": "09:15 - 10:30",
"SubjectAbbr": "Subject2",
},
],
}
The array that I am getting in console.log() is as below:
Array [
Attendance {
"Att": undefined,
"SessionDate": undefined,
"SubjectName": "undefined-undefined",
},
]
Can you please tell am I pushing the data correctly to the class?
Thanks in Advance.

WeeklyAttendanceList is Array of Objects. So you have to iterate over it and push that data into loadedStudentAtt.
const resData = await response.json();
console.log(resData);
const WeeklyAttendanceList = resData.WeeklyAttendanceList;
const loadedStudentAtt = [];
WeeklyAttendanceList.forEach(item => {
loadedStudentAtt.push(new Attendance(
item.SessionDate,
item.SubjectAbbr,
item.Att,
))
})
console.log(loadedStudentAtt);

Related

change toolkit redux state inside of fetch

I just want to update state outside of component after server give me failed response.
the project is react native .
After a lot of online search on website like this , I learn that i need to import my store and use dispatch method. but when i import storage and dispatch it, it give me this error: Property 'crypto' doesn't exist .
this is my feachService.js code:
import { URL } from 'react-native-url-polyfill';
import { store } from '../store/index'
import { errorSliceActions } from '../store/slices/global/errorSlice'
export default (url, isGet) => {
let headers = {
Referer: new URL(url).origin,
}
headers['X-Requested-With'] = 'XMLHttpRequest'
return fetch(
url,
{
method: (isGet ? 'GET' : 'POST'),
headers: headers
})
.then(function (res) {
return res.json();
})
.then(function (res)
{
if(res && res.isSuccess == false && res.message) {
store.dispatch(errorSliceActions.add(res.message));
}
return {json: function() { return res; }};
})
.catch(function (error) { console.log(error.message); })
};
this is my storage js file:
import { configureStore } from '#reduxjs/toolkit';
import errorSliceReducer from './slices/global/errorSlice';
export const store = configureStore({
reducer: {
errorSlice: errorSliceReducer
}
});
this is my error slice.js file:
import { createSlice } from "#reduxjs/toolkit"
function uuidv4() {
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
);
}
const errorSlice = createSlice({
name: "errorSlice",
initialState: {
errors: [
]
},
reducers:
{
add: (state, action) => {
const newItem = {
id: uuidv4(),
message: action.payload
};
return [...state, newItem];
},
remove: (state, action) => {
return { errors: state.errors.filter(function(item) { return item.id != action.payload; }) }
}
}
})
export const errorSliceActions = errorSlice.actions;
export default errorSlice.reducer
and this is my code for executing fetch request
async function loadInfo (inputSearch, inputPage) {
if(config.dataurl) {
console.log(inputSearch);
setIsLoading(true);
const hasQuestionMark = config.dataurl.indexOf('?') > 0;
let targetUrl = '/test/test' + config.dataurl + (!hasQuestionMark ? '?' : '&');
targetUrl += 'page=' + inputPage;
targetUrl += '&search=' + inputSearch;
console.log(targetUrl);
const response = await feachService(appJSon.baseUrl + targetUrl , true);
const responseData = await response.json();
setIsLoading(false);
if(responseData.pagination)
setPagination(responseData.pagination);
if(!responseData.results)
setItems([]);
else
setItems(responseData.results);
}
}
useEffect(() => {
loadInfo('', 1).catch(function (error) { console.log(error.message); });
}, [])
what am i doing wrong ?

Vue JWT token is only attached after refresh

Token is null right after login, It stores only if I refresh the page. It should store just after login without need to reload.
src/stores/index.ts:
const initialUser = JSON.parse(sessionStorage.getItem('Project:token') || '{}');
const useProject = defineStore('project-store', {
state: () => ({
token: initialUser as string | null,
status: initialUser ? { loggedIn: false } : { loggedIn: true },
}),
actions: {
async login(user: User) {
const token = await grantAuth(user);
this.loginSuccess = token;
},
loginSuccess(token: string) {
this.token = token;
this.status.loggedIn = !!token;
},
src/services/entryPoint.js:
import store from '../stores/index';
export default async function entryPoint() {
const getStore = async () => {
if (!store) {
store = await import('../stores/index');
} else {
if (store) {
const { token } = store;
if (token) {
return token;
}
}
}
};
}
src/services/api.js:
import axios from 'axios';
import entryPoint from './entryPoint';
const api = axios.create({ baseURL: import.meta.env.VITE_APP_API_URL });
const entry = entryPoint();
if (entry) {
api.defaults.headers.Authorization = `Bearer ${entry}`;
}
export default api;
src/services/auth.js:
import api from './api';
const requestToken = encodedData => {
return api.post('/projects/login', null, {
headers: {
Authorization: `Basic ${encodedData}`,
},
});
}
const registerToken = data => {
if (data && data.token) {
sessionStorage.setItem('Project:token', JSON.stringify(data.token));
}
};
export const grantAuth = async user => {
const flatData = `${user.username.toUpperCase()}:${user.password}`;
const encodedData = btoa(flatData);
const response = await requestToken(encodedData);
registerToken(response.data);
return response.data ? response.data.token : null;
};
A solution would be to give the command window.location.reload(), however It is not viable for a SPA, It is preferable that the token to be available right after login

vue unit test get data of component

I am testing if a function works,
The function doesn't return anything but infact changes the data in the component
This is the test I am trying to write
describe('ModalAddCollectionCSV', () => {
it('Test load csv function', () => {
const localVue = createLocalVue()
const wrapper = shallowMount(AddCSV, {
localVue,
propsData: {
visible: true,
},
})
var fileDict = [{ file: new Blob([wrongDateFormat]) }]
wrapper.vm.loadcsv(fileDict)
expect(wrapper.html()).toContain('error')
})
})
I am expecting some changes to the data of the component
data() {
return {
collections: [],
inlineVisibility: false,
inlineTitle: '',
inlineSubtitle: '',
inlineKind: 'info',
loading: false,
}
},
This is the function I am testing in unit test, as you see it doesn't return anything just changes the data at the end of it
async loadcsv(element) {
const reader = new FileReader()
const file = element[0].file
this.toggleLoading()
reader.onload = async (e) => {
try {
//Normalising headers
const results = e.target.result
let resultSplit = results.split('\n')
const header = resultSplit[0]
.toLowerCase()
.replace(/[^a-zA-Z,]/g, '')
.trim()
resultSplit[0] = header
let table = resultSplit.join('\n')
const rows = await d3.csvParse(table)
await Promise.all(
rows.map(async (row) => {
if (!(this.getSerial(row).length == 9)) {
if (!this.getName(row)) {
throw `Please enter Person of interest`
}
if (!row.country) {
throw `Country for ${this.getName(
row,
)} is empty`
}
}
)
this.inlineVisibility = false
this.$emit('rowEmit', {
collections: this.row,
})
this.toggleLoading()
this.collections = []
this.$refs.modal.hide()
} catch (err) {
this.collections = []
this.inlineNotification('error', 'Unable to process CSV', `${err}.`)
}
}
reader.readAsText(file)
},
Is there a way to check emit action or error action?
I tried wrapper.text()
Wrapper.html()
but no difference

Storing data in global state

I want to store usere_id in global value state so i create global.js
module.exports = {
users_id: "",
};
and import it in post.js , so how can store data in Global.users_id and use it anywhere i want ...
i tried this
Login = async () => {
const response = await fetch("http://192.168.6.107:8080/login", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
username: this.state.username,
password: this.state.password,
})
});
const data = await response.json();
console.log("data", data);
console.log("data.suc", data.success);
if (data.success) {
AsyncStorage.setItem("user", JSON.stringify(data.user));
console.log("DATAAA>>>>",data)
const global= data.user.users_id
const global2= GLOBAL.users_id.setState({
users_id:global
})
console.log("global",global2)
}
return data.success;
};
I want to get users_id from this data
DATAAA>>>> Object {
"success": true,
"user": Array [
Object {
"password": "ddd",
"username": "ddd",
"users_id": 1,
},
],
}
You can declare a global variable anywhere like this:
global.userID = 3
// and use it Login like this
global.userID // value = 3
however it's not recommended doing this very often. Maybe you should take a look at Redux.
If you want to use it anywhere, create a variable that stores and uses global variables.
global.js
let users_id = "";
...
function set_users_id(data) {
users_id = data;
}
function get_users_id() {
return users_id;
}
Usage
import * as global from "filepath/global.js"
...
let user_id = data.user[0].user_id
global.set_users_id(user_id)
import * as global from "filepath/global.js"
alert(global.user_id) // return 1
alert(global.get_users_id()) // return 1

Why am I getting data undefined when I can see the data?

I have been staring at these action creators:
import * as types from './constants';
import * as endpoints from 'endpoints';
import * as requester from 'services/Requester';
import * as helpers from 'account-settings/helpers/data-helpers';
export function fetchPrefences({Key}) {
return dispatch => {
const url = `${endpoints.v2.INDIVIDUALS}/${Key}/preferences`;
requester.sendGet(url).then(data => {
const payload = helpers.sortPreferences(data);
dispatch({
type: types.SET_USER_PREFERENCES,
payload,
});
});
};
}
export function fetchTopics() {
return dispatch => {
requester.sendGet(endpoints.TOPICS_OF_CONCERN).then(data => {
dispatch({
type: types.SET_USER_TOPICS,
payload: data.Items,
});
});
};
}
export function handleStateChange(payload) {
return {
type: types.SET_NEW_PREFERENCES,
payload,
};
}
export function handleUpdateTopics({topics, involved}, updateBoth = false) {
return dispatch => {
return requester
.sendPut(endpoints.TOPICS_OF_CONCERN, {
Items: topics,
})
.then(data => {
dispatch({
type: types.SET_USER_TOPICS,
payload: data.Items,
});
if (updateBoth) {
dispatch(handleUpdatePreferences({involved}));
}
});
};
}
export function handleUpdateGetInvoved({involved}) {
return (dispatch, getState) => {
const {auth} = getState();
//prettier-ignore
const url = `${endpoints.v2.INDIVIDUALS}/${auth.user.Key}/preferences`;
return requester
.sendPut(url, {
Items: involved,
})
.then(data => {
const payload = helpers.sortPreferences(data);
dispatch({
type: types.SET_USER_PREFERENCES,
payload,
});
});
};
}
And it's clear I am getting data as undefined with this message:
What is not clear is why? When I do a curl, the data is there:
{"items":[{"category":"None","key":"2883040c-88b8-4899-bd47-114a560d085b","displayText":"Energy
Costs","isSelected":false,"order":1},{"category":"None","key":"a745a3d6-0f64-4595-8734-6082d9c914f7","displayText":"Regulations","isSelected":false,"order":7},{"category":"None","key":"51797a61-8016-4817-a46e-72dee3d8239a","displayText":"Minimum
Wage","isSelected":false,"order":5},{"category":"None","key":"381e24d0-2668-4a69-a993-7d5e1ecaec3b","displayText":"Taxes","isSelected":false,"order":8},{"category":"None","key":"dfaf22cb-111a-46f3-bce3-93fbf4a91490","displayText":"Unemployment
Insurance","isSelected":false,"order":9},{"category":"None","key":"c55b5d2a-a0f3-4c35-bf59-b433259b2059","displayText":"Workers
Compensation","isSelected":false,"order":10},{"category":"None","key":"d4b787d4-550b-4866-a5cc-c6a2de61a91a","displayText":"Healthcare","isSelected":false,"order":4},{"category":"None","key":"c2557854-421d-4b2f-810f-caadf938cded","displayText":"Government
Spending","isSelected":false,"order":3},{"category":"None","key":"cf91f638-c5fa-4252-be01-dce504ae369d","displayText":"Private
Property
Rights","isSelected":false,"order":6},{"category":"None","key":"0eae5ccf-2ba5-41bd-9111-efe7acafa512","displayText":"Finding
Qualified Employees","isSelected":false,"order":2}]}%
In Swagger, I check, the data is there:
{
"items": [
{
"category": "None",
"key": "2883040c-88b8-4899-bd47-114a560d085b",
"displayText": "Energy Costs",
"isSelected": false,
"order": 1
},
{
"category": "None",
"key": "a745a3d6-0f64-4595-8734-6082d9c914f7",
"displayText": "Regulations",
"isSelected": false,
"order": 7
},
{
"category": "None",
"key": "51797a61-8016-4817-a46e-72dee3d8239a",
"displayText": "Minimum Wage",
"isSelected": false,
"order": 5
},
{
"category": "None",
"key": "381e24d0-2668-4a69-a993-7d5e1ecaec3b",
"displayText": "Taxes",
"isSelected": false,
"order": 8
},
{
"category": "None",
"key": "dfaf22cb-111a-46f3-bce3-93fbf4a91490",
"displayText": "Unemployment Insurance",
"isSelected": false,
"order": 9
},
{
"category": "None",
"key": "c55b5d2a-a0f3-4c35-bf59-b433259b2059",
"displayText": "Workers Compensation",
"isSelected": false,
"order": 10
},
{
"category": "None",
"key": "d4b787d4-550b-4866-a5cc-c6a2de61a91a",
"displayText": "Healthcare",
"isSelected": false,
"order": 4
},
{
"category": "None",
"key": "c2557854-421d-4b2f-810f-caadf938cded",
"displayText": "Government Spending",
"isSelected": false,
"order": 3
},
{
"category": "None",
"key": "cf91f638-c5fa-4252-be01-dce504ae369d",
"displayText": "Private Property Rights",
"isSelected": false,
"order": 6
},
{
"category": "None",
"key": "0eae5ccf-2ba5-41bd-9111-efe7acafa512",
"displayText": "Finding Qualified Employees",
"isSelected": false,
"order": 2
}
]
}
I noticed that in the code the items property was written as Items, I tried to change it to items to match the data property, that did nothing.
A colleague suggested the issue could be in the requester object, I do have a question about it too:
import axios from 'axios';
import LocalStorage from './LocalStorage';
import env from 'env';
import * as appcenter from 'utils/appcenterLogger';
import * as titlesHelper from 'utils/titleCaser';
let expired = false;
export const instance = axios.create({
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
NFIBAppID: env.NFIBAppID,
},
});
let preHeaders = {};
async function mergeConfig(config) {
try {
const access = await LocalStorage.get('access');
preHeaders = access;
return {...config, headers: {...access}};
} catch (error) {
return {...config};
}
}
export async function sendGet(url, config = {}) {
if (expired) {
return;
}
const now = new Date();
return instance
.get(url, await mergeConfig(config))
.then(response => {
return saveHeaders(response, now, url);
})
.catch(error => {
return catchErros(error, now, url);
});
}
export async function sendPost(url, data, config = {}) {
if (expired) {
return;
}
const now = new Date();
return instance
.post(url, titlesHelper.lowerCaser(data), await mergeConfig(config))
.then(response => {
console.log(response);
return saveHeaders(response, now, url);
})
.catch(error => {
return catchErros(error, now, url);
});
}
export async function sendPut(url, data, config = {}) {
if (expired) {
return;
}
const now = new Date();
return instance
.put(url, titlesHelper.lowerCaser(data), await mergeConfig(config))
.then(response => {
return saveHeaders(response, now, url);
})
.catch(error => {
return catchErros(error, now, url);
});
}
export async function sendPatch(url, data, config = {}) {
if (expired) {
return;
}
const now = new Date();
return instance
.patch(url, data, await mergeConfig(config))
.then(response => {
return saveHeaders(response, now, url);
})
.catch(error => {
return catchErros(error, now, url);
});
}
export async function sendDelete(url, data, config = {}) {
if (expired) {
return;
}
const now = new Date();
return instance
.delete(url, await mergeConfig(config))
.then(response => {
return saveHeaders(response, now, url);
})
.catch(error => {
return catchErros(error, now, url);
});
}
export function saveHeaders({data, headers}, timeSent, url) {
try {
if (headers && headers.authorizationtoken) {
LocalStorage.save('access', {
AuthorizationToken: headers.authorizationtoken,
});
}
const timeReceived = new Date();
LocalStorage.save('lastTimeRequestSent', timeReceived);
appcenter.trackRequestTiming(timeSent, timeReceived, headers, url, false);
return titlesHelper.toTitleCase(data);
} catch (_e) {
return false;
}
}
function catchErros({error, timeSent}, url) {
try {
const timeReceived = new Date();
LocalStorage.save('lastTimeRequestSent', timeReceived);
appcenter.trackRequestTiming(timeSent, timeReceived, error, url, true);
if (error && error.response) {
saveHeaders({
headers: preHeaders,
});
const {data} = error.response;
const message = data.message || data.Message;
if (message.includes('TokenExpired')) {
expired = true;
}
}
return Promise.reject(titlesHelper.toTitleCase(error.response.data));
} catch (_e) {
return error;
}
}
export function resetTokenExpired() {
expired = false;
}
I am seeing Promise syntax being mixed with async/await syntax, could this be causing an issue?
I tried to see if perhaps the issue was with the authorization token, so I console logged it:
let preHeaders = {};
async function mergeConfig(config) {
try {
const access = await LocalStorage.get('access');
console.log(access);
preHeaders = access;
return {...config, headers: {...access}};
} catch (error) {
return {...config};
}
}
but I am successfully getting that back:
{AuthorizationToken: "<bunch-o-numbers>"}
What I know at this point is that without the logic inside of the saveHeaders() function, a registered users' password will return undefined.
To complicate things, this application uses action helpers, which I have never implemented, but I see that Items property in there all over the place, keep in mind that the original warning read Items, but I changed it everywhere to items to make it match the JSON item property in the hope that would be the fix.
However, I have now come across these action helper files with the following code, action-helpers.js:
import * as endpoints from 'endpoints';
import * as requester from 'services/Requester';
import compareDesc from 'date-fns/compare_desc';
export async function fetchTransaction() {
try {
const response = await requester.sendGet(endpoints.TRANSACTIONS);
const {Items = []} = response;
return Items.sort((a, b) => compareDesc(a.DateTime, b.DateTime));
} catch (error) {
return [];
}
}
and in data-helpers.js:
export function sortPreferences(data) {
const sorted = data.Items.sort((a, b) => a.Order - b.Order);
const communications = sorted.filter(
p => p.Category === 'CommunicationPreferences'
);
const privacy = sorted.filter(p => p.Category === 'MemberPrivacy');
const involved = sorted.filter(p => p.Category === 'GetInvolved');
const format = data.EmailFormatType === 'HTML' ? 'HTML' : 'Plain Text';
return {
communications,
privacy,
involved,
emailFormatType: format,
isEmailAllowed: data.IsEmailAllowed,
isPhoneAllowed: data.IsPhoneAllowed,
};
}
Most probably you are not getting the expected response from your requester function.
Try logging the response from the requester and see the output. You might have to use response.json() to resolve the promise correctly. This is assuming your requester class/function works like that.