Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Moments): Add function to create Moment without uploading media #135

Merged
merged 2 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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[];
}