Skip to content
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
39 changes: 20 additions & 19 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ module.exports = {
rules: {

// Style
'@stylistic/js/arrow-parens': ["error", "always"],
'@stylistic/js/arrow-spacing': ["error", { "before": true, "after": true }],
'@stylistic/js/brace-style': "error",
'@stylistic/js/comma-dangle': ["error", "always-multiline"],
'@stylistic/js/eol-last': ["error", "always"],
'@stylistic/js/jsx-quotes': ["error", "prefer-double"],
'@stylistic/js/no-multi-spaces': "error",
'@stylistic/js/arrow-parens': ['error', 'always'],
'@stylistic/js/arrow-spacing': ['error', { 'before': true, 'after': true }],
'@stylistic/js/brace-style': 'error',
'@stylistic/js/comma-dangle': ['error', 'always-multiline'],
'@stylistic/js/eol-last': ['error', 'always'],
'@stylistic/js/implicit-arrow-linebreak': ['error', 'beside'],
'@stylistic/js/jsx-quotes': ['error', 'prefer-double'],
'@stylistic/js/no-multi-spaces': 'error',
'@stylistic/js/no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 0 }],
'@stylistic/ts/indent': ['error', 2],
'@stylistic/ts/object-curly-spacing': ['error', 'always'],
Expand All @@ -42,20 +43,20 @@ module.exports = {
'quotes': 'off',
'@typescript-eslint/quotes': ['error', 'single'],
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': ['warn', { 'argsIgnorePattern': '^_' }],
'@typescript-eslint/no-unused-vars': ['warn', { 'argsIgnorePattern': '^_', 'destructuredArrayIgnorePattern': '^_', 'varsIgnorePattern': '^_' }],

// Misc.
"curly": ["error"],
"arrow-body-style": ["error", "as-needed"],
"no-console": ["warn", { allow: ["warn", "error", "info"] }],
"@typescript-eslint//explicit-function-return-type": "off",
'curly': ['error'],
'arrow-body-style': ['error', 'as-needed'],
'no-console': ['warn', { allow: ['warn', 'error', 'info'] }],
'@typescript-eslint/explicit-function-return-type': 'off',

// Plugin configurations
'import-newlines/enforce': ['error', 2],
// ENABLE LATER
// 'import-newlines/enforce': ['error', {
// items: 2,
// "max-len": 100,
// 'max-len': 100,
// }],
'react-refresh/only-export-components': [ 'warn', { allowConstantExport: true } ],
'simple-import-sort/exports': 'error',
Expand All @@ -75,21 +76,21 @@ module.exports = {
'react/display-name': 'off',
// 'react/jsx-sort-props': [ 'error', {
// callbacksLast: true,
// multiline: "last",
// multiline: 'last',
// reservedFirst: true,
// ignoreCase: true,
// }],
// "react/jsx-max-props-per-line": ["error", {
// 'react/jsx-max-props-per-line': ['error', {
// maximum: 1,
// when: "multiline"
// when: 'multiline'
// }]
},
overrides: [
{
// enable the rule specifically for TypeScript files
"files": ["convex/**/*.ts"],
"rules": {
"@typescript-eslint/explicit-function-return-type": "error",
'files': ['convex/**/*.ts'],
'rules': {
'@typescript-eslint/explicit-function-return-type': 'error',
},
},
],
Expand Down
48 changes: 38 additions & 10 deletions convex/_generated/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type * as _model_common__helpers_gameSystem_createSortByRanking from "../
import type * as _model_common__helpers_gameSystem_divideBaseStats from "../_model/common/_helpers/gameSystem/divideBaseStats.js";
import type * as _model_common__helpers_gameSystem_sumBaseStats from "../_model/common/_helpers/gameSystem/sumBaseStats.js";
import type * as _model_common__helpers_getCountryName from "../_model/common/_helpers/getCountryName.js";
import type * as _model_common__helpers_getDocStrict from "../_model/common/_helpers/getDocStrict.js";
import type * as _model_common__helpers_getEnvironment from "../_model/common/_helpers/getEnvironment.js";
import type * as _model_common__helpers_getRange from "../_model/common/_helpers/getRange.js";
import type * as _model_common__helpers_getStaticEnumConvexValidator from "../_model/common/_helpers/getStaticEnumConvexValidator.js";
Expand All @@ -41,7 +42,9 @@ import type * as _model_common_themes from "../_model/common/themes.js";
import type * as _model_common_tournamentPairingConfig from "../_model/common/tournamentPairingConfig.js";
import type * as _model_common_tournamentStatus from "../_model/common/tournamentStatus.js";
import type * as _model_common_types from "../_model/common/types.js";
import type * as _model_files_actions_convertImageToPdf from "../_model/files/actions/convertImageToPdf.js";
import type * as _model_files_index from "../_model/files/index.js";
import type * as _model_files_queries_getFileMetadata from "../_model/files/queries/getFileMetadata.js";
import type * as _model_files_queries_getFileUrl from "../_model/files/queries/getFileUrl.js";
import type * as _model_friendships__helpers_deepenFriendship from "../_model/friendships/_helpers/deepenFriendship.js";
import type * as _model_friendships_index from "../_model/friendships/index.js";
Expand All @@ -51,10 +54,6 @@ import type * as _model_friendships_mutations_deleteFriendship from "../_model/f
import type * as _model_friendships_queries_getFriendship from "../_model/friendships/queries/getFriendship.js";
import type * as _model_friendships_queries_getFriendshipsByUser from "../_model/friendships/queries/getFriendshipsByUser.js";
import type * as _model_friendships_table from "../_model/friendships/table.js";
import type * as _model_gameSystems_battlefront_flamesOfWarV4__helpers_deepenListData from "../_model/gameSystems/battlefront/flamesOfWarV4/_helpers/deepenListData.js";
import type * as _model_gameSystems_battlefront_flamesOfWarV4__model_listData from "../_model/gameSystems/battlefront/flamesOfWarV4/_model/listData.js";
import type * as _model_gameSystems_battlefront_flamesOfWarV4_index from "../_model/gameSystems/battlefront/flamesOfWarV4/index.js";
import type * as _model_gameSystems_index from "../_model/gameSystems/index.js";
import type * as _model_leagueOrganizers__helpers_checkUserIsLeagueOrganizer from "../_model/leagueOrganizers/_helpers/checkUserIsLeagueOrganizer.js";
import type * as _model_leagueOrganizers__helpers_deepenLeagueOrganizer from "../_model/leagueOrganizers/_helpers/deepenLeagueOrganizer.js";
import type * as _model_leagueOrganizers_index from "../_model/leagueOrganizers/index.js";
Expand All @@ -80,11 +79,23 @@ import type * as _model_leagues_queries_getLeague from "../_model/leagues/querie
import type * as _model_leagues_queries_getLeagues from "../_model/leagues/queries/getLeagues.js";
import type * as _model_leagues_table from "../_model/leagues/table.js";
import type * as _model_leagues_types from "../_model/leagues/types.js";
import type * as _model_listComments__helpers_deepenListComment from "../_model/listComments/_helpers/deepenListComment.js";
import type * as _model_listComments_index from "../_model/listComments/index.js";
import type * as _model_listComments_mutations_createListComment from "../_model/listComments/mutations/createListComment.js";
import type * as _model_listComments_table from "../_model/listComments/table.js";
import type * as _model_listComments_types from "../_model/listComments/types.js";
import type * as _model_lists__helpers_checkListSubmittedOnTime from "../_model/lists/_helpers/checkListSubmittedOnTime.js";
import type * as _model_lists__helpers_deepenList from "../_model/lists/_helpers/deepenList.js";
import type * as _model_lists__helpers_getAvailableActions from "../_model/lists/_helpers/getAvailableActions.js";
import type * as _model_lists_index from "../_model/lists/index.js";
import type * as _model_lists_mutations_importListData from "../_model/lists/mutations/importListData.js";
import type * as _model_lists_mutations_createList from "../_model/lists/mutations/createList.js";
import type * as _model_lists_mutations_deleteList from "../_model/lists/mutations/deleteList.js";
import type * as _model_lists_mutations_updateList from "../_model/lists/mutations/updateList.js";
import type * as _model_lists_queries_getList from "../_model/lists/queries/getList.js";
import type * as _model_lists_queries_getListsByTournamentRegistration from "../_model/lists/queries/getListsByTournamentRegistration.js";
import type * as _model_lists_queries_getListsByUser from "../_model/lists/queries/getListsByUser.js";
import type * as _model_lists_table from "../_model/lists/table.js";
import type * as _model_lists_types from "../_model/lists/types.js";
import type * as _model_matchResultComments__helpers_deepenMatchResultComment from "../_model/matchResultComments/_helpers/deepenMatchResultComment.js";
import type * as _model_matchResultComments_index from "../_model/matchResultComments/index.js";
import type * as _model_matchResultComments_mutations_addMatchResultComment from "../_model/matchResultComments/mutations/addMatchResultComment.js";
Expand Down Expand Up @@ -122,6 +133,8 @@ import type * as _model_photos_index from "../_model/photos/index.js";
import type * as _model_photos_mutations_createPhoto from "../_model/photos/mutations/createPhoto.js";
import type * as _model_photos_queries_getPhoto from "../_model/photos/queries/getPhoto.js";
import type * as _model_photos_table from "../_model/photos/table.js";
import type * as _model_tournamentCompetitors__helpers_checkUserIsTeamCaptain from "../_model/tournamentCompetitors/_helpers/checkUserIsTeamCaptain.js";
import type * as _model_tournamentCompetitors__helpers_checkUsersAreTeammates from "../_model/tournamentCompetitors/_helpers/checkUsersAreTeammates.js";
import type * as _model_tournamentCompetitors__helpers_deepenTournamentCompetitor from "../_model/tournamentCompetitors/_helpers/deepenTournamentCompetitor.js";
import type * as _model_tournamentCompetitors__helpers_getAvailableActions from "../_model/tournamentCompetitors/_helpers/getAvailableActions.js";
import type * as _model_tournamentCompetitors__helpers_getDetails from "../_model/tournamentCompetitors/_helpers/getDetails.js";
Expand Down Expand Up @@ -291,6 +304,7 @@ import type * as generateFileUploadUrl from "../generateFileUploadUrl.js";
import type * as http from "../http.js";
import type * as leagueRankings from "../leagueRankings.js";
import type * as leagues from "../leagues.js";
import type * as listComments from "../listComments.js";
import type * as lists from "../lists.js";
import type * as matchResultComments from "../matchResultComments.js";
import type * as matchResultLikes from "../matchResultLikes.js";
Expand Down Expand Up @@ -336,6 +350,7 @@ declare const fullApi: ApiFromModules<{
"_model/common/_helpers/gameSystem/divideBaseStats": typeof _model_common__helpers_gameSystem_divideBaseStats;
"_model/common/_helpers/gameSystem/sumBaseStats": typeof _model_common__helpers_gameSystem_sumBaseStats;
"_model/common/_helpers/getCountryName": typeof _model_common__helpers_getCountryName;
"_model/common/_helpers/getDocStrict": typeof _model_common__helpers_getDocStrict;
"_model/common/_helpers/getEnvironment": typeof _model_common__helpers_getEnvironment;
"_model/common/_helpers/getRange": typeof _model_common__helpers_getRange;
"_model/common/_helpers/getStaticEnumConvexValidator": typeof _model_common__helpers_getStaticEnumConvexValidator;
Expand All @@ -356,7 +371,9 @@ declare const fullApi: ApiFromModules<{
"_model/common/tournamentPairingConfig": typeof _model_common_tournamentPairingConfig;
"_model/common/tournamentStatus": typeof _model_common_tournamentStatus;
"_model/common/types": typeof _model_common_types;
"_model/files/actions/convertImageToPdf": typeof _model_files_actions_convertImageToPdf;
"_model/files/index": typeof _model_files_index;
"_model/files/queries/getFileMetadata": typeof _model_files_queries_getFileMetadata;
"_model/files/queries/getFileUrl": typeof _model_files_queries_getFileUrl;
"_model/friendships/_helpers/deepenFriendship": typeof _model_friendships__helpers_deepenFriendship;
"_model/friendships/index": typeof _model_friendships_index;
Expand All @@ -366,10 +383,6 @@ declare const fullApi: ApiFromModules<{
"_model/friendships/queries/getFriendship": typeof _model_friendships_queries_getFriendship;
"_model/friendships/queries/getFriendshipsByUser": typeof _model_friendships_queries_getFriendshipsByUser;
"_model/friendships/table": typeof _model_friendships_table;
"_model/gameSystems/battlefront/flamesOfWarV4/_helpers/deepenListData": typeof _model_gameSystems_battlefront_flamesOfWarV4__helpers_deepenListData;
"_model/gameSystems/battlefront/flamesOfWarV4/_model/listData": typeof _model_gameSystems_battlefront_flamesOfWarV4__model_listData;
"_model/gameSystems/battlefront/flamesOfWarV4/index": typeof _model_gameSystems_battlefront_flamesOfWarV4_index;
"_model/gameSystems/index": typeof _model_gameSystems_index;
"_model/leagueOrganizers/_helpers/checkUserIsLeagueOrganizer": typeof _model_leagueOrganizers__helpers_checkUserIsLeagueOrganizer;
"_model/leagueOrganizers/_helpers/deepenLeagueOrganizer": typeof _model_leagueOrganizers__helpers_deepenLeagueOrganizer;
"_model/leagueOrganizers/index": typeof _model_leagueOrganizers_index;
Expand All @@ -395,11 +408,23 @@ declare const fullApi: ApiFromModules<{
"_model/leagues/queries/getLeagues": typeof _model_leagues_queries_getLeagues;
"_model/leagues/table": typeof _model_leagues_table;
"_model/leagues/types": typeof _model_leagues_types;
"_model/listComments/_helpers/deepenListComment": typeof _model_listComments__helpers_deepenListComment;
"_model/listComments/index": typeof _model_listComments_index;
"_model/listComments/mutations/createListComment": typeof _model_listComments_mutations_createListComment;
"_model/listComments/table": typeof _model_listComments_table;
"_model/listComments/types": typeof _model_listComments_types;
"_model/lists/_helpers/checkListSubmittedOnTime": typeof _model_lists__helpers_checkListSubmittedOnTime;
"_model/lists/_helpers/deepenList": typeof _model_lists__helpers_deepenList;
"_model/lists/_helpers/getAvailableActions": typeof _model_lists__helpers_getAvailableActions;
"_model/lists/index": typeof _model_lists_index;
"_model/lists/mutations/importListData": typeof _model_lists_mutations_importListData;
"_model/lists/mutations/createList": typeof _model_lists_mutations_createList;
"_model/lists/mutations/deleteList": typeof _model_lists_mutations_deleteList;
"_model/lists/mutations/updateList": typeof _model_lists_mutations_updateList;
"_model/lists/queries/getList": typeof _model_lists_queries_getList;
"_model/lists/queries/getListsByTournamentRegistration": typeof _model_lists_queries_getListsByTournamentRegistration;
"_model/lists/queries/getListsByUser": typeof _model_lists_queries_getListsByUser;
"_model/lists/table": typeof _model_lists_table;
"_model/lists/types": typeof _model_lists_types;
"_model/matchResultComments/_helpers/deepenMatchResultComment": typeof _model_matchResultComments__helpers_deepenMatchResultComment;
"_model/matchResultComments/index": typeof _model_matchResultComments_index;
"_model/matchResultComments/mutations/addMatchResultComment": typeof _model_matchResultComments_mutations_addMatchResultComment;
Expand Down Expand Up @@ -437,6 +462,8 @@ declare const fullApi: ApiFromModules<{
"_model/photos/mutations/createPhoto": typeof _model_photos_mutations_createPhoto;
"_model/photos/queries/getPhoto": typeof _model_photos_queries_getPhoto;
"_model/photos/table": typeof _model_photos_table;
"_model/tournamentCompetitors/_helpers/checkUserIsTeamCaptain": typeof _model_tournamentCompetitors__helpers_checkUserIsTeamCaptain;
"_model/tournamentCompetitors/_helpers/checkUsersAreTeammates": typeof _model_tournamentCompetitors__helpers_checkUsersAreTeammates;
"_model/tournamentCompetitors/_helpers/deepenTournamentCompetitor": typeof _model_tournamentCompetitors__helpers_deepenTournamentCompetitor;
"_model/tournamentCompetitors/_helpers/getAvailableActions": typeof _model_tournamentCompetitors__helpers_getAvailableActions;
"_model/tournamentCompetitors/_helpers/getDetails": typeof _model_tournamentCompetitors__helpers_getDetails;
Expand Down Expand Up @@ -606,6 +633,7 @@ declare const fullApi: ApiFromModules<{
http: typeof http;
leagueRankings: typeof leagueRankings;
leagues: typeof leagues;
listComments: typeof listComments;
lists: typeof lists;
matchResultComments: typeof matchResultComments;
matchResultLikes: typeof matchResultLikes;
Expand Down
25 changes: 12 additions & 13 deletions convex/_model/common/_helpers/filterWithSearchTerm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,17 @@ export const filterWithSearchTerm = <T extends object>(
return items;
}
const tokens = searchTerm.trim().toLowerCase().split(' ');
return items.filter((item) =>
fields.some((field) => {
const value = item[field];
return tokens.some((token) => {
if (typeof value === 'string') {
return value.toLowerCase().includes(token);
}
if (typeof value === 'number') {
return value.toString().includes(token);
}
return false;
});
}),
return items.filter((item) => fields.some((field) => {
const value = item[field];
return tokens.some((token) => {
if (typeof value === 'string') {
return value.toLowerCase().includes(token);
}
if (typeof value === 'number') {
return value.toString().includes(token);
}
return false;
});
}),
);
};
27 changes: 27 additions & 0 deletions convex/_model/common/_helpers/getDocStrict.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { GenericDatabaseReader } from 'convex/server';
import { ConvexError, GenericId } from 'convex/values';

import {
DataModel,
Doc,
TableNames,
} from '../../../_generated/dataModel';

/**
* Fetches a document by ID, throwing a `ConvexError` if it doesn't exist.
*
* @param ctx - A context object with a database reader.
* @param id - The ID of the document to fetch.
* @returns The document.
* @throws {ConvexError} If no document exists with the given ID.
*/
export const getDocStrict = async <T extends TableNames>(
ctx: { db: GenericDatabaseReader<DataModel> },
id: GenericId<T>,
): Promise<Doc<T>> => {
const doc = await ctx.db.get(id);
if (!doc) {
throw new ConvexError({ message: `Document not found: ${id}`, code: 'DOCUMENT_NOT_FOUND' });
}
return doc;
};
56 changes: 56 additions & 0 deletions convex/_model/files/actions/convertImageToPdf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { PDFDocument } from '@pdfme/pdf-lib';
import {
ConvexError,
Infer,
v,
} from 'convex/values';

import { Id } from '../../../_generated/dataModel';
import { ActionCtx } from '../../../_generated/server';
import { getErrorMessage } from '../../common/errors';

const IMAGE_MIME_TYPES = ['image/png', 'image/jpeg', 'image/jpg'] as const;
type ImageMimeType = (typeof IMAGE_MIME_TYPES)[number];

const isImageMimeType = (mimeType: string): mimeType is ImageMimeType => (IMAGE_MIME_TYPES as ReadonlyArray<string>).includes(mimeType);

export const convertImageToPdfArgs = v.object({
storageId: v.id('_storage'),
mimeType: v.string(),
});

export const convertImageToPdf = async (
ctx: ActionCtx,
args: Infer<typeof convertImageToPdfArgs>,
): Promise<Id<'_storage'>> => {
if (!isImageMimeType(args.mimeType)) {
throw new ConvexError({ message: `Unsupported MIME type: ${args.mimeType}. Expected one of: ${IMAGE_MIME_TYPES.join(', ')}` });
}

const blob = await ctx.storage.get(args.storageId);
if (!blob) {
throw new ConvexError(getErrorMessage('FILE_NOT_FOUND'));
}

const imageBytes = new Uint8Array(await blob.arrayBuffer());
const pdfDoc = await PDFDocument.create();

const image = args.mimeType === 'image/png' ? await pdfDoc.embedPng(imageBytes) : await pdfDoc.embedJpg(imageBytes);

const page = pdfDoc.addPage([image.width, image.height]);
page.drawImage(image, {
x: 0,
y: 0,
width: image.width,
height: image.height,
});

const pdfBytes = await pdfDoc.save();
const pdfBuffer = pdfBytes.buffer as ArrayBuffer;
const pdfBlob = new Blob([pdfBuffer], { type: 'application/pdf' });
const pdfStorageId = await ctx.storage.store(pdfBlob);

await ctx.storage.delete(args.storageId);

return pdfStorageId;
};
8 changes: 8 additions & 0 deletions convex/_model/files/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
export {
convertImageToPdf,
convertImageToPdfArgs,
} from './actions/convertImageToPdf';
export {
getFileMetadata,
getFileMetadataArgs,
} from './queries/getFileMetadata';
export {
getFileUrl,
getFileUrlArgs,
Expand Down
Loading