Skip to content

Commit

Permalink
feat(moments): Add function to create Moment without uploading media (#…
Browse files Browse the repository at this point in the history
…135)

* Rename `createMoment` to `createMomentAndUploadMedia`
* Create new `createMoment` function to create a Moment without uploading media.
* Change visibility to `public` for `uploadMediaList` and `awaitForMediaProcessing`
  * Allows clients to upload media separately from Moments creation
* Adjust MomentsClient unit tests
  • Loading branch information
reobin authored Oct 4, 2024
1 parent 6111874 commit a9d7528
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 17 deletions.
2 changes: 1 addition & 1 deletion docs/pages/packages/moments/UploadMoments.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const fileBuffer = await fsPromises.readFile('path/to/poap-moment.png');
const mimeType = mime.getType('path/to/poap-moment.png');

// Upload it.
const moment: Moment = await client.createMoment({
const moment: Moment = await client.createMomentAndUploadMedia({
/**
* Moments are associated with a Drop.
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/moments/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const input: CreateMomentInput = {
},
timeOut: 5000, // Optional: Set a timeout for the media processing
};
const moment: Moment = await client.createMoment(input);
const moment: Moment = await client.createMomentAndUploadMedia(input);
```

Explanations for each step:
Expand Down
2 changes: 1 addition & 1 deletion packages/moments/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@poap-xyz/moments",
"version": "0.5.5",
"version": "0.6.0",
"description": "Moments module for the poap.js library",
"main": "dist/cjs/index.cjs",
"module": "dist/esm/index.mjs",
Expand Down
61 changes: 57 additions & 4 deletions packages/moments/src/client/MomentsClient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CreateMomentInput } from './dtos/create/CreateInput';
import { CreateSteps } from './dtos/create/CreateSteps';
import { v4 } from 'uuid';
import { PatchMomentInput } from './dtos/patch/PatchInput';
import { CreateAndUploadMomentInput } from './dtos/create/CreateAndUploadInput';

describe('MomentsClient', () => {
const MOMENT_ID = 'this-is-a-moment-id';
Expand All @@ -29,6 +30,10 @@ describe('MomentsClient', () => {
fileType: FILE_2_TYPE,
},
];
const MEDIA_KEYS = [
'45201634-1996-4243-9c24-31da706be427',
'fbc3cf5f-fd65-4d2f-88fa-7025ebc7d631',
];

let poapMomentsAPIMocked: MockProxy<PoapMomentsApi>;
let compassProviderMocked: MockProxy<PoapCompass>;
Expand All @@ -40,14 +45,14 @@ describe('MomentsClient', () => {
onStepUpdate = jest.fn();
});

describe('createMoment', () => {
it('should create a moment', async () => {
describe('createMomentAndUploadMedia', () => {
it('should create a moment and upload media', async () => {
// GIVEN
const client = new MomentsClient(
poapMomentsAPIMocked,
compassProviderMocked,
);
const inputs: CreateMomentInput = {
const inputs: CreateAndUploadMomentInput = {
dropId: DROP_ID,
tokenId: TOKEN_ID,
media: MEDIAS_TO_CREATE,
Expand Down Expand Up @@ -81,7 +86,7 @@ describe('MomentsClient', () => {
};

// WHEN
const moment = await client.createMoment(inputs);
const moment = await client.createMomentAndUploadMedia(inputs);

// THEN
expect(moment.id).toBe(MOMENT_ID);
Expand Down Expand Up @@ -111,6 +116,54 @@ describe('MomentsClient', () => {
expect(onStepUpdate).toHaveBeenCalledTimes(4);
});
});
describe('createMoment', () => {
it('should create a moment and attach media keys', async () => {
// GIVEN
const client = new MomentsClient(
poapMomentsAPIMocked,
compassProviderMocked,
);
const inputs: CreateMomentInput = {
dropId: DROP_ID,
tokenId: TOKEN_ID,
mediaKeys: MEDIA_KEYS,
author: AUTHOR,
onStepUpdate,
description: DESCRIPTION,
};
poapMomentsAPIMocked.createMoment.mockResolvedValue({
id: MOMENT_ID,
author: AUTHOR,
createdOn: new Date(),
dropId: DROP_ID,
tokenId: TOKEN_ID,
});

const EXPECTED_MOMENT_CREATE_INPUT = {
dropId: DROP_ID,
tokenId: TOKEN_ID,
author: AUTHOR,
description: DESCRIPTION,
mediaKeys: MEDIA_KEYS,
};

// WHEN
const moment = await client.createMoment(inputs);

// THEN
expect(moment.id).toBe(MOMENT_ID);
expect(moment.author).toBe(AUTHOR);
expect(moment.dropId).toBe(DROP_ID);
expect(moment.tokenId).toBe(TOKEN_ID);
expect(poapMomentsAPIMocked.createMoment).toHaveBeenCalledWith(
EXPECTED_MOMENT_CREATE_INPUT,
);
expect(poapMomentsAPIMocked.uploadFile).not.toHaveBeenCalledWith();
expect(onStepUpdate).toHaveBeenCalledWith(CreateSteps.UPLOADING_MOMENT);
expect(onStepUpdate).toHaveBeenCalledWith(CreateSteps.FINISHED);
expect(onStepUpdate).toHaveBeenCalledTimes(2);
});
});
describe('updateMoment', () => {
it('should update a moment', async () => {
// GIVEN
Expand Down
21 changes: 15 additions & 6 deletions packages/moments/src/client/MomentsClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,21 @@ import { CreateSteps } from './dtos/create/CreateSteps';
import { PatchMomentInput } from './dtos/patch/PatchInput';
import { FetchMomentsInput } from './dtos/fetch/FetchMomentsInput';
import { MomentsSortFields } from './dtos/fetch/MomentsSortFields';
import { CreateAndUploadMomentInput } from './dtos/create/CreateAndUploadInput';

export class MomentsClient {
constructor(
private poapMomentsApi: PoapMomentsApi,
private CompassProvider: CompassProvider,
) {}

public async createMoment(input: CreateMomentInput): Promise<Moment> {
/** Uploads media files first, then creates the Moment. */
public async createMomentAndUploadMedia(
input: CreateAndUploadMomentInput,
): Promise<Moment> {
let mediaKeys: string[] = [];
if (input.media && input.media.length > 0) {
mediaKeys = await this.uploadMedias(
mediaKeys = await this.uploadMediaList(
input.media,
input.onStepUpdate,
input.onFileUploadProgress,
Expand All @@ -39,28 +43,33 @@ export class MomentsClient {
}

if (mediaKeys.length > 0) {
await this.awaitForMediasProcessing(
await this.awaitForMediaProcessing(
mediaKeys,
input.onStepUpdate,
input.timeOut,
);
}

return this.createMoment({ ...input, mediaKeys });
}

/** Creates the Moment, attaching previously uploaded media when applicable. */
public async createMoment(input: CreateMomentInput): Promise<Moment> {
void input.onStepUpdate?.(CreateSteps.UPLOADING_MOMENT);
const response = await this.poapMomentsApi.createMoment({
dropId: input.dropId,
author: input.author,
tokenId: input.tokenId,
description: input.description,
mediaKeys,
mediaKeys: input.mediaKeys || [],
});
void input.onStepUpdate?.(CreateSteps.FINISHED);

return Moment.fromCreated(response);
}

// eslint-disable-next-line max-statements
private async uploadMedias(
public async uploadMediaList(
mediaArray: CreateMedia[],
onStepUpdate?: (step: CreateSteps) => void | Promise<void>,
onFileUploadProgress?: (progress: number) => void | Promise<void>,
Expand Down Expand Up @@ -89,7 +98,7 @@ export class MomentsClient {
return mediaKeys;
}

private async awaitForMediasProcessing(
public async awaitForMediaProcessing(
mediaKeys: string[],
onStepUpdate?: (step: CreateSteps) => void | Promise<void>,
timeOut?: number,
Expand Down
25 changes: 25 additions & 0 deletions packages/moments/src/client/dtos/create/CreateAndUploadInput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { CreateSteps } from './CreateSteps';
import { CreateMedia } from './CreateMedia';

/**
* Interface representing the input needed to create a moment and upload media in one action.
* @interface
* @property {number} dropId - The ID of the drop related to the moment.
* @property {number} [tokenId] - The ID of the token related to the moment (optional).
* @property {string} author - The author of the moment. An Ethereum address.
* @property {string} description - The description of the moment (optional).
* @property {string} timeOut - The amount of time to wait until media is processed.
* @property {(step: CreateSteps) => void | Promise<void>} [onStepUpdate] - Optional callback function to be called when the step changes.
* @property {(progress: number) => void | Promise<void>} [onFileProgress] - Optional callback function to be called when the file upload progress change - progress is a number between 0 and 1.
* @property {CreateMedia[]} media - The media to be uploaded.
*/
export interface CreateAndUploadMomentInput {
author: string;
description?: string;
dropId: number;
tokenId?: number;
timeOut?: number;
onStepUpdate?: (step: CreateSteps) => void | Promise<void>;
onFileUploadProgress?: (progress: number) => void | Promise<void>;
media?: CreateMedia[];
}
6 changes: 2 additions & 4 deletions packages/moments/src/client/dtos/create/CreateInput.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { CreateSteps } from './CreateSteps';
import { CreateMedia } from './CreateMedia';

/**
* Interface representing the input needed to create a moment.
Expand All @@ -11,7 +10,7 @@ import { CreateMedia } from './CreateMedia';
* @property {string} timeOut - The amount of time to wait until media is processed.
* @property {(step: CreateSteps) => void | Promise<void>} [onStepUpdate] - Optional callback function to be called when the step changes.
* @property {(progress: number) => void | Promise<void>} [onFileProgress] - Optional callback function to be called when the file upload progress change - progress is a number between 0 and 1.
* @property {CreateMedia[]} media - The media to be uploaded.
* @property {string[]} mediaKeys - The media keys previously uploaded to attach to the Moment.
*/
export interface CreateMomentInput {
author: string;
Expand All @@ -20,6 +19,5 @@ export interface CreateMomentInput {
tokenId?: number;
timeOut?: number;
onStepUpdate?: (step: CreateSteps) => void | Promise<void>;
onFileUploadProgress?: (progress: number) => void | Promise<void>;
media?: CreateMedia[];
mediaKeys?: string[];
}

0 comments on commit a9d7528

Please sign in to comment.