pussy-ts/src/redux/reducers/backend.ts

import {
  ServiceName,
  SyncState,
  ServiceStatus,
  BroadcastChannelMessage,
} from 'src/services/backend/types/services';
import { assocPath } from 'ramda';
import { CommunityDto } from 'src/services/CozoDb/types/dto';
import { NeuronAddress } from 'src/types/base';

import { removeDublicates } from 'src/utils/list';
import { clone } from 'lodash';
import { SYNC_ENTRIES_TO_TRACK_PROGRESS } from 'src/services/backend/services/sync/services/consts';
import { syncEntryNameToReadable } from 'src/services/backend/services/sync/utils';

export const RESET_SYNC_STATE_ACTION_NAME = 'reset_sync_entry';

type BackendState = {
  dbPendingWrites: number;
  syncState: SyncState;
  community: {
    isLoaded: boolean;
    raw: CommunityDto[];
    following: NeuronAddress[];
    followers: NeuronAddress[];
    friends: NeuronAddress[];
  };
  services: {
    [key in ServiceName]: {
      status: ServiceStatus;
      error?: string;
      message?: string;
    };
  };
};

const initialSyncState = {
  // status: 'inactive',
  entryStatus: {},
  totalEstimatedTime: 0,
  message: '',
  inProgress: false,
  completeIntialSyncEntries: [],
  initialSyncDone: false,
};

const initialState: BackendState = {
  dbPendingWrites: 0,
  community: {
    isLoaded: false,
    raw: [],
    following: [],
    followers: [],
    friends: [],
  },
  syncState: initialSyncState,
  services: {
    db: { status: 'inactive' },
    ipfs: { status: 'inactive' },
    sync: { status: 'inactive' },
  },
};

// Backend state
function backendReducer(
  state = initialState,
  action:
    | BroadcastChannelMessage
    | {
        type: typeof RESET_SYNC_STATE_ACTION_NAME;
      }
) {
  switch (action.type) {
    case 'indexeddb_write': {
      return assocPath(['dbPendingWrites'], action.value, state);
    }

    case RESET_SYNC_STATE_ACTION_NAME: {
      return { ...state, syncState: initialSyncState };
    }
    case 'sync_entry': {
      const { entry, state: entryState } = action.value;
      const updatedEntry = {
        ...state.syncState.entryStatus[entry],
        ...entryState,
      };
      const newState = assocPath(
        ['syncState', 'entryStatus', entry],
        updatedEntry,
        state
      );

      const messages: string[] = [];
      let totalEstimatedTime = 0;
      const { entryStatus, completeIntialSyncEntries } = newState.syncState;
      const newCompleteIntitalSyncEntries = clone(completeIntialSyncEntries);
      SYNC_ENTRIES_TO_TRACK_PROGRESS.forEach((name) => {
        if (entryStatus[name]) {
          const { progress, status } = newState.syncState.entryStatus[name]!;

          // Push flags that initial sync was done
          if (
            status &&
            ['active', 'listen'].some((s) => s === status) &&
            !completeIntialSyncEntries.some((entryName) => entryName === name)
          ) {
            newCompleteIntitalSyncEntries.push(name);
          }

          if (progress && status === 'in-progress') {
            totalEstimatedTime += progress.estimatedTime;
            const percents = Math.round(
              (progress.completeCount / progress.totalCount) * 100
            );
            messages.push(`${syncEntryNameToReadable(name)}: ${percents}%`);
          }
        }
      });

      const initialSyncDone = SYNC_ENTRIES_TO_TRACK_PROGRESS.reduce(
        (prev, curr) =>
          prev && newCompleteIntitalSyncEntries.some((n) => n === curr),
        true
      );

      newState.syncState = {
        ...newState.syncState,
        message: messages.join(', '),
        totalEstimatedTime,
        inProgress: messages.length > 0,
        completeIntialSyncEntries: newCompleteIntitalSyncEntries,
        initialSyncDone,
      };

      return newState;
    }

    case 'service_status': {
      const { name, status, message } = action.value;
      return assocPath(['services', name], { status, message }, state);
    }

    case 'load_community': {
      const { action: stateAction, items } = action.value;
      // console.log('------------load_community', stateAction, items, state);
      if (stateAction === 'reset') {
        const community = {
          isLoaded: false,
          raw: [],
          following: [],
          followers: [],
          friends: [],
        };
        return { ...state, community };
      }
      const allItems = [...state.community.raw, ...items];

      const community = {
        isLoaded: stateAction === 'complete',
        raw: allItems,
        following: removeDublicates(
          allItems
            .filter((item) => item.following && !item.follower)
            .map((item) => item.neuron)
        ),
        followers: removeDublicates(
          allItems
            .filter((item) => item.follower && !item.following)
            .map((item) => item.neuron)
        ),
        friends: removeDublicates(
          allItems
            .filter((item) => item.follower && item.following)
            .map((item) => item.neuron)
        ),
      };

      return { ...state, community };
    }

    default:
      return state;
  }
}

export default backendReducer;

Synonyms

cyb/src/redux/reducers/backend.ts

Neighbours