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

190 ticket dr 07 add reveal your nft collection cta in back office as well as both deploy cta #222

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
3ec2156
🐛 fix(DataTable.stories.tsx): update play function to include asserti…
sebpalluel Dec 15, 2023
997c47e
🐛 fix(server.ts): change port variable case from lowercase port to up…
sebpalluel Dec 20, 2023
1217708
🐛 fix(EventPassFilesUploaderClient.tsx): set missing files number bas…
sebpalluel Dec 20, 2023
49e33b2
🔧 chore(.eslintrc.json): add 'jsx-a11y' plugin to improve accessibili…
sebpalluel Dec 20, 2023
1231736
🐛 fix(server.ts): change port variable case from lowercase port to up…
sebpalluel Dec 21, 2023
1ef8215
🐛 fix(renameEventPassNftFiles.spec.ts): add missing import statements…
sebpalluel Dec 21, 2023
52a5969
🐛 fix(EventPassDeployButtonClient.tsx): remove unused imports and upd…
sebpalluel Dec 21, 2023
14bec8d
🚀 feat(deployCollectionWrapper.ts): add deployCollectionWrapper funct…
sebpalluel Dec 21, 2023
3cc1c89
🐛 fix(getEventWithPassesOrganizer): add next tags to improve caching …
sebpalluel Dec 21, 2023
9672f1f
🔀 chore(next.config.js): update module imports to include new feature…
sebpalluel Dec 22, 2023
7d0039a
🔨 refactor(action.ts): remove unused imports and functions for better…
sebpalluel Dec 22, 2023
f3e514f
🔀 chore(nft-event-pass): rename eventPass library to event-pass for c…
sebpalluel Dec 22, 2023
f6a0a33
🔧 chore(.eslintrc.json): reformat and optimize ESLint configuration f…
sebpalluel Dec 22, 2023
3ada917
🔧 chore(build-and-e2e-tests.yml): update workflow to use environment …
sebpalluel Dec 22, 2023
1958f6f
🐛 fix(globalSetupHasura.ts): update hasuraUrl variable to use '9696' …
sebpalluel Dec 22, 2023
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
11 changes: 9 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
{
"root": true,
"plugins": ["@nx/eslint-plugin", "markdown", "sonarjs", "tailwindcss"],
"plugins": [
"@nx/eslint-plugin",
"markdown",
"sonarjs",
"tailwindcss",
"jsx-a11y"
],
"extends": [
"eslint-config-prettier",
"plugin:import/recommended",
Expand All @@ -10,7 +16,8 @@
"plugin:sonarjs/recommended",
"plugin:storybook/recommended",
"plugin:playwright/recommended",
"plugin:tailwindcss/recommended"
"plugin:tailwindcss/recommended",
"plugin:jsx-a11y/recommended"
],
"settings": {
"import/resolver": {
Expand Down
13 changes: 7 additions & 6 deletions .github/workflows/build-and-e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ on:

env:
NODE_OPTIONS: '--max_old_space_size=4096'
web: 'false'
back-office: 'false'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand Down Expand Up @@ -41,17 +43,16 @@ jobs:
id: check
run: |
affected=$(pnpm nx affected -t=build)
echo "::set-output name=back-office::$(echo $affected | grep -q 'back-office:build:production' && echo true || echo false)"
echo "::set-output name=web::$(echo $affected | grep -q 'web:build:production' && echo true || echo false)"
echo "back-office=$(echo $affected | grep -q 'back-office:build:production' && echo true || echo false)" >> $GITHUB_ENV
echo "web=$(echo $affected | grep -q 'web:build:production' && echo true || echo false)" >> $GITHUB_ENV

- name: Launch docker services
if: steps.check.outputs.back-office == 'true' || steps.check.outputs.web == 'true'
if: ${{ env.back-office == 'true' || env.web == 'true' }}
run: pnpm docker:services

- name: Run e2e tests for back-office
if: steps.check.outputs.back-office == 'true'
if: ${{ env.back-office == 'true' }}
run: pnpm nx run back-office:e2e --skipInstall

- name: Run e2e tests for web
if: steps.check.outputs.web == 'true'
if: ${{ env.web == 'true' }}
run: pnpm nx run web:e2e --skipInstall
2 changes: 1 addition & 1 deletion apps/back-office/app/global-error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function Error({
}, [error]);

return (
<html>
<html lang="en">
<body>{/* <UIError error={error} reset={reset} /> */}</body>
</html>
);
Expand Down
2 changes: 1 addition & 1 deletion apps/back-office/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export default function NotFound() {
return (
<html>
<html lang="en">
<body>Not Found</body>
</html>
);
Expand Down
10 changes: 10 additions & 0 deletions apps/back-office/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,16 @@ const nextConfig = {
'@features/appNav',
'@features/back-office/appNav',
'@features/back-office/events',
'@features/back-office/events-api',
'@features/back-office/roles',
'@features/back-office/roles-actions',
'@features/back-office/roles-api',
'@features/kyc',
'@features/kyc/server',
'@features/navigation',
'@features/pass',
'@features/pass-api',
'@features/pass-actions',
'@features/organizer/event',
'@features/organizer/event/server',
'@features/settings',
Expand All @@ -108,6 +115,9 @@ const nextConfig = {
'@gql/anonymous/react-query',
'@gql/anonymous/types',
'@gql/shared/types',
'@nft/thirdweb-admin',
'@nft/thirdweb-organizer',
'@nft/event-pass',
],
// https://vercel.com/docs/concepts/deployments/skew-protection#enabling-skew-protection
useDeploymentId: true,
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/global-error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function Error({
}, [error]);

return (
<html>
<html lang="en">
<body>{}</body>
</html>
);
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export default function NotFound() {
return (
<html>
<html lang="en">
<body>Not Found</body>
</html>
);
Expand Down
4 changes: 0 additions & 4 deletions libs/features/back-office/events-api/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
export { getEventPassDelayedRevealedFromEventPassIdOrganizer } from './lib/getEventPassDelayedRevealedFromEventPassIdOrganizer';
export {
getEventPassNftFiles,
type GetEventPassNftFilesProps,
} from './lib/getEventPassNftFiles';
export { getEventWithPassesOrganizer } from './lib/getEventWithPassesOrganizer';
export { getEventsFromOrganizerIdTable } from './lib/getEventsFromOrganizerIdTable';
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,11 @@ export const getEventPassNftFiles = cacheWithDynamicKeys(
const folderPath = getEventPassOrganizerFolderPath(props);
const list = await folder.listFolder({
accountId: env.UPLOAD_ACCOUNT_ID,
folderPath: folderPath,
folderPath,
});
return list.items.filter((item): item is FileSummary => 'filePath' in item);
},
(props: [GetEventPassNftFilesProps]) => [
props[0].organizerId,
props[0].eventId,
props[0].eventPassId,
'getEventPassNftFiles',
`${props[0].organizerId}-${props[0].eventId}-${props[0].eventPassId}-getEventPassNftFiles`,
],
);
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,18 @@ interface GetEventWithPassesOrganizer {

export const getEventWithPassesOrganizer = cache(
async ({ slug, locale }: GetEventWithPassesOrganizer) => {
const data = await adminSdk.GetEventWithPassesOrganizer({
slug,
locale: locale as Locale,
stage: env.HYGRAPH_STAGE as Stage,
});
const data = await adminSdk.GetEventWithPassesOrganizer(
{
slug,
locale: locale as Locale,
stage: env.HYGRAPH_STAGE as Stage,
},
{
next: {
tags: [`${slug}-getEventWithPassesOrganizer`],
},
},
);
return data?.event;
},
);
5 changes: 5 additions & 0 deletions libs/features/back-office/events-types/src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FileSummary } from '@bytescale/sdk';
import type {
GetEventWithPassesOrganizerQuery,
GetEventsFromOrganizerIdTableQuery,
Expand All @@ -16,3 +17,7 @@ export type EventPass = EventFromOrganizerWithPasses['eventPasses'][0];
export type EventPassDelayedRevealed = NonNullable<
EventPass['eventPassDelayedRevealed']
>;

export interface EventPassFileWithName extends FileSummary {
fileName: string;
}
4 changes: 0 additions & 4 deletions libs/features/back-office/events/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@
export default {
displayName: 'features-back-office-events',
preset: '../../../../jest.preset.js',
transform: {
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }],
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../../../coverage/libs/features/back-office/events',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use server';
import env from '@env/server';
import { GetEventPassOrganizerFolderPath } from '@features/pass-common';
import { FileWrapper } from '@file-upload/admin';
import { cacheWithDynamicKeys } from '@next/cache';

import crypto from 'crypto';

export type CheckEventPassNftFilesHashProps =
GetEventPassOrganizerFolderPath & {
filesPath: string[];
};

export const checkEventPassNftFilesHash = cacheWithDynamicKeys(
async ({ filesPath }: CheckEventPassNftFilesHashProps) => {
const fileWrapper = new FileWrapper();
const filesContent = await Promise.all(
filesPath.map((filePath) =>
fileWrapper
.downloadFile({
accountId: env.UPLOAD_ACCOUNT_ID,
filePath,
})
.then(async (response) => {
const blob = await response.blob();
const arrayBuffer = await blob.arrayBuffer();
const hash = crypto
.createHash('sha256')
.update(Buffer.from(arrayBuffer))
.digest('hex');
return { hash, path: filePath };
}),
),
);
const hashMap = new Map();
for (const file of filesContent) {
const existingFiles = hashMap.get(file.hash) || [];
existingFiles.push(file.path);
hashMap.set(file.hash, existingFiles);
}
return Array.from(hashMap.values()).filter((paths) => paths.length > 1);
},
(props: [CheckEventPassNftFilesHashProps]) => [
`${props[0].organizerId}-${props[0].eventId}-${props[0].eventPassId}-getEventPassNftFiles`,
],
);

export type DuplicatesType = Array<Array<string>>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { FileWrapper } from '@file-upload/admin';
import crypto from 'crypto';
import { unstable_cache } from 'next/cache';
import { checkEventPassNftFilesHash } from './checkEventPassFilesHash';

jest.mock('@file-upload/admin');
jest.mock('crypto');
jest.mock('next/cache');

describe('checkEventPassNftFilesHash', () => {
beforeAll(() => {
(unstable_cache as jest.Mock).mockImplementation(
(fn) =>
(...args) =>
fn(...args),
);
const mockArrayBuffer = new ArrayBuffer(8);
const mockBlob = new Blob(['file content']);
mockBlob.arrayBuffer = jest.fn().mockResolvedValue(mockArrayBuffer); // Mock arrayBuffer method

const mockResponse = { blob: jest.fn().mockResolvedValue(mockBlob) };

FileWrapper.prototype.downloadFile = jest
.fn()
.mockResolvedValue(mockResponse);
});
it('should return duplicate file paths', async () => {
const mockFilesPath = ['path1', 'path2'];
const mockProps = {
organizerId: 'org1',
eventId: 'event1',
eventPassId: 'pass1',
filesPath: mockFilesPath,
};
(crypto.createHash as jest.Mock).mockReturnValue({
update: jest.fn().mockReturnThis(),
digest: jest.fn().mockReturnValue('hash1'),
});

const result = await checkEventPassNftFilesHash(mockProps);

expect(result).toEqual([mockFilesPath]);
});
it('should return empty array when no duplicate file paths', async () => {
const mockFilesPath = ['path1', 'path2'];
const mockProps = {
organizerId: 'org1',
eventId: 'event1',
eventPassId: 'pass1',
filesPath: mockFilesPath,
};

(crypto.createHash as jest.Mock).mockReturnValue({
update: jest.fn().mockReturnThis(),
digest: jest
.fn()
.mockReturnValueOnce('hash1')
.mockReturnValueOnce('hash2'),
});

const result = await checkEventPassNftFilesHash(mockProps);

expect(result).toEqual([]);
});

it('should return duplicate separate entries for each files that have paths that have the same hash', async () => {
const mockFilesPath = [
'path1',
'path2',
'path3',
'path4',
'path5',
'path6',
];
const mockProps = {
organizerId: 'org1',
eventId: 'event1',
eventPassId: 'pass1',
filesPath: mockFilesPath,
};

(crypto.createHash as jest.Mock).mockReturnValue({
update: jest.fn().mockReturnThis(),
digest: jest
.fn()
.mockReturnValueOnce('hash1')
.mockReturnValueOnce('hash2')
.mockReturnValueOnce('hash1')
.mockReturnValueOnce('hash1')
.mockReturnValueOnce('hash2')
.mockReturnValueOnce('hash3'),
});

const result = await checkEventPassNftFilesHash(mockProps);

expect(result).toEqual([
['path1', 'path3', 'path4'],
['path2', 'path5'],
]);
});
});
Loading
Loading