import { AnyAction } from "redux" ; import { EthAddress , BigNumber , CharterData , ListingWrapper } from "@joincivil/typescript-types" ; import { Map } from "immutable" ; import { Civil } from "@joincivil/core" ; import { getInfuraUrlFromIpfs , sanitizeConstitutionHtml , is0x0Address } from "@joincivil/utils" ; import { NewsroomState , StateWithNewsroom } from "./reducers" ; import { CmsUserData } from "./types" ; export enum newsroomActions { ADD_NEWSROOM = "ADD_NEWSROOM" , UPDATE_NEWSROOM = "UPDATE_NEWSROOM" , CHANGE_NAME = "CHANGE_NAME" , ADD_EDITOR = "ADD_EDITOR" , ADD_OWNER = "ADD_OWNER" , REMOVE_EDITOR = "REMOVE_EDITOR" , SET_IS_OWNER = "SET_IS_OWNER" , SET_IS_EDITOR = "SET_IS_EDITOR" , SET_MULTISIG_ADDRESS = "SET_MULTISIG_ADDRESS" , SET_MULTISIG_BALANCE = "SET_MULTISIG_BALANCE" } export enum uiActions { ADD_GET_CMS_USER_DATA_FOR_ADDRESS = "ADD_GET_CMS_USER_DATA_FOR_ADDRESS" , GET_CMS_USER_DATA_FOR_ADDRESS = "GET_CMS_USER_DATA_FOR_ADDRESS" , ADD_PERSIST_CHARTER = "ADD_PERSIST_CHARTER" , PERSIST_CHARTER = "PERSIST_CHARTER" } export enum userActions { STORE_USER_DATA = "STORE_USER_DATA" } export enum governmentActions { ADD_CONSTITUTION_URI = "ADD_CONSTITUTION_URI" , ADD_CONSTITUTION_HASH = "ADD_CONSTITUTION_HASH" , ADD_CONSTITUTION_CONTENT = "ADD_CONSTITUTION_CONTENT" } export enum grantActions { SET_GRANT = "CHOOSE_GRANT" , SET_SKIP = "CHOOSE_SKIP" } export enum listingActions { GET_LISTING_FAIL = "GET_LISTING_FAIL" , ADD_OR_UPDATE_LISTING = "ADD_OR_UPDATE_LISTING" , SETUP_LISTING_APPLICATION_SUBSCRIPTION = "SETUP_LISTING_APPLICATION_SUBSCRIPTION" , LISTING_APPLICATION_SUBSCRIPTION_ALREADY_EXISTS = "LISTING_APPLICATION_SUBSCRIPTION_ALREADY_EXISTS" } export enum analyticsActions { EVENT = "EVENT" , NAVIGATE_STEP = "NAVIGATE_STEP" , REACHED_NEW_STEP = "REACHED_NEW_STEP" , APPLICATION_SUBMITTED = "APPLICATION_SUBMITTED" , APPLICATION_SKIPPED = "APPLICATION_SKIPPED" , TRACK_TX = "TRACK_TX" , PUBLISH_CHARTER = "PUBLISH_CHARTER" } export enum TX_TYPE { CREATE_NEWSROOM = "CREATE_NEWSROOM" , CHANGE_NAME = "CHANGE_NAME" , TRANSFER_TOKENS = "TRANSFER_TOKENS" , APPROVE_TOKENS = "APPROVE_TOKENS" , APPLY_TO_TCR = "APPLY_TO_TCR" } export const getEditors = ( address , civil ) : any => async ( dispatch , getState ) : Promise < void > => { const newsroom = await civil . newsroomAtUntrusted ( address ) ; newsroom . editors ( ) . distinct ( ) . forEach ( val => { dispatch ( initContractMember ( address , val ) ) ; dispatch ( addEditor ( address , val ) ) ; } ) ; } ; export const getNewsroom = ( address , civil , charter ) : any => async ( dispatch , getState ) : Promise < AnyAction > => { const newsroom = await civil . newsroomAtUntrusted ( address ) ; const wrapper = await newsroom . getNewsroomWrapper ( ) ; wrapper . data . owners . forEach ( ( userAddress ) => { dispatch ( initContractMember ( address , userAddress ) ) ; } ) ; const multiSigAddr = await newsroom . getMultisigAddress ( ) ; dispatch ( setNewsroomMultisigAddress ( address , multiSigAddr || "" ) ) ; return dispatch ( updateNewsroom ( address , { wrapper , newsroom , charter } ) ) ; } ; export const getIsOwner = ( address , civil ) : any => async ( dispatch , getState ) : Promise < AnyAction > => { const newsroom = await civil . newsroomAtUntrusted ( address ) ; return dispatch ( setIsOwner ( address , await newsroom . isOwner ( ) ) ) ; } ; export const getIsEditor = ( address , civil ) : any => async ( dispatch , getState ) : Promise < AnyAction > => { const newsroom = await civil . newsroomAtUntrusted ( address ) ; return dispatch ( setIsEditor ( address , await newsroom . isEditor ( ) ) ) ; } ; export const getNewsroomMultisigBalance = ( address , multisigAddress , civil ) : any => async ( dispatch , getState ) : Promise < AnyAction > => { const tcr = await civil . tcrSingletonTrusted ( ) ; const token = await tcr . getToken ( ) ; const balance = await token . getBalance ( multisigAddress ) ; dispatch ( setNewsroomMultisigAddress ( address , multisigAddress ) ) ; return dispatch ( setNewsroomMultisigBalance ( address , balance ) ) ; } ; export const setNewsroomMultisigAddress = ( address , multisigAddress ) : AnyAction => { return { type : newsroomActions . SET_MULTISIG_ADDRESS , data : { address , multisigAddress , } , } ; } ; const setNewsroomMultisigBalance = ( address , multisigBalance ) : AnyAction => { return { type : newsroomActions . SET_MULTISIG_BALANCE , data : { address , multisigBalance , } , } ; } ; export const getListing = ( address , civil ) : any => async ( dispatch , getState ) : Promise < AnyAction > => { const tcr = await civil . tcrSingletonTrusted ( ) ; const listing = await tcr . getListing ( address ) ; const listingData = await getListingData ( listing ) ; if ( listingData ) { return dispatch ( addListing ( listingData ) ) ; } else if ( listing ) { return dispatch ( setupListingApplicationsSubscription ( address , listing ) ) ; } return { type : listingActions . GET_LISTING_FAIL , } ; } ; const getListingData = async ( listing ) : Promise < ListingWrapper | undefined > => { const listingData = await listing . getListingWrapper ( ) ; const owner = listingData && listingData . data && listingData . data . owner ; if ( owner && ! is0x0Address ( owner ) ) { return listingData ; } return ; } ; let listingApplicationSubscriptions = Map < EthAddress , any > ( ) ; const setupListingApplicationsSubscription = ( listingAddress , listing ) => async ( dispatch , getState ) : Promise < AnyAction > => { if ( ! listingApplicationSubscriptions . includes ( listingAddress ) ) { const applicationEventHandler = async ( event ) => { const listingData = await getListingData ( listing ) ; if ( listingData ) { dispatch ( addListing ( listingData ) ) ; listingApplicationSubscriptions . get ( listingAddress ) . unsubscribe ( applicationEventHandler ) ; listingApplicationSubscriptions = listingApplicationSubscriptions . delete ( listingAddress ) ; } } ; const subscription = listing . applications ( ) . subscribe ( applicationEventHandler ) ; listingApplicationSubscriptions = listingApplicationSubscriptions . set ( listingAddress , subscription ) ; return { type : listingActions . SETUP_LISTING_APPLICATION_SUBSCRIPTION , data : { address : listingAddress , } , } ; } return { type : listingActions . LISTING_APPLICATION_SUBSCRIPTION_ALREADY_EXISTS , data : { address : listingAddress , } , } ; } ; export const addNewsroom = ( newsroom ) : AnyAction => { return { type : newsroomActions . ADD_NEWSROOM , data : newsroom , } ; } ; export const updateNewsroom = ( address , data ) : AnyAction => { return { type : newsroomActions . UPDATE_NEWSROOM , data : { address , ... data , } , } ; } ; export const addEditor = ( address , editor ) : AnyAction => { return { type : newsroomActions . ADD_EDITOR , data : { address , editor , } , } ; } ; export const addOwner = ( address , owner ) : AnyAction => { return { type : newsroomActions . ADD_OWNER , data : { address , owner , } , } ; } ; export const addListing = ( listing ) : AnyAction => { return { type : listingActions . ADD_OR_UPDATE_LISTING , data : listing , } ; } ; export const removeEditor = ( address , editor ) => { return { type : newsroomActions . REMOVE_EDITOR , data : { address , editor , } , } ; } ; export const setIsOwner = ( address , isOwner ) => { return { type : newsroomActions . SET_IS_OWNER , data : { address , isOwner , } , } ; } ; export const setIsEditor = ( address , isEditor ) => { return { type : newsroomActions . SET_IS_EDITOR , data : { address , isEditor , } , } ; } ; export const changeName = ( address , name ) : AnyAction => { return { type : newsroomActions . CHANGE_NAME , data : { name , address } , } ; } ; export const updateCharter = ( address , charter , dontPersist ? ) : any => ( dispatch , getState ) : AnyAction => { const { newsrooms , newsroomUi } = getState ( ) ; const newsroom = newsrooms . get ( address ) || { wrapper : { data : { } } } ; const persistCharter = newsroomUi . get ( uiActions . PERSIST_CHARTER ) ; if ( persistCharter && ! dontPersist ) { persistCharter ( charter ) ; } return dispatch ( updateNewsroom ( address , { ... newsroom , charter , } ) ) ; } ; export const fetchConstitution = ( ipfsAddress ) : any => async ( dispatch ) => { const infuraUrl = getInfuraUrlFromIpfs ( ipfsAddress ) ; const constitution = await fetch ( infuraUrl ) . then ( async ( body ) => body . json ( ) ) ; return dispatch ( { type : governmentActions . ADD_CONSTITUTION_CONTENT , data : { content : sanitizeConstitutionHtml ( constitution . content ) , } , } ) ; } ; export const fetchNewsroom = ( address ) : any => async ( dispatch , getState ) => { const { newsrooms } = getState ( ) ; const newsroom = newsrooms . get ( address ) ; const wrapper = await newsroom . newsroom ! . getNewsroomWrapper ( ) ; await dispatch ( updateNewsroom ( address , { ... newsroom , wrapper } ) ) ; wrapper . data . owners . forEach ( ( userAddress ) => { dispatch ( initContractMember ( address , userAddress ) ) ; } ) ; } ; export const addGetCmsUserDataForAddress = ( func ) : AnyAction => { return { type : uiActions . ADD_GET_CMS_USER_DATA_FOR_ADDRESS , data : func , } ; } ; export const addPersistCharter = ( func ) : AnyAction => { return { type : uiActions . ADD_PERSIST_CHARTER , data : func , } ; } ; export const storeUserData = ( newsroomAddress , address , userData ) : AnyAction => { return { type : userActions . STORE_USER_DATA , data : { address , userData , } , } ; } ; export const initContractMember = ( newsroomAddress , userAddress ) : any => async ( dispatch , getState ) => { const state = getState ( ) ; let userData = state . newsroomUsers . get ( userAddress ) ; const getCmsUserDataForAddress = state . newsroomUi . get ( uiActions . GET_CMS_USER_DATA_FOR_ADDRESS ) ; if ( ! userData && getCmsUserDataForAddress ) { userData = await getCmsUserDataForAddress ( userAddress ) ; dispatch ( storeUserData ( newsroomAddress , userAddress , userData ) ) ; } } ; export const addAndHydrateEditor = ( newsroomAddress , editorAddress ) : any => async ( dispatch , getState ) => { dispatch ( addEditor ( newsroomAddress , editorAddress ) ) ; return dispatch ( initContractMember ( newsroomAddress , editorAddress ) ) ; } ; export const addAndHydrateOwner = ( newsroomAddress , ownerAddress ) : any => async ( dispatch , getState ) => { dispatch ( addOwner ( newsroomAddress , ownerAddress ) ) ; return dispatch ( initContractMember ( newsroomAddress , ownerAddress ) ) ; } ; export const addConstitutionUri = ( uri ) : AnyAction => { return { type : governmentActions . ADD_CONSTITUTION_URI , data : { uri , } , } ; } ; export const addConstitutionHash = ( hash ) : AnyAction => { return { type : governmentActions . ADD_CONSTITUTION_HASH , data : { hash , } , } ; } ; export const setGrant = ( value ) : AnyAction => { return { type : grantActions . SET_GRANT , data : value , } ; } ; export const setSkip = ( value ) : AnyAction => { return { type : grantActions . SET_SKIP , data : value , } ; } ; export const grantSubmitted = ( ) : AnyAction => { return { type : analyticsActions . APPLICATION_SUBMITTED , } ; } ; export const grantSkipped = ( ) : AnyAction => { return { type : analyticsActions . APPLICATION_SKIPPED , } ; } ; export const trackTx = ( txType , state , txHash ? ) : AnyAction => { return { type : analyticsActions . TRACK_TX , data : { txType , state , txHash , } , } ; } ; export const publishCharter = ( ipfsHash ) : AnyAction => { return { type : analyticsActions . PUBLISH_CHARTER , data : ipfsHash , } ; } ; export const navigateStep = ( step , path = "/apply-to-registry" ) : AnyAction => { return { type : analyticsActions . NAVIGATE_STEP , step , path , } ; } ; export const reachedNewStep = ( step ) : AnyAction => { return { type : analyticsActions . REACHED_NEW_STEP , step , } ; } ; export const analyticsEvent = ( event ) : AnyAction => { return { type : analyticsActions . EVENT , event , } ; } ;