cordis/archive/atoms-old.ts

151 lines
5.9 KiB
TypeScript
Raw Normal View History

2022-01-29 23:05:12 +00:00
import * as electronRemote from '@electron/remote';
const electronConsole = electronRemote.getGlobal('console') as Console;
import Logger from '../../../../logger/logger';
2022-01-29 23:05:12 +00:00
const LOG = Logger.create(__filename, electronConsole);
import { ReactNode } from 'react';
2022-01-29 23:05:12 +00:00
import { atom, selector } from 'recoil';
import { Channel, GuildMetadata, Member, Message } from '../../data-types';
import CombinedGuild from '../../guild-combined';
import GuildsManager from '../../guilds-manager';
2022-01-29 23:05:12 +00:00
export type WithUnloadedValue = {
value: undefined;
hasValueError: false;
valueError: undefined;
};
export type WithLoadedValue<T> = T extends undefined ? never : {
value: T;
2022-01-29 23:05:12 +00:00
hasValueError: false;
valueError: undefined;
};
export type WithFailedValue = {
value: undefined;
hasValueError: true;
valueError: unknown;
};
export type WithLoadableValue<T> = WithUnloadedValue | WithLoadedValue<T> | WithFailedValue;
// NOTE: Should not extend this type. It is for type guards
export type GuildWithValue<T> = WithLoadedValue<T> & { guild: CombinedGuild };
export type GuildWithErrorableValue<T> = WithLoadableValue<T> & { guild: CombinedGuild };
export type ChannelWithErrorableValue<T> = WithLoadableValue<T> & { channel: Channel };
// Devoid is when we don't have a selected guild yet.
export function isDevoid<T>(state: NonNullable<T> | null): state is null {
return state === null;
}
2022-01-29 23:05:12 +00:00
// NOTE: Using "pended" instead of "pending" since it has 6 letters like the rest of these functions. It will make the code look nicer :)
export function isPended<T>(withLoadableValue: WithLoadableValue<T>): withLoadableValue is WithUnloadedValue {
return withLoadableValue.value === undefined && withLoadableValue.hasValueError === false;
}
export function isLoaded<T>(withLoadableValue: WithLoadableValue<T>): withLoadableValue is WithLoadedValue<T> {
return withLoadableValue.value !== undefined;
}
export function isFailed<T>(withLoadableValue: WithLoadableValue<T>): withLoadableValue is WithFailedValue {
return withLoadableValue.hasValueError;
}
2022-02-03 05:05:38 +00:00
// WARNING: This must NOT be used in a place that could prevent hooks from running
2022-01-29 23:05:12 +00:00
// NOTE: This is useful to skip rendering elements that require an atom if its value is not available yet. Using this in the parent element will prevent the child eleemnt from
// needing to implement the complexity of loading without a value
export function isDevoidPendedOrFailed<T>(withNullableLoadableValue: WithLoadableValue<T> | null): withNullableLoadableValue is null | WithUnloadedValue | WithFailedValue {
return withNullableLoadableValue === null || isPended(withNullableLoadableValue) || isFailed(withNullableLoadableValue);
}
export const overlayState = atom<ReactNode>({
key: 'overlayState',
default: null
});
export const guildsManagerState = atom<GuildsManager | null>({
key: 'guildsManagerState',
default: null,
// Allow mutability so that we can have changes to internal guild stuff
// We will still listen to new/update/delete/conflict events to maintain the UI's state
dangerouslyAllowMutability: true
2022-01-29 23:05:12 +00:00
});
export const guildsState = atom<GuildWithErrorableValue<GuildMetadata>[] | null>({
key: 'guildsState',
default: null,
dangerouslyAllowMutability: true
});
export const selectedGuildIdState = atom<number | null>({
key: 'selectedGuildIdState',
default: null
});
export const selectedGuildWithMetaState = selector<GuildWithErrorableValue<GuildMetadata> | null>({
key: 'selectedGuildWithMetaState',
get: ({ get }) => {
const guildsWithMeta = get(guildsState);
if (guildsWithMeta === null) return null;
const guildId = get(selectedGuildIdState);
if (guildId === null) return null;
return guildsWithMeta.find(guildWithMeta => guildWithMeta.guild.id === guildId) ?? null;
},
dangerouslyAllowMutability: true
});
2022-01-29 23:05:12 +00:00
// Note: You likely want selectedGuildWithMetaState
export const selectedGuildState = selector<CombinedGuild | null>({
key: 'selectedGuildState',
get: ({ get }) => {
const guildWithMeta = get(selectedGuildWithMetaState);
2022-01-29 23:05:12 +00:00
if (isDevoid(guildWithMeta)) return null;
return guildWithMeta.guild;
},
dangerouslyAllowMutability: true
});
2022-01-29 23:05:12 +00:00
export const selectedGuildWithMembersState = atom<GuildWithErrorableValue<Member[]> | null>({
key: 'selectedGuildWithMembersState',
default: null,
dangerouslyAllowMutability: true
});
export const selectedGuildWithSelfMemberState = selector<GuildWithErrorableValue<Member> | null>({
key: 'selectedGuildWithSelfMemberState',
get: ({ get }) => {
const guildWithMembers = get(selectedGuildWithMembersState);
if (isDevoid(guildWithMembers)) return null;
if (isFailed(guildWithMembers)) return { guild: guildWithMembers.guild, value: undefined, hasValueError: true, valueError: 'members fetch error' };
if (isPended(guildWithMembers)) return { guild: guildWithMembers.guild, value: undefined, hasValueError: false, valueError: undefined };
const selfMember = guildWithMembers.value.find(member => member.id === guildWithMembers.guild.memberId) ?? null;
if (selfMember === null) {
LOG.warn('unable to find self member in members');
return { guild: guildWithMembers.guild, value: undefined, hasValueError: true, valueError: 'unable to find self in members' };
}
return { guild: guildWithMembers.guild, value: selfMember, hasValueError: false, valueError: undefined };
},
dangerouslyAllowMutability: true
});
export const selectedGuildWithChannelsState = atom<GuildWithErrorableValue<Channel[]> | null>({
key: 'selectedGuildChannelsState',
2022-01-29 23:05:12 +00:00
default: null,
dangerouslyAllowMutability: true
});
export const selectedGuildWithActiveChannelIdState = atom<GuildWithValue<string | null> | null>({
key: 'selectedGuildWithActiveChannelIdState',
2022-01-29 23:05:12 +00:00
default: null,
dangerouslyAllowMutability: true
});
2022-01-29 23:05:12 +00:00
export const selectedGuildWithActiveChannelMessagesState = atom<GuildWithValue<ChannelWithErrorableValue<Message[]>> | null>({
key: 'selectedGuildWithActiveChannelMessagesState',
2022-01-29 23:05:12 +00:00
default: null,
dangerouslyAllowMutability: true
});
2022-01-29 23:05:12 +00:00
// TODO: selectedGuildWithActiveChannelState