IO consuming with FP-TS - fp-ts

What is the idiomatic fp alternative of forEach part in this code
const ios: IO<void>[] = [...]
ios.forEach(io => io());
?
There are some docs which use sequence_ from Foldable but it is no longer available in fp-ts#2.0.3.
EDIT:
The best I could do is
import { array } from 'fp-ts/lib/Array';
array.sequence(io)(ios)();
but sequence collects the results and I do not really have anything to do with void[].

I was wondering the same thing. The following seems to work.
import { IO, io } from 'fp-ts/lib/IO';
import { traverse_ } from 'fp-ts/lib/Foldable';
import { array } from 'fp-ts/lib/Array';
import { identity } from 'fp-ts/lib/function';
import { log } from 'fp-ts/lib/Console';
const actions: Array<IO<void>> = [log('hello'), log('world')];
const action: IO<void> = traverse_(io,array)(actions,identity);

Related

unable to read from new table in Amplify Studio

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,

React - useEffect based on service variable

I have a question about usage of React.useEffect function based on the variable being a part of a service which I use to make some magic behind.
import React, { useEffect } from "react";
import { treeStructureService } from "../../services/dependency_injection";
import "./ModelTree.css";
const ModelTree = (props: any) => {
useEffect(() => {
// some code
console.log('Use Effect runs...')
}, [treeStructureService.tree])
return <div>ModelTree</div>;
};
export { ModelTree };
TreeStructureService.tree changes the variable depending upon the upload of new files to a project. Such action takes some time in the background, which is why I tried to use such a variable in useEffect to rerender the tree again when changes were propagated to the service.
The most interesting part of the TreeStructureService was presented below:
import { TreeNode } from "../../interfaces/tree_node";
import { modelLoaderService } from "../dependency_injection";
export class TreeStructureService {
public tree: TreeNode | undefined;
constructor() {}
async addTreeToProject(modelID: number, newTree: TreeNode):Promise<void> {
if (modelID == 0) {
this.tree = newTree;
}else{
console.log('Doing magic')
}
}
}
In dependency injection, necessary services are called and exported to use the "equivalent" of DependencyInjection from Angular.:
import { IFCLoaderService } from "./viewer/model_loaders/ifc_loader_service";
import { ModelLoaderService } from "./viewer/model_loaders/model_loader_service";
import { SelectionService } from "./viewer/selection_service";
import { ThreeSceneService } from "./viewer/three_scene_service";
import { TreeStructureService } from "./viewer/tree_structure_service";
import { VisibilityService } from "./viewer/visiblity_service";
export const modelLoaderService = new ModelLoaderService();
export const ifcLoaderService = new IFCLoaderService();
export const threeSceneService = new ThreeSceneService();
export const selectionService = new SelectionService();
export const visibilityService = new VisibilityService();
export const treeStructureService = new TreeStructureService();
I'll be glad for any suggestions. In the next steps, I'll add redux to control the state of the application. So maybe you have some idea that I could pass a new tree as an action argument? However, I don't know how to do it outside of the components.
While you don't need any fancy code to connect your tree model to React, there a few ways to do that.
Basically, you have to wire or connect your state changes.
You could write your own event emmitter, then subscribe via react hook, but here is straightforward shortcut. Mobx does this for you
import React, { useEffect } from "react"
import { treeStructureService } from "../../services/dependency_injection"
import "./ModelTree.css"
import { TreeNode } from "../../interfaces/tree_node"
import { modelLoaderService } from "../dependency_injection"
// Step 1: Notice 2 new imports
import { makeAutoObservable } from "mobx"
import { observer } from "mobx-react-lite"
export class TreeStructureService {
public tree: TreeNode | undefined
constructor() {
// Step 2: notice that I mark `tree` as observable
makeAutoObservable(this)
}
async addTreeToProject(modelID: number, newTree: TreeNode): Promise<void> {
if (modelID == 0) {
this.tree = newTree
} else {
console.log("Doing magic")
}
}
}
// Step 3: Notice the observer wrapper from "mobx-react-lite"
export const ModelTree = observer((props: any) => {
// This re-render when TreeNode changes
console.log(treeStructureService.tree)
return <div>ModelTree</div>
})

React redux - actions

Recently I'm trying my best in redux, and I have seen a really good folder structure project, I tried to get the same structure, but the same way didn't work...
E.g. I've got a path something like that: ./src/_actions and inside this folder I've got "user.actions.js", "alert.actions.js", "index.js".
In alert.actions.js I've got something like that:
import { alertConstants } from "../_constants/alert.constants";
export const alertActions = {
success,
error,
clear,
};
function success(message) {
return { type: alertConstants.SUCCESS, message };
}
function error(message) {
return { type: alertConstants.ERROR, message };
}
function clear() {
return { type: alertConstants.CLEAR };
}
And I'd love to import all of them from one place like to the folder where path is "./../test.js":
import {alertActions} from "./../_actions";
import {useDispatch} from "react-redux";
export const test = () => {
const dispatch = useDispatch();
return (
<button onClick={() => dispatch(alertActions.success("test"))}> Click </button>
)
}
but I got something like "alertActions.success" is undefined. I don't know what I'm doing wrong.. In that project, index.js has been empty as well... that object supposed to export those all functions.. somebody know any solution? :(
You need to export the object after the functions are made. Usually they are hoisted, but in this case you are probably using strict mode and they are not. You have to either move the export object or better yet export all of them individually and then when you are importing them you should write:
import * as alertActions from 'youfile'
And if you want to export a whole object you should export it like:
export default alertActions
And then you need to import them like:
import alertActions from 'yourfile'
and access them:
alrtActions.error()

Client Side Unit Testing Meteor/React w/Enzyme

so i've been stuck for several days on an issue while implementing Unit Testing and Integration testing in a large production application that was built in Meteor/React tech stack. I am using the meteortesting:mocha package as recommended by the meteor documentation and enzyme.
The issue i am having is that i am not really grasping how i can mock the withTracker functionality. I am trying to use our dev database as the source for the test users and mock data. All of the props are generated in the tracker and then sent to the component it wraps. (Code sample below). Another issue i am having is that we are using meteor:universe for i18n internationalization. When mounting the component it shows plain text instead of the translated content. Wondering if there's a work around. Thanks in advance!
Component I am testing:
import React, { useState } from "react";
import ABCComponent from "./ABCComponent";
import XYZ from "./XYZComponent";
import * as ROUTE_CONSTANTS from "../../global/RoutesConstants";
import { withRouter } from "react-router-dom";
import { withTracker } from "meteor/react-meteor-data";
import UserAssessments from "../../collections/UserAssessments";
import moment from "moment-timezone";
import { i18n } from "meteor/universe:i18n";
const SortDashboard = (props) => {
const [isSkillsSort, setIsSkillSort] = useState(true);
return (
<div>
{/* Contains some logic to set 'isSetSkillSort' state true or false (business logic hidden for security purposes*/}
{isSkillsSort ? (
<ABCComponent user={props.user} skillsSorts={props.skillsSorts} employeeList={props.directReportEmp} />
) : (
<XYZComponent
user={props.user}
importanceSorts={props.importanceSorts}
employeeList={props.directReportEmp}
/>
)}
</div>
);
};
const SortDashboardTracker = withTracker((props) => {
if (!props.user) return {};
const abcSubscription = Meteor.subscribe("abcSubscription");
if (abcSubscription.ready()) {
const rawData = UserAssessments.find(
{ "assessor._id": Meteor.user().profile._id },
{ sort: { updatedDate: -1 } }
).fetch();
rawData.forEach((assessment) => {
//Do Something (business logic hidden for security purposes)
});
}
const xyzSubscription = Meteor.subscribe("xyzSubscription");
let directReportEmp = [];
if (xyzSubscription.ready()) {
directReportEmp = Meteor.users.find({ "profile.managerId": Meteor.user().username }).fetch();
}
return { importanceSorts, skillsSorts, directReportEmp };
})(SortDashboard);
export default withRouter(SortDashboardTracker);
My Test:
import {Meteor} from 'meteor/meteor';
import React from 'react';
import chai from 'chai';
import sinon, { mock } from 'sinon'
import {mount, shallow, configure, render} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import {mockManager,mockEmp1,mockEmp2,mockEmp3,mockUser} from '../../mockUsers'
import SortDashboard from '../../../../imports/components/cllWizard/SortDashboard';
import { withRouter, BrowserRouter as Router } from "react-router-dom";
configure({adapter: new Adapter()});
if (Meteor.isClient) {
describe('WizardComponent', ()=> {
//let returnedText
//importing the mock user we created for testing purposes
const currentUser = mockUser
let props = {user: currentUser}
beforeEach(() => {
// now Meteor.user() will return the user we just imported
sinon.stub(Meteor, 'user');
Meteor.user.returns(currentUser);
// needed in methods
sinon.stub(Meteor, 'userId');
Meteor.userId.returns(currentUser._id);
});
//afterEach specifies that we want to restore the user after running the test
afterEach(() => {
Meteor.user.restore();
Meteor.userId.restore();
});
it('CLIENT: should render the Sort Dashboard', () => {
const wrapper = mount(<Router><SortDashboard.WrappedComponent {...props}/></Router>)
console.log(wrapper.debug())
});
});
}
TLDR;
Need to test a client side component that uses withTracker and withRouter
Need to be able to see the translated text from meteor:universe:i18n in the test
Pulling mock data from the db instead of manually creating it.
The issue may very well be my approach and lack of understanding. Please correct me where-ever necessary. Thanks in advance!

React-intl for non components

Currently I have the following code to expose react-intl to non-components, but it throws an error for intl as undefined.
I have created a separate component as 'CurrentLocale' and inject-intl to it. The exporting function t will use intl formatMessage from CurrentLocale context.
import React from 'react';
import {injectIntl} from 'react-intl';
import PropTypes from 'prop-types';
import { flow } from 'lodash';
class CurrentLocale extends React.Component {
constructor(props,context){
super();
console.log(context,props);
console.log(this.formatMessage);
const { intl } = this.context.intl;//this.props;
this.formatMessage = intl.formatMessage;
}
render() {
return false;
}
}
CurrentLocale.contextTypes={
intl:PropTypes.object,
};
injectIntl(CurrentLocale);
function intl() {
return new CurrentLocale();
}
function formatMessage(...args) {
return intl().formatMessage(...args);
}
const t = opts => {
const id = opts.id;
const type = opts.type;
const values = opts.values;
let t;
switch (type){
case 'message':
default:
t = formatMessage(id, values);
}
return t;
}
export default t;
t is called as in another plain javascript file as,
import t from './locale/t';
t( { type: 'message', id:'button.Next'});
Following is the error message.
Thanks in advance.
There's also another approach very simple I used for solving a similar problem: Provide access to the intl object for a non-component:
import { IntlProvider, addLocaleData } from 'react-intl';
import localeDataDE from 'react-intl/locale-data/de';
import localeDataEN from 'react-intl/locale-data/en';
import { formMessages } from '../../../store/i18n'; // I defined some messages here
import { Locale } from '../../../../utils'; //I set the locale fom here
addLocaleData([...localeDataEN, ...localeDataDE]);
const locale = Locale.setLocale(); //my own methods to retrieve locale
const messages = Locale.setMessages(); //getting messages from the json file.
const intlProvider = new IntlProvider({ locale, messages });
const { intl } = intlProvider.getChildContext();
export const SCHEMA = {
salutation: {
label: intl.formatMessage(formMessages.salutationLabel),
errormessages: {
required: intl.formatMessage(formMessages.salutationError),
},
},
academic_title_code: {
label: intl.formatMessage(formMessages.academicTitleLabel),
},
};
It's working like a charm!
UPDATE for v3.x
After migration to react-intl 3.x
import { createIntl, createIntlCache } from 'react-intl'
import { formMessages } from '../../../store/i18n'; // I defined some messages here
import { Locale } from '../../../../utils'; //I set the locale fom here
const locale = Locale.setLocale(); //my own methods to retrieve locale
const messages = Locale.setMessages(); //getting messages from the json file.
// This is optional but highly recommended
// since it prevents memory leak
const cache = createIntlCache();
const intl = createIntl({ locale, messages }, cache)
export const SCHEMA = {
salutation: {
label: intl.formatMessage(formMessages.salutationLabel),
errormessages: {
required: intl.formatMessage(formMessages.salutationError),
},
},
academic_title_code: {
label: intl.formatMessage(formMessages.academicTitleLabel),
},
};
There's a new way to do it pretty easily with createIntl, it returns an object that you can use outside React components. Here's an example from the documentation.
import {createIntl, createIntlCache, RawIntlProvider} from 'react-intl'
// This is optional but highly recommended
// since it prevents memory leak
const cache = createIntlCache()
const intl = createIntl({
locale: 'fr-FR',
messages: {}
}, cache)
// Call imperatively
intl.formatNumber(20)
// Pass it to IntlProvider
<RawIntlProvider value={intl}>{foo}</RawIntlProvider>
I personally store the intl object in Redux store so I can access it everywhere in my app.
This line: const { intl } = this.context.intl; should be const { intl } = this.context;
Here is a reference post of someone doing almost the exact same thing as you are: https://github.com/yahoo/react-intl/issues/983#issuecomment-342314143
In the above the author is creating essentially a singleton that is exported instead of creating a new instance each time like you have above. This might be something you want to consider as well.
There's also another way solving a similar problem to used react-intl formatMessage for non-components.
Create a LocaleStore.js store file.
import _formatMessage from "format-message";
export default class LocaleStore {
formatMessage = (id, values) => {
if (!(id in this.messages)) {
console.warn("Id not found in intl list: " + id);
return id;
}
return _formatMessage(this.messages[id], values);
};
}
import LocaleStore your CombinedStores.js
import LocaleStore from "./stores/LocaleStore";
import en from "./translations/en";
import de from "./translations/de";
import Global from "./stores/global"
const locale = new LocaleStore("en", {
en,
de
});
export default {
global:new Global(locale)
}
now you can use this in your GlobalStore.js
class GlobalStore {
constructor(locale) {
this.locale = locale;
}
formatMessage=(message_is,formatLanguage="en")=> {
return this.locale.formatMessage(message_id, formatLanguage);
}
}
react-intl decorates your React.Component with wrapped component which is injected internationalized message dynamically so that the locale data is able to be loaded dynamically.
import { injectIntl } from 'react-intl';
class MyComponent extends Component {
render() {
const intl = this.props;
const title = intl.formatMessage({ id: 'title' });
return (<div>{title}</div>);
}
};
export default injectIntl(MyComponent);
It can be applied only in view layer such as React.Component.
react-intl can't be used in Vanilla JS. For example,
export default const rules = {
noSpace(value) {
if (value.includes(' ')) {
return 'Space is not allowed.';
}
}
};
One of alternative is react-intl-universal. It can be used not only in Component but also in Vanilla JS.
For example:
import intl from 'react-intl-universal';
export default const rules = {
noSpace(value) {
if (value.includes(' ')) {
return intl.get('no_space');
}
}
};
See react-intl-universal online example
If you can accept to use a function component I prefer to use the useIntl hook
https://reactjs.org/docs/components-and-props.html#function-and-class-components
I can then get values like this:
import { useIntl } from "react-intl";
const intl = useIntl()
intl.formatMessage({ id: 'myId' }),
https://formatjs.io/docs/react-intl/api/#useintl-hook

Resources