React Query hook call from orval - react-query

I use orval to create interfaces, services and it also create React Query hooks. I have a hook that I cant figur out how to use. It wants some UseMutationOptions togheter with my data.
export const useGetUserContext = <TError = ErrorType<unknown>, TContext = unknown>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof getUserContext>>,
TError,
{ data: UserContextRequest },
TContext
>;
request?: SecondParameter<typeof customInstance>;
}) => {
const { mutation: mutationOptions, request: requestOptions } = options ?? {};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof getUserContext>>, { data: UserContextRequest }> = (
props,
) => {
const { data } = props ?? {};
return getUserContext(data, requestOptions);
};
return useMutation<Awaited<ReturnType<typeof getUserContext>>, TError, { data: UserContextRequest }, TContext>(
mutationFn,
mutationOptions,
);
};

Related

How to insert a draft-js custom component/block

I'm trying to insert my custom block to the editorState of draft-js's editor. I can't seem to find any detailed information on how to accomplish this.
Block Renderer:
const blockRendererFn = (contentBlock) => {
const type = contentBlock.getType();
if (type === 'CustomTestChipBlock') {
return {
component: CustomTestChipBlock,
editable: false,
props: {
foo: 'bar',
},
};
}
}
Block Render Map:
import { DefaultDraftBlockRenderMap } from "draft-js";
import { Map } from 'immutable';
const blockRenderMap = Map({
CustomTestChipBlock: {
element: 'div',
}
}).merge(DefaultDraftBlockRenderMap);
My custom block (material ui chip):
import { Chip } from "#mui/material";
const CustomTestChipBlock = (props) => {
const { block, contentState } = props;
const { foo } = props.blockProps;
const data = contentState.getEntity(block.getEntityAt(0)).getData();
console.log("foo: "+foo)
console.log("data: "+data)
return (
<Chip label="test" size="small"/>
)
}
Now my problem is when I try to insert my custom block. I assume my method of insertion must be wrong. I tried multiple insertion methods but due to lack of any detailed information on the subject, all of them ended up not even running the console.log inside my custom component.
Insertion:
const addChip = () => {
setEditorState(insertBlock("CustomTestChipBlock"));
}
const insertBlock = (type) => {
// This is where I can't find any detailed info at all
const newBlock = new ContentBlock({
key: genKey(),
type: type,
text: "",
characterList: List(),
});
const contentState = editorState.getCurrentContent();
const newBlockMap = contentState.getBlockMap().set(newBlock.key, newBlock);
const newEditorState = ContentState.createFromBlockArray(
newBlockMap.toArray()
)
.set("selectionBefore", contentState.getSelectionBefore())
.set("selectionAfter", contentState.getSelectionAfter());
return EditorState.push(editorState, newEditorState, "add-chip");
};

Rendering a menu in vue 3 after ajax method

I've gotten this menu to work without filtering it, but now I'm doing an ajax request to filter out menu items the user isn't supposed to see, and I'm having some trouble to figure out how to set the resulting menu data, the line that is not working is commented below:
<script>
import { ref } from 'vue';
import axios from 'axios';
var currentSelected = 'device_access';
var menuData = [
{
text: 'Device Access',
id: 'device_access',
children: [
{
text: 'Interactive',
link: '/connection_center'
},{
text: 'Reservation',
link: '/reserve_probe'
}, {
text: 'Reservation Vue',
link: '/reservation.html'
}
]
}, {
text: 'Automation',
id: 'automation',
show: ['is_mxadmin', 'can_schedule_scripts'],
children: [
{
text: 'Builder',
link: '/builder',
},{
text: 'Execution Results',
link: '/test_suite_execution_results'
},
]
}
];
function hasMatch(props, list) {
var match = false;
for (var i=0; i < list.length && !match; i++) {
match = props[list[i]];
}
return match;
}
export default {
name: 'Header',
setup() {
const cursorPosition = ref('0px');
const cursorWidth = ref('0px');
const cursorVisible = ref('visible');
//the menu is zero length until I get the data:
const menu = ref([]);
return {
menu,
cursorPosition,
cursorWidth,
cursorVisible
}
},
created() {
let that = this;
axios.get('navigation_props')
.then(function(res) {
var data = res.data;
var result = [];
menuData.forEach(function(item) {
if (!item.show || hasMatch(data, item.show)) {
var children = [];
item.children.forEach(function (child) {
if (!child.show || hasMatch(data, child.show)) {
children.push({ text: child.text, link: child.link });
}
});
if (children.length > 0) {
result.push({ text: item.text,
children: children, lengthClass: "length_" + children.length });
}
}
});
//continues after comment
this is probably the only thing wrong, I've run this in the debugger and I'm getting the
correct data:
that.$refs.menu = result;
since the menu is not being rebuilt, then this fails:
//this.restoreCursor();
})
.catch(error => {
console.log(error)
// Manage errors if found any
});
},
this.$refs is for template refs, which are not the same as the refs from setup().
And the data fetching in created() should probably be moved to onMounted() in setup(), where the axios.get() callback sets menu.value with the results:
import { onMounted, ref } from 'vue'
export default {
setup() {
const menu = ref([])
onMounted(() => {
axios.get(/*...*/).then(res => {
const results = /* massage res.data */
menu.value = results
})
})
return {
menu
}
}
}
I finally figured out the problem.
This code above will probably work with:
that.menu = result;
You don't need: that.$refs.menu
You can't do it in setup because for some reason "that" is not yet defined.
In my working code I added a new method:
methods: {
setMenuData: function() {
this.menu = filterMenu();
},
}
And "this" is properly defined inside them.

Redux Toolkit - action from one slice to be caught in another slice

There's an action (addOrder) in an orderSlice
orderSlice.js
import { createSlice } from '#reduxjs/toolkit';
const initialState = {
orders: []
};
const ordersSlice = createSlice({
name: 'orders',
initialState,
reducers: {
addOrder: {
reducer: (state, action) => {
state.orders.push(action.payload)
},
prepare: (orderItems, orderTotal) => {
const orderDate = new Date().toDateString();
return { payload: { orderDate, orderItems: orderItems, orderTotal: orderTotal }}
}
}
}
})
export const { addOrder } = ordersSlice.actions;
export default ordersSlice.reducer;
I'd like it to also affect the state in another slice (cartSlice). Once the 'addOrder' is fired, it should also bring the cartReducer to its initial state. Some googling suggested that I should use extrareducers for that but I'm really not getting its syntax. See below (not valid code in extrareducers)
cartSlice
import { createSlice } from '#reduxjs/toolkit';
import { addOrder } from './ordersSlice';
const initialState = {
items: {},
totalAmount: 0
};
const cartSlice = createSlice({
name: 'cart',
initialState: initialState,
reducers: {
addToCart: (state, action) => {
// p = product to be added or amended
const p = action.payload;
if (state.items[p.id]) {
// already exists
state.items[p.id].quantity += 1;
state.items[p.id].sum += p.price;
state.totalAmount += p.price;
} else {
state.items[p.id] = { price: p.price, quantity: 1, title: p.title, sum: p.price};
state.totalAmount += p.price;
}
},
removeFromCart: (state, action) => {
console.log('remove from cart');
console.log(action.payload);
const currentQuantity = state.items[action.payload].quantity;
console.log(currentQuantity);
if (currentQuantity > 1) {
state.items[action.payload].quantity -= 1;
state.items[action.payload].sum -= state.items[action.payload].price;
state.totalAmount -= state.items[action.payload].price;
} else {
state.totalAmount -= state.items[action.payload].price;
delete state.items[action.payload];
}
}
},
extraReducers: (builder) => {
builder
.addCase(addOrder(state) => {
return initialState;
})
}
});
export const { addToCart, removeFromCart } = cartSlice.actions;
export default cartSlice.reducer;
You're almost there! The builder.addCase function takes two arguments. The first is the action creator and the second is the case reducer. So you need a comma after addOrder.
extraReducers: (builder) => {
builder.addCase(addOrder, (state) => {
return initialState;
});
}

Uncaught (in promise) TypeError: Cannot use 'in' operator to search for 'validateStatus' in

I am getting ** Uncaught (in promise) TypeError: Cannot use 'in' operator to search for 'validateStatus' in 5f8425a33a14f026f80133ed** where 5f8425a33a14f026f80133ed is the id passed to the axios url
I want to display the services based on the user id. My url works perfectly in postman but when i access it from the veux store it gives an error.
services.js (store)
import axios from 'axios';
const state = {
services : {},
status: '',
error: null
};
const getters = {
services : state => { return state.services }
};
const actions = {
async fetchServices({commit}, userId) {
let res = await axios.get('http://localhost:5000/api/services/displayUser' , userId)
commit('setProducts', res.data)
return res;
}
};
const mutations = {
setProducts (state, items) {
state.services= items
},
};
export default {
state,
actions,
mutations,
getters
};
This is how I am calling the action :
computed: {
...mapGetters(["services"]),
},
methods: {
...mapActions(["fetchServices"]),
getData(){
this.fetchServices(this.user._id)
},
},
async created() {
await this.getProfile();
await this.getData();
}
The axios route is defined as
router.get('/displayUser', (req,res) => {
const query = user = req.body ;
Services.find(query)
.exec((err, services) => res.json(services))
})
the error screenshot :
Error screenshot
GET request should not have a body. Either use query params, indicate an id in a path, or use POST request.
In case of query params this may look like this:
let res = await axios.get('http://localhost:5000/api/services/displayUser' , { params: { userId })
router.get('/displayUser', (req,res) => {
const query = user = req.query;
Services.find(query)
.exec((err, services) => res.json(services))
})
This worked for me too:
In front end: Vue Js
let res = axios.get("http://localhost:3000/api/v1/role/getRoleByName",
{ params: { roleName: "name of role you want to send as params" },
});
In back end: Node Js
router.get('/getRoleByName', (req,res)=>{
let roleName = req.query.roleName;
roleModule.getRoleByName(roleName).then(data =>{
response.json(res,data)
}
).catch(err=> {
response.badRequest(res, err);
})
});
it's a silly mistake axios.post req.
async addTodo({ commit }, title) {
try {
const res = await axios.post(BASE_URL, { title, complete: false });
commit("newTodo", res.data);
} catch (err) {
console.log(err.message);
}
},

redux observable with axios onProgress

i am creating an upload function that will show a progress bar to the client inside a React Redux and Redux-observable, and i use axios to do a put request to AWS S3.
My epics is as follow
...
function uploadFile(mimetype, url, file) {
const config = {
headers: {
'Content-Type': mimetype,
},
onUploadProgress(progress) {
const percentCompleted = Math.round((progress.loaded * 100) / progress.total)
uploadProgress(percentCompleted)
},
}
axiosRetry(axios, { retries: 3 })
return axios.put(url, file[0], config)
}
export const uploadEpic = (action$, store) => action$
.ofType(SIGNED_URL_SUCCESS)
.mergeMap(() => {
const file = store.getState().File.droppedFile
const mimetype = file[0].type
const { url } = store.getState().SignedUrl
const { fileData } = store.getState().Upload
return of(uploadFile(mimetype, url.data, file))
.concatMap(() => {
const uploadedData = {
url: fileData.url,
thumbUrl: `${fileData.folder}/${fileData.filename}-00001.png`,
}
return [
upload(uploadedData),
uploadSuccess(),
]
})
.catch(error => of(uploadFailure(error)))
})
export default uploadEpic
The upload seems to work, as i received an AWS SNS email telling that its done, but i can't seem to see that it is updating the Upload.progress state inside my Upload reducer.
The reason i am using axios is particulary because its axios-retry and its onUploadProgress, since i can't seem to find an example doing an onProgress using universal-rx-request
so two questions probably
How can i achieve this using axios
How can i achieve this using universal-rx-request
Thanks to this SO answer
I ended up not using axios at all
I got it working with this
import { of } from 'rxjs/observable/of'
import { Subject } from 'rxjs/Subject'
import { Observable } from 'rxjs/Observable'
import 'rxjs/add/observable/dom/ajax'
import { SIGNED_URL_SUCCESS } from 'ducks/SignedUrl'
import {
upload,
uploadIsLoading,
uploadSuccess,
uploadFailure,
uploadProgress,
} from 'ducks/Upload'
export const uploadEpic = (action$, store) => action$
.ofType(SIGNED_URL_SUCCESS)
.mergeMap(() => {
const file = store.getState().File.droppedFile
const mimetype = file[0].type
const { url } = store.getState().SignedUrl
const { fileData } = store.getState().Upload
const progressSubscriber = new Subject()
const request = Observable.ajax({
method: 'PUT',
url: url.data,
body: file[0],
headers: {
'Content-Type': mimetype,
},
progressSubscriber,
})
const requestObservable = request
.concatMap(() => {
const uploadedData = {
...
}
return [
upload(uploadedData),
uploadIsLoading(false),
uploadSuccess(),
]
})
.catch(error => of(uploadFailure(error)))
return progressSubscriber
.map(e => ({ percentage: (e.loaded / e.total) * 100 }))
.map(data => uploadProgress(data.percentage))
.merge(requestObservable)
})
UPDATE: on rxjs 6 the merge operators is deprecated, so if you're using rxjs 6, change the code above to
// some/lib/folder/uploader.js
import { of, merge } from 'rxjs' // import merge here
import { ajax } from 'rxjs/ajax'
import { map, catchError } from 'rxjs/operators' // instead of here
import { Subject } from 'rxjs/Subject'
export function storageUploader(...args) {
const progressSubscriber = new Subject()
const request = ajax({...someRequestOptions})
.pipe(
map(() => success()),
catchError((error) => of(failure(error))),
)
const subscriber = progressSubscriber
.pipe(
map((e) => ({ percentage: (e.loaded / e.total) * 100 })),
map((upload) => progress(upload.percentage)),
catchError((error) => of(failure(error))),
)
return merge(subscriber, request) // merge both like this, instead of chaining the request on progressSubscriber
}
//the_epic.js
export function uploadEpic(action$, state$) {
return action$
.pipe(
ofType(UPLOAD),
mergeMap((someUploadOptions) => uploaderLib(
{ ...someUploadOptions },
actionSuccess,
actionFailure,
actionProgress,
)),
catchError((error) => of(actionFailure(error))),
)
}