diff --git a/app/routes/to/$organization.$tournament.tsx b/app/routes/to/$organization.$tournament.tsx new file mode 100644 index 000000000..ebeb2f5a1 --- /dev/null +++ b/app/routes/to/$organization.$tournament.tsx @@ -0,0 +1,42 @@ +// TODO: 404 page that shows other tournaments by the organization + +import type { MetaFunction, LoaderFunction } from "remix"; +import { useLoaderData, json, Link } from "remix"; +import invariant from "tiny-invariant"; +import { makeTitle } from "~/utils"; +import { + findTournamentByNameForUrl, + FindTournamentByNameForUrlI, +} from "../../../services/tournament"; + +export const loader: LoaderFunction = ({ params }) => { + invariant( + typeof params.organization === "string", + "Expected params.organization to be string" + ); + invariant( + typeof params.tournament === "string", + "Expected params.tournament to be string" + ); + + return findTournamentByNameForUrl({ + organizationNameForUrl: params.organization, + tournamentNameForUrl: params.tournament, + }); +}; + +export const meta: MetaFunction = (props) => { + const data = props.data as FindTournamentByNameForUrlI; + + return { + title: makeTitle(data.name), + //description: data.description ?? undefined, + }; +}; + +// https://remix.run/guides/routing#index-routes +export default function Index() { + const data = useLoaderData(); + + return
hello
; +} diff --git a/app/utils.ts b/app/utils.ts index f4bec3f1d..86f32d37a 100644 --- a/app/utils.ts +++ b/app/utils.ts @@ -16,3 +16,5 @@ export const navItems = [ items: ["badges", "links"], }, ]; + +export const makeTitle = (endOfTitle: string) => `sendou.ink | ${endOfTitle}`; diff --git a/package-lock.json b/package-lock.json index 9960b58b9..2df5efadd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "name": "remix-app-template", "hasInstallScript": true, "dependencies": { + "@prisma/client": "^3.5.0", "@remix-run/express": "^1.0.4", "@remix-run/react": "^1.0.4", "classnames": "^2.3.1", @@ -16,13 +17,17 @@ "morgan": "^1.10.0", "react": "^17.0.2", "react-dom": "^17.0.2", - "remix": "^1.0.4" + "remix": "^1.0.4", + "tiny-invariant": "^1.2.0" }, "devDependencies": { "@remix-run/dev": "^1.0.4", "@types/react": "^17.0.24", "@types/react-dom": "^17.0.9", "concurrently": "^6.4.0", + "faker": "^5.5.3", + "prisma": "^3.5.0", + "ts-node": "^10.4.0", "typescript": "^4.1.2" }, "engines": { @@ -75,6 +80,27 @@ "node": ">=6.9.0" } }, + "node_modules/@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", + "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-consumer": "0.8.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@gar/promisify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.2.tgz", @@ -104,6 +130,38 @@ "node": ">=10" } }, + "node_modules/@prisma/client": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-3.5.0.tgz", + "integrity": "sha512-LuaaisknLe9CCfJ1Rtqe9b9knvPgEEcC77OMmWdo3fSanxl5oTDxcH3IIhpULQQlJfZvDcaEXuXNU4dsNF+q1w==", + "hasInstallScript": true, + "dependencies": { + "@prisma/engines-version": "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e" + }, + "engines": { + "node": ">=12.6" + }, + "peerDependencies": { + "prisma": "*" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + } + } + }, + "node_modules/@prisma/engines": { + "version": "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e.tgz", + "integrity": "sha512-MqZUrxuLlIbjB3wu8LrRJOKcvR4k3dunKoI4Q2bPfAwLQY0XlpsLZ3TRVW1c32ooVk939p6iGNkaCUo63Et36g==", + "devOptional": true, + "hasInstallScript": true + }, + "node_modules/@prisma/engines-version": { + "version": "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e.tgz", + "integrity": "sha512-X16YmBmj7Omso4ZbkNBe6gPYlNcnwZMUPtXsguCkn+KoMqm3DJD9M4X31gx0Gf13Q44dY3SKPJZUk44/XUj/WA==" + }, "node_modules/@remix-run/dev": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@remix-run/dev/-/dev-1.0.4.tgz", @@ -223,6 +281,30 @@ "node": ">=10" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, "node_modules/@types/acorn": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", @@ -424,6 +506,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -471,6 +562,12 @@ "node": ">= 8" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1030,6 +1127,12 @@ "node": ">=6.6.0" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -1705,6 +1808,12 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, + "node_modules/faker": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", + "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==", + "dev": true + }, "node_modules/fault": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", @@ -2486,6 +2595,12 @@ "node": ">=10" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/map-obj": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", @@ -3883,6 +3998,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/prisma": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-3.5.0.tgz", + "integrity": "sha512-WEYQ+H98O0yigG+lI0gfh4iyBChvnM6QTXPDtY9eFraLXAmyb6tf/T2mUdrUAU1AEvHLVzQA5A+RpONZlQozBg==", + "devOptional": true, + "hasInstallScript": true, + "dependencies": { + "@prisma/engines": "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e" + }, + "bin": { + "prisma": "build/index.js", + "prisma2": "build/index.js" + }, + "engines": { + "node": ">=12.6" + } + }, "node_modules/promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -4533,6 +4665,11 @@ "node": ">= 10" } }, + "node_modules/tiny-invariant": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", + "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -4601,6 +4738,56 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-node": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz", + "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "0.7.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -5102,6 +5289,15 @@ "node": ">=10" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/zwitch": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.2.tgz", @@ -5148,6 +5344,21 @@ "regenerator-runtime": "^0.13.4" } }, + "@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true + }, + "@cspotcode/source-map-support": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", + "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", + "dev": true, + "requires": { + "@cspotcode/source-map-consumer": "0.8.0" + } + }, "@gar/promisify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.2.tgz", @@ -5174,6 +5385,25 @@ "rimraf": "^3.0.2" } }, + "@prisma/client": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-3.5.0.tgz", + "integrity": "sha512-LuaaisknLe9CCfJ1Rtqe9b9knvPgEEcC77OMmWdo3fSanxl5oTDxcH3IIhpULQQlJfZvDcaEXuXNU4dsNF+q1w==", + "requires": { + "@prisma/engines-version": "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e" + } + }, + "@prisma/engines": { + "version": "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e.tgz", + "integrity": "sha512-MqZUrxuLlIbjB3wu8LrRJOKcvR4k3dunKoI4Q2bPfAwLQY0XlpsLZ3TRVW1c32ooVk939p6iGNkaCUo63Et36g==", + "devOptional": true + }, + "@prisma/engines-version": { + "version": "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e.tgz", + "integrity": "sha512-X16YmBmj7Omso4ZbkNBe6gPYlNcnwZMUPtXsguCkn+KoMqm3DJD9M4X31gx0Gf13Q44dY3SKPJZUk44/XUj/WA==" + }, "@remix-run/dev": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@remix-run/dev/-/dev-1.0.4.tgz", @@ -5269,6 +5499,30 @@ "defer-to-connect": "^2.0.0" } }, + "@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, "@types/acorn": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", @@ -5459,6 +5713,12 @@ "dev": true, "requires": {} }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -5494,6 +5754,12 @@ "picomatch": "^2.0.4" } }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -5922,6 +6188,12 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.1.0.tgz", "integrity": "sha512-Alvs19Vgq07eunykd3Xy2jF0/qSNv2u7KDbAek9H5liV1UMijbqFs5cycZvv5dVsvseT/U4H8/7/w8Koh35C4A==" }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -6390,6 +6662,12 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, + "faker": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", + "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==", + "dev": true + }, "fault": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", @@ -6974,6 +7252,12 @@ "yallist": "^4.0.0" } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "map-obj": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", @@ -7901,6 +8185,15 @@ "parse-ms": "^2.1.0" } }, + "prisma": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-3.5.0.tgz", + "integrity": "sha512-WEYQ+H98O0yigG+lI0gfh4iyBChvnM6QTXPDtY9eFraLXAmyb6tf/T2mUdrUAU1AEvHLVzQA5A+RpONZlQozBg==", + "devOptional": true, + "requires": { + "@prisma/engines": "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e" + } + }, "promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -8417,6 +8710,11 @@ "yallist": "^4.0.0" } }, + "tiny-invariant": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", + "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -8466,6 +8764,34 @@ "integrity": "sha512-FnHq5sTMxC0sk957wHDzRnemFnNBvt/gSY99HzK8F7UP5WAbvP70yX5bd7CjEQkN+TjdxwI7g7lJ6podqrG2/w==", "dev": true }, + "ts-node": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz", + "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "0.7.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -8830,6 +9156,12 @@ "decamelize": "^1.2.0" } }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, "zwitch": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.2.tgz", diff --git a/package.json b/package.json index c606cc000..a3b5bf715 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,18 @@ "dev:server": "cross-env NODE_ENV=development node server/index.js", "dev": "concurrently \"npm run dev:remix\" \"npm run dev:server\"", "postinstall": "remix setup node", - "start": "cross-env NODE_ENV=production node server/index.js" + "start": "cross-env NODE_ENV=production node server/index.js", + "migration:create": "npx prisma migrate dev --create-only", + "migration:apply:dev": "npx prisma migrate dev", + "migration:apply:prod": "npx prisma migrate deploy", + "seed": "npx prisma db seed", + "seed:reset": "npx prisma migrate reset --force", + "lint:styles": "stylelint \"**/*.css\"", + "cy:open": "npx cypress open", + "cy:run": "npx cypress run" }, "dependencies": { + "@prisma/client": "^3.5.0", "@remix-run/express": "^1.0.4", "@remix-run/react": "^1.0.4", "classnames": "^2.3.1", @@ -21,17 +30,24 @@ "morgan": "^1.10.0", "react": "^17.0.2", "react-dom": "^17.0.2", - "remix": "^1.0.4" + "remix": "^1.0.4", + "tiny-invariant": "^1.2.0" }, "devDependencies": { "@remix-run/dev": "^1.0.4", "@types/react": "^17.0.24", "@types/react-dom": "^17.0.9", "concurrently": "^6.4.0", + "faker": "^5.5.3", + "prisma": "^3.5.0", + "ts-node": "^10.4.0", "typescript": "^4.1.2" }, "engines": { "node": ">=14" }, - "sideEffects": false + "sideEffects": false, + "prisma": { + "seed": "node --experimental-specifier-resolution=node --loader ts-node/esm prisma/seed.ts" + } } diff --git a/services/tournament.ts b/services/tournament.ts new file mode 100644 index 000000000..54af4a21e --- /dev/null +++ b/services/tournament.ts @@ -0,0 +1,113 @@ +import { Prisma } from ".prisma/client"; +import { json } from "@remix-run/server-runtime"; +import prisma from "../prisma/client"; + +export type FindTournamentByNameForUrlI = Prisma.PromiseReturnType< + typeof findTournamentByNameForUrl +>; + +export async function findTournamentByNameForUrl({ + organizationNameForUrl, + tournamentNameForUrl, +}: { + organizationNameForUrl: string; + tournamentNameForUrl: string; +}) { + const tournaments = await prisma.tournament.findMany({ + where: { + nameForUrl: tournamentNameForUrl.toLowerCase(), + }, + select: { + id: true, + name: true, + description: true, + startTime: true, + checkInTime: true, + bannerBackground: true, + bannerTextHSLArgs: true, + organizer: { + select: { + name: true, + discordInvite: true, + twitter: true, + nameForUrl: true, + }, + }, + mapPool: { + select: { + mode: true, + name: true, + }, + }, + teams: { + select: { + checkedIn: true, + id: true, + name: true, + members: { + select: { + captain: true, + member: { + select: { + id: true, + discordAvatar: true, + discordName: true, + discordId: true, + discordDiscriminator: true, + }, + }, + }, + }, + }, + }, + }, + }); + + const result = tournaments.find( + (tournament) => + tournament.organizer.nameForUrl === organizationNameForUrl.toLowerCase() + ); + + if (!result) throw json("Not Found", { status: 404 }); + + result.organizer.twitter = twitterToUrl(result.organizer.twitter); + result.organizer.discordInvite = discordInviteToUrl( + result.organizer.discordInvite + ); + + return result; +} + +function twitterToUrl(twitter: string | null) { + if (!twitter) return twitter; + + return `https://twitter.com/${twitter}`; +} + +function discordInviteToUrl(discordInvite: string) { + return `https://discord.com/invite/${discordInvite}`; +} + +export function createTournamentTeam({ + userId, + name, + tournamentId, +}: { + userId: number; + name: string; + tournamentId: number; +}) { + return prisma.tournamentTeam.create({ + data: { + name: name.trim(), + tournamentId, + members: { + create: { + memberId: userId, + tournamentId, + captain: true, + }, + }, + }, + }); +}