import Reflux from 'reflux'; import OrganizationActions from 'app/actions/organizationActions'; import ProjectActions from 'app/actions/projectActions'; import TeamActions from 'app/actions/teamActions'; import {ORGANIZATION_FETCH_ERROR_TYPES} from 'app/constants'; import {Organization, Project, Team} from 'app/types'; import RequestError from 'app/utils/requestError/requestError'; type UpdateOptions = { replace?: boolean; }; type OutputState = { organization: Organization | null; loading: boolean; dirty: boolean; errorType?: string | null; error?: RequestError | null; }; type OrganizationStoreInterface = { init: () => void; reset: () => void; onUpdate: (org: Organization, options: UpdateOptions) => void; onFetchOrgError: (err: RequestError) => void; onProjectOrTeamChange: () => void; onLoadProjects: (projects: Project[]) => void; onLoadTeams: (teams: Team[]) => void; get: () => OutputState; }; const storeConfig: Reflux.StoreDefinition & OrganizationStoreInterface = { init() { this.reset(); this.listenTo(OrganizationActions.update, this.onUpdate); this.listenTo(OrganizationActions.fetchOrg, this.reset); this.listenTo(OrganizationActions.fetchOrgError, this.onFetchOrgError); // fill in teams and projects if they are loaded this.listenTo(ProjectActions.loadProjects, this.onLoadProjects); this.listenTo(TeamActions.loadTeams, this.onLoadTeams); // mark the store as dirty if projects or teams change this.listenTo(ProjectActions.createSuccess, this.onProjectOrTeamChange); this.listenTo(ProjectActions.updateSuccess, this.onProjectOrTeamChange); this.listenTo(ProjectActions.changeSlug, this.onProjectOrTeamChange); this.listenTo(ProjectActions.addTeamSuccess, this.onProjectOrTeamChange); this.listenTo(ProjectActions.removeTeamSuccess, this.onProjectOrTeamChange); this.listenTo(TeamActions.updateSuccess, this.onProjectOrTeamChange); this.listenTo(TeamActions.removeTeamSuccess, this.onProjectOrTeamChange); this.listenTo(TeamActions.createTeamSuccess, this.onProjectOrTeamChange); }, reset() { this.loading = true; this.error = null; this.errorType = null; this.organization = null; this.dirty = false; this.trigger(this.get()); }, onUpdate(updatedOrg: Organization, {replace = false}: UpdateOptions = {}) { this.loading = false; this.error = null; this.errorType = null; this.organization = replace ? updatedOrg : {...this.organization, ...updatedOrg}; this.dirty = false; this.trigger(this.get()); }, onFetchOrgError(err: RequestError) { this.organization = null; this.errorType = null; switch (err?.status) { case 401: this.errorType = ORGANIZATION_FETCH_ERROR_TYPES.ORG_NO_ACCESS; break; case 404: this.errorType = ORGANIZATION_FETCH_ERROR_TYPES.ORG_NOT_FOUND; break; default: } this.loading = false; this.error = err; this.dirty = false; this.trigger(this.get()); }, onProjectOrTeamChange() { // mark the store as dirty so the next fetch will trigger an org details refetch this.dirty = true; }, onLoadProjects(projects: Project[]) { if (this.organization) { // sort projects to mimic how they are received from backend projects.sort((a, b) => a.slug.localeCompare(b.slug)); this.organization = {...this.organization, projects}; this.trigger(this.get()); } }, onLoadTeams(teams: Team[]) { if (this.organization) { // sort teams to mimic how they are received from backend teams.sort((a, b) => a.slug.localeCompare(b.slug)); this.organization = {...this.organization, teams}; this.trigger(this.get()); } }, get() { return { organization: this.organization, error: this.error, loading: this.loading, errorType: this.errorType, dirty: this.dirty, }; }, }; type OrganizationStore = Reflux.Store & OrganizationStoreInterface; const OrganizationStore = Reflux.createStore(storeConfig) as OrganizationStore; export default OrganizationStore;