@amityco/ts-sdk-react-native
Version:
Amity Social Cloud Typescript SDK
161 lines (132 loc) • 4.88 kB
text/typescript
import { uuid } from '~/core/uuid';
import { fireEvent } from '~/core/events';
import { getActiveClient, getActiveUser } from '~/client/api';
import { ingestInCache } from '~/cache/api/ingestInCache';
import { UNSYNCED_OBJECT_CACHED_AT_VALUE } from '~/utils/constants';
import { dropFromCache, pullFromCache, pushToCache, upsertInCache } from '~/cache/api';
import { LinkedObject } from '~/utils/linkedObject';
import { convertParams, prepareMessagePayload } from '../utils';
const getLocalId = () => `LOCAL_${uuid()}`;
// FIXME: temp solution
let uniqueId: string | undefined;
/* begin_public_function
id: message.create.text_message, message.create.image_message, message.create.file_message, message.create.video_message, message.create.audio_message, message.create.custom_message
*/
type createMessageParam<T extends Amity.MessageContentType> = Pick<
Amity.Message<T>,
'subChannelId' | 'parentId' | 'dataType' | 'tags' | 'metadata' | 'mentionees'
> & {
data?: Amity.Message<T>['data'];
fileId?: Amity.File['fileId'];
referenceId?: string;
};
const createMessageOptimistic = <T extends Amity.MessageContentType>(
bundle: createMessageParam<T>,
): Amity.InternalMessage | undefined => {
const client = getActiveClient();
if (!client.cache) return;
/*
* When creating messages optimistically a messageId needs to be added by the
* client, created a new variable to allow backward compatibility of API
*
* Updated to handle client requirement to add messageId while uploading
* a message with image.
* Temporary!
*/
uniqueId = bundle.referenceId || getLocalId();
const bundleWithMessageId = { messageId: uniqueId, uniqueId, ...bundle };
client.log('message/createMessage.optimistically', bundleWithMessageId);
const subChannel = pullFromCache<Amity.SubChannel>(['subChannel', 'get', bundle.subChannelId]);
if (subChannel) {
upsertInCache(['subChannel', 'get', bundle.subChannelId], {
...subChannel.data,
messageCount: subChannel.data.messageCount + 1,
});
if (subChannel.data.channelId === subChannel.data.subChannelId) {
const channel = pullFromCache<Amity.StaticInternalChannel>([
'channel',
'get',
subChannel.data.channelId,
]);
if (channel?.data) {
upsertInCache(['channel', 'get', subChannel.data.channelId], {
...channel.data,
messageCount: (channel.data.messageCount ?? 0) + 1,
});
}
}
}
// as reused to update created and updated time, which should be the same
const createdTime = new Date().toISOString();
const message = {
creatorId: client.userId!,
creatorPrivateId: getActiveUser()._id,
channelSegment: (subChannel?.data.messageCount ?? 0) + 1,
childrenNumber: 0,
createdAt: createdTime,
updatedAt: createdTime,
syncState: Amity.SyncState.Syncing,
isDeleted: false,
...bundleWithMessageId,
} as Amity.InternalMessage;
const cachedAt = UNSYNCED_OBJECT_CACHED_AT_VALUE;
pushToCache(['message', 'get', message.messageId], message, { cachedAt });
fireEvent('local.message.created', { messages: [message] });
return message;
};
/**
* ```js
* import { createMessage, createQuery, runQuery } from '@amityco/ts-sdk-react-native'
*
* const query = createQuery(createMessage, {
* subChannelId: 'foobar',
* data: { text: 'hello world' },
* });
*
* runQuery(query, ({ data: message, loading }) => {
* console.log(message);
* });
* ```
*
* Creates an {@link Amity.Message}
*
* @param bundle The data necessary to create a new {@link Amity.Message}
* @returns The newly created {@link Amity.Message}
*
* @category Message API
* @async
*/
export const createMessage = async <T extends Amity.MessageContentType>(
bundle: createMessageParam<T>,
): Promise<Amity.Cached<Amity.Message>> => {
const client = getActiveClient();
client.log('message/createMessage', bundle);
const optimisticData = createMessageOptimistic<T>(bundle);
const referenceId = bundle.referenceId || uniqueId || getLocalId();
uniqueId = undefined;
try {
const { data: payload } = await client.http.post<Amity.MessagePayload>('/api/v5/messages', {
...convertParams(bundle),
referenceId,
});
const data = await prepareMessagePayload(payload);
const { messages } = data;
const cachedAt = client.cache && Date.now();
if (client.cache) {
ingestInCache(data, { cachedAt });
}
fireEvent('local.message.created', {
messages: [{ ...messages[0], syncState: Amity.SyncState.Synced }],
});
return {
data: LinkedObject.message(messages[0]),
cachedAt,
};
} catch (e) {
fireEvent('local.message.created', {
messages: [{ ...optimisticData, syncState: Amity.SyncState.Error } as Amity.InternalMessage],
});
throw e;
}
};
/* end_public_function */