React hook array to a specific format to be used in react native Calendar - react-hooks

I have date value in this format from a for each loop. Each loop provides value in the following format.
start: 2021-06-30T18:30:00.000Z
title: one
start: 2021-07-31T18:30:00.000Z
title: two
start: 2021-08-31T18:30:00.000Z
title: three
function loadItems() {
firebase.database().ref("events").once("value", (userSnapshot) => {
userSnapshot.forEach(element => {
const start = moment(element.child('start').val()).toDate();
const title = element.child('title').val();
)}
)}
}
I have created variables like this.
const [items, setItems] = useState([]);
const [markedDates, setMarkedDates] = useState([]);
I need to convert this to the following format. How can I use useState to update the value on for each loop.
markedDates={{
'2021-06-30': {selected: true, marked: true},
'2021-06-30': {selected: true, marked: true},
'2021-06-30': {selected: true, marked: true},
}}
items={{
'2021-06-30': [{name: 'one'}],
'2021-06-30': [{name: 'two'}],
'2021-06-30': [{name: 'three'}],
}}

Reduce your firebase array to required format. Something along these lines would do the job.
const items = userSnapshot.reduce((accumulator: any, item: any) => {
if(accumulator.hasOwnProperty(item.start.slice(0, 10))) {
accumulator = {...accumulator, [item.start.slice(0, 10)]: [...accumulator[item.start.slice(0, 10)], { name: item.title }]}
} else {
accumulator = {...accumulator, [`${item.start.slice(0, 10)}`]: [{ name: item.title }]}
}
return accumulator
}, {})

Related

Mongoose refPath one path multi model populate

Used refPath here documentation: https://mongoosejs.com/docs/populate.html#dynamic-ref
const match = { $or: [{ build: variable }, { country: variable }], isDeleted: undefined };
const populate = [
{ path: `reviewer`, model: 'Build', select: { _id: 1, username: 1, } },
{ path: `reviewer`, model: 'Country', select: { _id: 1, username: 1 } },
];
const buildPopulate = await this.reviewsModel.find(match).select(select).populate(populate[0]).lean().exec();
const countryPopulate = await this.reviewsModel.find(match).select(select).populate(populate[1]).lean().exec();
return { buildPopulate, countryPopulate };
When i was try to populate with just one query i cant get populate[0] already get reviewer null.
I have find this solution but i think is not healthy solution. Anyone have idea ??

Optimistic response not working when adding items to list

My data model is a list with items. Very simple:
{
_id: 1,
name: "List 1",
items: [
{ _id: 2, text: "Item text 1" },
{ _id: 3, text: "Item text 2" }
]
}
Adding a new list with optimistic response works perfectly:
const [addListMutation] = useAddListMutation({
update: (cache, { data }) => {
const cachedLists =
(cache.readQuery<GetAllListsQuery>({
query: GetAllListsDocument,
})?.lists as TList[]) ?? [];
if (data) {
cache.writeQuery({
query: GetAllListsDocument,
data: {
lists: [...cachedLists, data?.list as TList],
},
});
}
},
});
const addList = async (name: string) => {
const list = {
_id: ..new id here,
name,
items: [],
};
const variables: AddListMutationVariables = {
data: list,
};
await addListMutation({
variables,
optimisticResponse: {
list,
},
});
};
This gets reflected immediately in my component using const { loading, data } = useGetAllListsQuery();. data is updated twice; first with the optimistic response and then after the mutation is done. Just like expected.
Now I'm trying to add an item to the list this way:
const [updateListMutation] = useUpdateListMutation({
update: (cache, { data }) => {
const cachedLists =
(cache.readQuery<GetAllListsQuery>(
{
query: GetAllListsDocument,
},
)?.lists as TList[]) ?? [];
if (data?.list) {
// Find existing list to update
const updatedList = data?.list as TList;
const updatedListIndex = cachedLists.findIndex(
(list: TList) => list._id === updatedList._id,
);
// Create a copy of cached lists and replace entire list
// with new list from { data }.
const updatedLists = [...cachedLists];
updatedLists[updatedListIndex] = { ...updatedList };
cache.writeQuery({
query: GetAllListsDocument,
data: {
lists: updatedLists,
},
});
}
}
});
const updateList = async (updatedList: TList) => {
const variables: UpdateListMutationVariables = {
query: {
_id: updatedList._id,
},
set: updatedList,
};
await updateListMutation({
variables,
optimisticResponse: {
list: updatedList,
},
});
};
const addListItem = async (list: TList, text: string) => {
const updatedList = R.clone(list);
updatedList.items.push({
_id: ...new item id here,
text: 'My new list item',
});
await updateList(updatedList);
};
The problem is is in my component and the const { loading, data } = useGetAllListsQuery(); not returning what I expect. When data first changes with the optimistic response it contains an empty list item:
{
_id: 1,
name: "List 1",
items: [{}]
}
And only after the mutation response returns, it populates the items array with the item with text 'My new list item'. So my component first updates when the mutation is finished and not with the optimistic response because it can't figure out to update the array. Don't know why?
(and I have checked that the updatedLists array in writeQuery correctly contains the new item with text 'My new list item' so I'm trying to write the correct data).
Please let me know if you have any hints or solutions.
I've tried playing around with the cache (right now it's just initialized default like new InMemoryCache({})). I can see the cache is normalized with a bunch of List:1, List:2, ... and ListItem:3, ListItem:4, ...
Tried to disable normalization so I only have List:{id} entries. Didn't help. Also tried to add __typename: 'ListItem' to item added, but that only caused the { data } in the update: ... for the optimistic response to be undefined. I have used hours on this now. It should be a fairly simple and common use case what I'm trying to do :).
package.json
"#apollo/client": "^3.3.4",
"graphql": "^15.4.0",
"#graphql-codegen/typescript": "^1.19.0",

Executing rxjs observable function recursively

I'm new to RxJs. I'm trying to run observable function recursively with no luck. I want to print in this order.
form textbox icon textarea
Here is what I tried so far. Any help will be very much appreciated.
const args = {
name: 'form',
children: [{
name: 'textbox',
children: [{
name: 'icon',
children: []
}]
}, {
name: 'textarea',
children: []
}]
};
import { of, from, Observable, concat } from 'rxjs';
import { map, concatAll, combineAll } from 'rxjs/operators';
const render = (component) => {
return new Observable<any>(observer => {
console.log(component.name);
concat(...component.children.map(x => render(x)))
.subscribe(() => observer.next());
});
};
render(args).subscribe(() => console.log('done'));
This gives the correct order. If I've missed something, please comment:
const { of, concat } = rxjs;
const args = {
name: 'form',
children: [
{
name: 'textbox',
children: [
{
name: 'icon',
children: []
}
]
},
{
name: 'textarea',
children: []
}
]
};
const render = (component) => concat(of(component), ...component.children.map(render));
render(args).subscribe(({name}) => console.log(name));
<script src="https://unpkg.com/#reactivex/rxjs#6.4/dist/global/rxjs.umd.js"></script>

Combine the all custom array value into one string observable

I am trying to return single string once map the whole array object.
Here it's below code that combine my custom array input to string but it's emit each value alone instead map into single block of string(concatenation of string).
const exampleInfo: GithubInfo = {
name: "Hello",
login: "Hello1",
description: "TypeScript dev",
repos: [{ project: "ts", star: 5 }, { project: "js", star: 5 }]
};
const repos = from(gitHubInfo["repos"]);
const reposeDetial = repos.pipe(
map(val => `${val.project},${val.star}`))
.subscribe(val => {
console.log(val); // emit `ts,5` ,`js,5` instead in single block `ts,5,js,5`
});
If you want to concat your emitted data at the end of your operators chain, you can use reduce. It will accumulate all your stream into one single value:
const exampleInfo: GithubInfo = {
name: "Hello",
login: "Hello1",
description: "TypeScript dev",
repos: [{ project: "ts", star: 5 }, { project: "js", star: 5 }]
};
const repos = from(gitHubInfo["repos"]);
const reposeDetial = repos.pipe(
map(val => `${val.project},${val.star}`)),
reduce((acc, value) => acc.concat(value), '')
).subscribe(val => {
console.log(val); // emit `ts,5,js,5`
});

CycleJS Collection returning old data

I'm trying to recreate RxMarbles for RxJS 5, but I'm having feedback problems when I change the collection's data (specifically the length of the data source).
I added console.logs for debugging
Note for those who are familiar with RxMarbles, I renamed "Diagram" to "Timeline".
import { svg } from '#cycle/dom';
import isolate from '#cycle/isolate';
import { Observable } from 'rxjs';
import { apply, flip, map, max, merge, path, prop, sortBy, zip } from 'ramda';
import { Collection } from '../collection';
import { Marble } from './marble';
import { EndMarker } from './end-marker';
function sortMarbleDoms$(marbles$) {
const doms$ = Collection.pluck(marbles$, prop('DOM'));
const dataList$ = Collection.pluck(marbles$, prop('data'));
return Observable.combineLatest(doms$, dataList$, zip)
.map(sortBy(path([1, 'time'])))
.map(map(prop(0)));
}
function OriginalTimeline({ DOM, marbles: marblesState$, end: end$ }) {
const marblesProps$ = end$.map(({ time }) => ({
minTime: 0,
maxTime: time,
}));
const endMarkerProps$ = marblesState$.map(marbles => ({
minTime: marbles.map(prop('time')).reduce(max, 0),
maxTime: 100,
}));
const marblesSources = { DOM, props: marblesProps$ };
const endMarkerSources = {
DOM,
props: endMarkerProps$,
time: end$.pluck('time'),
};
const marbles$ = Collection.gather(
Marble, marblesSources, marblesState$
.do(a=>console.log('marblesState', a)), '_itemId');
const marbleDOMs$ = sortMarbleDoms$(marbles$);
const endMarker = EndMarker(endMarkerSources);
const vtree$ = Observable.combineLatest(marbleDOMs$, endMarker.DOM)
.map(([marbleDOMs, endMarkerDOM]) =>
svg({
attrs: { viewBox: '0 0 100 10' },
style: { width: 500, height: 50, overflow: 'visible' },
}, [
svg.line({
attrs: { x1: 0, x2: 100, y1: 5, y2: 5 },
style: { stroke: 'black', strokeWidth: 0.4 },
}),
endMarkerDOM,
...marbleDOMs,
])
);
const marbleData$ = Collection.pluck(marbles$, prop('data'))
.withLatestFrom(marblesState$, zip)
.map(map(apply(flip(merge))))
const data$ = Observable.combineLatest(marbleData$, endMarker.time)
.map(([marbles, endMarkerTime]) => ({
marbles,
end: { time: endMarkerTime },
}))
.debounceTime(1);
return { DOM: vtree$, data: data$.do(a=>console.log('tdata', a)) };
}
export function Timeline(sources) {
return isolate(OriginalTimeline)(sources);
}
The basic structure of the app is that all necessary data is fed into a global sink to a dummy driver that just takes the data and re-emits it as is (so in theory, all outputs should be new inputs).
Because of this, the problem might be in other parts of my code so I'm happy to post a codepen/plunkr of the code if it helps. This is indeed working sometimes, but not all the time.
Here's the console outputs (abridged)
store Object {route: "merge", inputs: undefined}
timeline.js:39 marblesState [Object, Object, Object, Object]
timeline.js:69 tdata Object {marbles: Array[3], end: Object}
sandbox.js:48 data [Object, Object]
app.js:26 store Object {route: "merge", inputs: Array[2]}
Notice the marblesState has 4 objects, but the tdata returns marbles with an array of 3 objects. For some reason, the Collection is only returning 3 items.
Any help is appreciated. Thanks!
I have no idea why this makes sense but moving up the debounceTime(1) made it work
const marbleData$ = Collection.pluck(marbles$, prop('data'))
.debounceTime(1)
.withLatestFrom(marblesState$, zip)
.map(map(apply(flip(merge))))
const data$ = Observable.combineLatest(marbleData$, endMarker.time)
.map(([marbles, endMarkerTime]) => ({
marbles,
end: { time: endMarkerTime },
}));
The Collection.pluck was sending once for each piece of new and old data.

Resources