diff --git a/drizzle/0020_lyrical_white_queen.sql b/drizzle/0020_lyrical_white_queen.sql new file mode 100644 index 00000000..56bfb2de --- /dev/null +++ b/drizzle/0020_lyrical_white_queen.sql @@ -0,0 +1,9 @@ +ALTER TABLE `feature` ADD `isNudist` boolean;--> statement-breakpoint +ALTER TABLE `feature` ADD `hasUnofficialName` boolean;--> statement-breakpoint +ALTER TABLE `feature` ADD `isOutOfTheMunicipality` boolean;--> statement-breakpoint +ALTER TABLE `feature` ADD `allowedAccess` enum('public','permissive','customers','permit','private','mixed');--> statement-breakpoint +ALTER TABLE `feature` ADD `duration` int;--> statement-breakpoint +ALTER TABLE `feature` ADD `distance` int;--> statement-breakpoint +ALTER TABLE `feature` ADD `slope` int;--> statement-breakpoint +ALTER TABLE `feature` ADD `allowedAccessNotes` text;--> statement-breakpoint +ALTER TABLE `feature_translation` ADD `allowedAccessNotes` text; \ No newline at end of file diff --git a/drizzle/meta/0020_snapshot.json b/drizzle/meta/0020_snapshot.json new file mode 100644 index 00000000..f9c1c502 --- /dev/null +++ b/drizzle/meta/0020_snapshot.json @@ -0,0 +1,1400 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "681fb2bb-2ee4-4b26-856f-b73c79269db3", + "prevId": "d45a3d2f-23a4-4e2c-a24e-5952705e34db", + "tables": { + "account": { + "name": "account", + "columns": { + "userId": { + "name": "userId", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "session_sessionToken": { + "name": "session_sessionToken", + "columns": [ + "sessionToken" + ] + } + }, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {} + }, + "feature": { + "name": "feature", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "amountOfPeople": { + "name": "amountOfPeople", + "type": "enum('none','few','some','many','crowded')", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "difficulty": { + "name": "difficulty", + "type": "enum('accessible','normal','smallEffort','hard','dangerous')", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "groundType": { + "name": "groundType", + "type": "enum('sand','pebbles','rocks','concrete','dirt','pavimented')", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hasBus": { + "name": "hasBus", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hasParking": { + "name": "hasParking", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parkingSpaces": { + "name": "parkingSpaces", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hasToilet": { + "name": "hasToilet", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hasRestaurant": { + "name": "hasRestaurant", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hasDrinkingWater": { + "name": "hasDrinkingWater", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hasShower": { + "name": "hasShower", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hasLifeguard": { + "name": "hasLifeguard", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hasLeisure": { + "name": "hasLeisure", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "isNudist": { + "name": "isNudist", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hasUnofficialName": { + "name": "hasUnofficialName", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "isOutOfTheMunicipality": { + "name": "isOutOfTheMunicipality", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "allowedAccess": { + "name": "allowedAccess", + "type": "enum('public','permissive','customers','permit','private','mixed')", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions": { + "name": "dimensions", + "type": "tinytext", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "price": { + "name": "price", + "type": "double", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "priceUnit": { + "name": "priceUnit", + "type": "enum('eur','eur/minute','eur/hour','eur/day')", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "isCovered": { + "name": "isCovered", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "duration": { + "name": "duration", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "distance": { + "name": "distance", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "slope": { + "name": "slope", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "timeToArrive": { + "name": "timeToArrive", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "placeToArriveFrom": { + "name": "placeToArriveFrom", + "type": "enum('townCenter','parking','beach','road')", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "isFreeWithLocalStamp": { + "name": "isFreeWithLocalStamp", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "difficultyNotes": { + "name": "difficultyNotes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "priceNotes": { + "name": "priceNotes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "allowedAccessNotes": { + "name": "allowedAccessNotes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "feature_id": { + "name": "feature_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + }, + "feature_translation": { + "name": "feature_translation", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "feature_id": { + "name": "feature_id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "locale": { + "name": "locale", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "difficultyNotes": { + "name": "difficultyNotes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "priceNotes": { + "name": "priceNotes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "allowedAccessNotes": { + "name": "allowedAccessNotes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "feature_translation_id": { + "name": "feature_translation_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + }, + "image": { + "name": "image", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "key": { + "name": "key", + "type": "varchar(1024)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "captureDate": { + "name": "captureDate", + "type": "date", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "alt": { + "name": "alt", + "type": "tinytext", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "blurDataURL": { + "name": "blurDataURL", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "image_id": { + "name": "image_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + }, + "placeListToPlace": { + "name": "placeListToPlace", + "columns": { + "placeListId": { + "name": "placeListId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "placeId": { + "name": "placeId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "addedAt": { + "name": "addedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "placeListToPlace_placeId_placeListId_pk": { + "name": "placeListToPlace_placeId_placeListId_pk", + "columns": [ + "placeId", + "placeListId" + ] + } + }, + "uniqueConstraints": {} + }, + "placeList": { + "name": "placeList", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "userId": { + "name": "userId", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "placeList_id": { + "name": "placeList_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + }, + "placeCategory": { + "name": "placeCategory", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "icon": { + "name": "icon", + "type": "tinytext", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "tinytext", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "hasVisitMission": { + "name": "hasVisitMission", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "name": { + "name": "name", + "type": "tinytext", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "namePlural": { + "name": "namePlural", + "type": "tinytext", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nameGender": { + "name": "nameGender", + "type": "enum('masculine','feminine')", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "placeCategory_id": { + "name": "placeCategory_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + }, + "placeCategory_translation": { + "name": "placeCategory_translation", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "placeCategory_id": { + "name": "placeCategory_id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "locale": { + "name": "locale", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "tinytext", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "namePlural": { + "name": "namePlural", + "type": "tinytext", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nameGender": { + "name": "nameGender", + "type": "enum('masculine','feminine')", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "placeCategory_translation_id": { + "name": "placeCategory_translation_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + }, + "place": { + "name": "place", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "mainImageId": { + "name": "mainImageId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "location": { + "name": "location", + "type": "POINT SRID 25831", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mainCategoryId": { + "name": "mainCategoryId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "featuresId": { + "name": "featuresId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "verificationRequirementsId": { + "name": "verificationRequirementsId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "tinytext", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "place_id": { + "name": "place_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + }, + "placeToPlaceCategory": { + "name": "placeToPlaceCategory", + "columns": { + "placeId": { + "name": "placeId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "categoryId": { + "name": "categoryId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "placeToPlaceCategory_categoryId_placeId_pk": { + "name": "placeToPlaceCategory_categoryId_placeId_pk", + "columns": [ + "categoryId", + "placeId" + ] + } + }, + "uniqueConstraints": {} + }, + "place_translation": { + "name": "place_translation", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "place_id": { + "name": "place_id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "locale": { + "name": "locale", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "tinytext", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "place_translation_id": { + "name": "place_translation_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + }, + "routeCategory": { + "name": "routeCategory", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "icon": { + "name": "icon", + "type": "tinytext", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "tinytext", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "hasVisitMission": { + "name": "hasVisitMission", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "name": { + "name": "name", + "type": "tinytext", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "namePlural": { + "name": "namePlural", + "type": "tinytext", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nameGender": { + "name": "nameGender", + "type": "enum('masculine','feminine')", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "routeCategory_id": { + "name": "routeCategory_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + }, + "routeCategory_translation": { + "name": "routeCategory_translation", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "routeCategory_id": { + "name": "routeCategory_id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "locale": { + "name": "locale", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "tinytext", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "namePlural": { + "name": "namePlural", + "type": "tinytext", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nameGender": { + "name": "nameGender", + "type": "enum('masculine','feminine')", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "routeCategory_translation_id": { + "name": "routeCategory_translation_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + }, + "route": { + "name": "route", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "mainImageId": { + "name": "mainImageId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "MULTILINESTRING SRID 25831", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mainCategoryId": { + "name": "mainCategoryId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "featuresId": { + "name": "featuresId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "verificationRequirementsId": { + "name": "verificationRequirementsId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "tinytext", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "route_id": { + "name": "route_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + }, + "routeToPlace": { + "name": "routeToPlace", + "columns": { + "routeId": { + "name": "routeId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "placeId": { + "name": "placeId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "routeToPlace_placeId_routeId_pk": { + "name": "routeToPlace_placeId_routeId_pk", + "columns": [ + "placeId", + "routeId" + ] + } + }, + "uniqueConstraints": {} + }, + "routeToRouteCategory": { + "name": "routeToRouteCategory", + "columns": { + "routeId": { + "name": "routeId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "categoryId": { + "name": "categoryId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "routeToRouteCategory_categoryId_routeId_pk": { + "name": "routeToRouteCategory_categoryId_routeId_pk", + "columns": [ + "categoryId", + "routeId" + ] + } + }, + "uniqueConstraints": {} + }, + "route_translation": { + "name": "route_translation", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "route_id": { + "name": "route_id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "locale": { + "name": "locale", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "tinytext", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "route_translation_id": { + "name": "route_translation_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hashedPassword": { + "name": "hashedPassword", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'user'" + }, + "visitedPlaceListId": { + "name": "visitedPlaceListId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "user_id": { + "name": "user_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + "email" + ] + } + } + }, + "verificationRequirement": { + "name": "verificationRequirement", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "isLocationRequired": { + "name": "isLocationRequired", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "maxLocationDistance": { + "name": "maxLocationDistance", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationRequirement_id": { + "name": "verificationRequirement_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + }, + "verification": { + "name": "verification", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "placeId": { + "name": "placeId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "validatedOn": { + "name": "validatedOn", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deviceLocation": { + "name": "deviceLocation", + "type": "POINT SRID 25831", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "deviceLocationAccuracy": { + "name": "deviceLocationAccuracy", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verification_id": { + "name": "verification_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + } + }, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index dae53a14..c8e6c44d 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -141,6 +141,13 @@ "when": 1708425618677, "tag": "0019_warm_zaladane", "breakpoints": true + }, + { + "idx": 20, + "version": "5", + "when": 1708619014761, + "tag": "0020_lyrical_white_queen", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/app/[locale]/(app)/explore/_components/features-block.tsx b/src/app/[locale]/(app)/explore/_components/features-block.tsx index cc0b60f4..7467acbd 100644 --- a/src/app/[locale]/(app)/explore/_components/features-block.tsx +++ b/src/app/[locale]/(app)/explore/_components/features-block.tsx @@ -12,6 +12,7 @@ import { getCompositeFeatureKey, getCompositeFeatureValues, getIconForFeature, + nestedT, useFeatureDisplay, } from '~/server/db/constants/features-display-data' @@ -26,15 +27,22 @@ export const FeaturesBlock: FC<{ features: Features; className?: string }> = ({ if (allValuesNull) return null + const thereIsJustOneGroup = + Object.values(allValuesNullInGroup).filter((v) => !v).length === 1 + return ( - + {featureDisplayGroups.map( (group) => !allValuesNullInGroup[group.key] && ( {group.featureDisplays.map((featureDisplay) => { @@ -137,7 +145,7 @@ export const FeaturesBlock: FC<{ features: Features; className?: string }> = ({ as="li" key={key} icon={featureDisplay.icon} - text={t(`values.composite.${key}`, values)} + text={nestedT(t, `values.composite.${key}`, values)} moreInfo={getMoreInfoContent(featureDisplay)} /> ) @@ -242,7 +250,7 @@ const FeatureList: FC< > = ({ title, children, variant }) => { return (
-

+

{title}

    = memo( @@ -23,6 +24,7 @@ export const OverrideMainMap: FC = memo( emphasizedMarkers, veryEmphasizedMarkers, veryEmphasizedLines, + reset, }) => { const { map, @@ -44,10 +46,14 @@ export const OverrideMainMap: FC = memo( } } - setEmphasizedMarkers(emphasizedMarkers) + if (reset) { + setEmphasizedMarkers(new Set()) + setVeryEmphasizedMarkers(new Set()) + setVeryEmphasizedLines(new Set()) + } + setEmphasizedMarkers(emphasizedMarkers) setVeryEmphasizedMarkers(veryEmphasizedMarkers) - setVeryEmphasizedLines(veryEmphasizedLines) } }, [map]) diff --git a/src/app/[locale]/(app)/explore/_components/place-list.tsx b/src/app/[locale]/(app)/explore/_components/place-list.tsx index a8d2d305..72a92bbc 100644 --- a/src/app/[locale]/(app)/explore/_components/place-list.tsx +++ b/src/app/[locale]/(app)/explore/_components/place-list.tsx @@ -44,7 +44,7 @@ export const PlaceList: FC<{ diff --git a/src/app/[locale]/(app)/explore/page.tsx b/src/app/[locale]/(app)/explore/page.tsx index fb9af2c4..347fafee 100644 --- a/src/app/[locale]/(app)/explore/page.tsx +++ b/src/app/[locale]/(app)/explore/page.tsx @@ -7,6 +7,7 @@ import { onlyTranslatableLocales, type LocaleRouteParams } from '~/i18n' import { getTrpc } from '~/server/get-server-thing' import { CategoriesGrid } from './_components/categories-grid' import { ListPlacesOfCategory } from './_components/list-places-of-category' +import { OverrideMainMap } from './_components/override-main-map' export async function generateMetadata({ params: { locale }, @@ -38,6 +39,8 @@ const ExplorePage: FC = async () => { return ( <> + +
    diff --git a/src/helpers/types.ts b/src/helpers/types.ts index 74fca687..2e34d0eb 100644 --- a/src/helpers/types.ts +++ b/src/helpers/types.ts @@ -31,6 +31,25 @@ export type IntlMessageKeys< > > +/** + * Get a union of all the keys of an object and its nested objects, joined by a dot. + */ +export type Paths = T extends object + ? { + [K in keyof T]: `${Exclude}${'' | `.${Paths}`}` + }[keyof T] + : never + +/** + * Get a union of all the keys of an object and its nested objects, joined by a dot. + * But only the ones leading to a leaf node. + */ +export type Leaves = T extends object + ? { + [K in keyof T]: `${Exclude}${Leaves extends never ? '' : `.${Leaves}`}` + }[keyof T] + : never + export type ControlledInputProps = { value?: T onChange?: (e: { target: { value: T } }) => void diff --git a/src/messages/ca.json b/src/messages/ca.json index 39cde332..77495e98 100644 --- a/src/messages/ca.json +++ b/src/messages/ca.json @@ -4,7 +4,9 @@ "titles": { "features": "Característiques", "services": "Serveis", - "notes": "Notes" + "notes": "Notes", + "other": "Altres", + "general": "General" }, "labels": { "amountOfPeople": "Quantitat de gent", @@ -19,6 +21,9 @@ "hasShower": "Té dutxes", "hasLifeguard": "Té socorrista", "hasLeisure": "Té serveis d'oci", + "hasUnofficialName": "Nom no oficial", + "isOutOfTheMunicipality": "Fora del municipi", + "allowedAccess": "Accés", "dimensions": "Dimensions", "price": "Preu", "priceUnit": "Unitat del preu", @@ -27,18 +32,26 @@ "placeToArriveFrom": "Lloc d'arribada", "isFreeWithLocalStamp": "És gratuït amb segell de Begur", "difficultyNotes": "Accessibilitat", - "priceNotes": "Preu" + "priceNotes": "Preu", + "allowedAccessNotes": "Accés", + "isNudist": "És nudista", + "duration": "Durada", + "distance": "Distància", + "slope": "Desnivell" }, "values": { "number": { - "parkingSpaces": "{value} places" + "parkingSpaces": "{value} places", + "slope": "{value} m" }, "text": {}, "composite": { - "price-priceUnit": "{price} {priceUnit}", - "timeToArrive-placeToArriveFrom": "A {hours, plural, =0 {} other {# h }}{minutes, plural, =0 {} other {# min}} {placeToArriveFrom, select, townCenter {del centre} parking {del parking} beach {de la platja} road {de la carretera} other {}}" + "price-priceUnit": "{price} {unit}", + "timeToArrive-placeToArriveFrom": "A {hours, plural, =0 {} other {# h }}{minutes, plural, =0 {} other {# min}} {placeToArriveFrom, select, townCenter {del centre} parking {del parking} beach {de la platja} road {de la carretera} other {}}", + "distance": "{distance} {unit}", + "duration": "{hours, plural, =0 {} other {# h }}{minutes, plural, =0 {} other {# min}}" }, "boolean": { @@ -74,6 +87,14 @@ "true": "Serveis d'oci", "false": "Sense serveis d'oci" }, + "hasUnofficialName": { + "true": "Nom no oficial", + "false": "Nom oficial" + }, + "isOutOfTheMunicipality": { + "true": "Fora del municipi", + "false": "Dins del municipi" + }, "hasDrinkingWater": { "true": "Aigua potable", "false": "Aigua no potable" @@ -81,6 +102,10 @@ "isCovered": { "true": "Cobert", "false": "Descobert" + }, + "isNudist": { + "true": "Nudista", + "false": "No nudista" } }, @@ -118,6 +143,14 @@ "concrete": "Ciment", "dirt": "Terra", "pavimented": "Pavimentat" + }, + "allowedAccess": { + "public": "Accés públic", + "permissive": "Accés permès, però no públic", + "customers": "Només per clients", + "permit": "Autorització necessària", + "private": "Accés privat", + "mixed": "Accés mixt" } } } diff --git a/src/messages/en.json b/src/messages/en.json index 5f74c382..ad0a2680 100644 --- a/src/messages/en.json +++ b/src/messages/en.json @@ -4,7 +4,9 @@ "titles": { "features": "Features", "services": "Services", - "notes": "Notes" + "notes": "Notes", + "other": "Other", + "general": "General" }, "labels": { "amountOfPeople": "Amount of people", @@ -19,6 +21,9 @@ "hasShower": "Has shower", "hasLifeguard": "Has lifeguard", "hasLeisure": "Has leisure services", + "hasUnofficialName": "Name is unofficial", + "isOutOfTheMunicipality": "Is out of the municipality", + "allowedAccess": "Allowed access", "dimensions": "Dimensions", "price": "Price", "priceUnit": "Price unit", @@ -27,18 +32,26 @@ "placeToArriveFrom": "Place to arrive from", "isFreeWithLocalStamp": "Is free with Begur's stamp", "difficultyNotes": "Accessibility", - "priceNotes": "Price" + "priceNotes": "Price", + "allowedAccessNotes": "Allowed access", + "isNudist": "Is nudist", + "duration": "Duration", + "distance": "Distance", + "slope": "Slope" }, "values": { "normal": { - "parkingSpaces": "{value} spaces" + "parkingSpaces": "{value} spaces", + "slope": "{value} m" }, "text": {}, "composite": { - "price-priceUnit": "{price} {priceUnit}", - "timeToArrive-placeToArriveFrom": "{hours, plural, =0 {} other {# h }}{minutes, plural, =0 {} other {# min}} from {placeToArriveFrom, select, townCenter {the town center} parking {the parking} beach {the beach} road {the road} other {}}" + "price-priceUnit": "{price} {unit}", + "timeToArrive-placeToArriveFrom": "{hours, plural, =0 {} other {# h }}{minutes, plural, =0 {} other {# min}} from {placeToArriveFrom, select, townCenter {the town center} parking {the parking} beach {the beach} road {the road} other {}}", + "distance": "{distance} {unit}", + "duration": "{hours, plural, =0 {} other {# h }}{minutes, plural, =0 {} other {# min}}" }, "boolean": { @@ -74,6 +87,15 @@ "true": "Leisure services", "false": "No leisure services" }, + + "hasUnofficialName": { + "true": "Unofficial name", + "false": "Official name" + }, + "isOutOfTheMunicipality": { + "true": "Out of the municipality", + "false": "In the municipality" + }, "hasDrinkingWater": { "true": "Drinking water", "false": "No drinking water" @@ -81,6 +103,10 @@ "isCovered": { "true": "Covered", "false": "Not covered" + }, + "isNudist": { + "true": "Nudist", + "false": "Not nudist" } }, @@ -118,6 +144,14 @@ "concrete": "Concrete", "dirt": "Dirt", "pavimented": "Pavimented" + }, + "allowedAccess": { + "public": "Public access", + "permissive": "Access allowed, but not public", + "customers": "Customers only", + "permit": "Permit required", + "private": "Private access", + "mixed": "Mixed access" } } } diff --git a/src/server/db/constants/features-display-data.ts b/src/server/db/constants/features-display-data.ts index 040bc179..d73868e0 100644 --- a/src/server/db/constants/features-display-data.ts +++ b/src/server/db/constants/features-display-data.ts @@ -4,14 +4,19 @@ import { IconAccessibleOff, IconAlertTriangle, IconAlertTriangleFilled, + IconArrowDownRight, IconBadgeWc, + IconBarrierBlock, IconBus, IconBusOff, IconCar, - IconCarGarage, + IconCertificate, IconClock, IconCoinEuro, IconCurrencyEuro, + IconDimensions, + IconDoorEnter, + IconDoorExit, IconDropletOff, IconDroplets, IconFountain, @@ -20,24 +25,31 @@ import { IconGrain, IconLifebuoy, IconLifebuoyOff, + IconMessageCheck, + IconMessageReport, IconMoodSad, IconMoodSmile, IconParking, IconParkingOff, IconRulerMeasure, + IconShirt, + IconShirtOff, IconTicket, IconToiletPaperOff, IconToolsKitchen2, IconToolsKitchen2Off, + IconUmbrella, IconWalk, } from '@tabler/icons-react' import { useMemo } from 'react' import { Join } from 'ts-toolbelt/out/String/Join' +import { Leaves } from '~/helpers/types' import { pick } from '~/helpers/utilities' import { FeaturesInsert, FeaturesSelect, PriceUnit, + allowedAccess, amountOfPeople, difficulty, groundType, @@ -45,19 +57,33 @@ import { priceUnit, } from '~/server/db/constants/features' -const typeFeatureDisplay = (feature: F) => feature +const typeFeatureDisplay = , K extends FeatureKey>( + feature: F +) => feature export const featureDisplayGroups = [ { - key: 'features', + key: 'general', featureDisplays: [ + typeFeatureDisplay({ + type: 'boolean', + key: 'isNudist', + icon: IconShirtOff, + icons: { + true: IconShirtOff, + false: IconShirt, + }, + } as const), typeFeatureDisplay({ type: 'composite', keys: ['price', 'priceUnit'], icon: IconCurrencyEuro, transformValues: ({ price, priceUnit }) => ({ price, - priceUnit: priceUnit ?? ('eur' satisfies PriceUnit), + unit: [ + `values.enum.priceUnit.${priceUnit ?? ('eur' satisfies PriceUnit)}`, + {}, + ], }), showIf: ({ price }) => price !== null, moreInfoFeatureKey: 'priceNotes', @@ -97,15 +123,17 @@ export const featureDisplayGroups = [ } as const), typeFeatureDisplay({ type: 'enum', - key: 'groundType', - icon: IconGrain, - options: groundType, - }), - typeFeatureDisplay({ - type: 'text', - showRaw: true, - key: 'dimensions', - icon: IconRulerMeasure, + key: 'allowedAccess', + icon: IconBarrierBlock, + icons: { + public: IconWalk, + private: IconBarrierBlock, + customers: IconBarrierBlock, + permit: IconCertificate, + permissive: IconWalk, + mixed: IconBarrierBlock, + }, + options: allowedAccess, } as const), typeFeatureDisplay({ type: 'composite', @@ -131,21 +159,73 @@ export const featureDisplayGroups = [ hidden: true, options: placeToArriveFrom, } as const), + typeFeatureDisplay({ + type: 'boolean', + key: 'isFreeWithLocalStamp', + icon: IconTicket, + } as const), + ], + }, + { + key: 'features', + featureDisplays: [ typeFeatureDisplay({ type: 'number', key: 'parkingSpaces', icon: IconCar, } as const), typeFeatureDisplay({ - type: 'boolean', - key: 'isCovered', - icon: IconCarGarage, - moreInfoTranslationKey: true, + type: 'number', + key: 'duration', + hidden: true, + icon: IconClock, + } as const), + typeFeatureDisplay({ + type: 'composite', + keys: ['duration'], + transformValues: ({ duration }) => ({ + hours: Math.floor((duration ?? 0) / 60), + minutes: (duration ?? 0) % 60, + }), + showIf: ({ duration }) => duration !== null, + icon: IconClock, } as const), + typeFeatureDisplay({ + type: 'number', + key: 'distance', + hidden: true, + icon: IconRulerMeasure, + } as const), + typeFeatureDisplay({ + type: 'composite', + keys: ['distance'], + transformValues: ({ distance }) => + distance && distance >= 1000 + ? { distance: distance / 1000, unit: 'km' } + : { distance: distance, unit: 'm' }, + icon: IconRulerMeasure, + } as const), + typeFeatureDisplay({ + type: 'number', + key: 'slope', + icon: IconArrowDownRight, + } as const), + typeFeatureDisplay({ + type: 'text', + showRaw: true, + key: 'dimensions', + icon: IconDimensions, + } as const), + typeFeatureDisplay({ + type: 'enum', + key: 'groundType', + icon: IconGrain, + options: groundType, + }), typeFeatureDisplay({ type: 'boolean', - key: 'isFreeWithLocalStamp', - icon: IconTicket, + key: 'isCovered', + icon: IconUmbrella, } as const), ], }, @@ -226,6 +306,29 @@ export const featureDisplayGroups = [ } as const), ], }, + { + key: 'other', + featureDisplays: [ + typeFeatureDisplay({ + type: 'boolean', + key: 'hasUnofficialName', + icon: IconMessageReport, + icons: { + true: IconMessageReport, + false: IconMessageCheck, + }, + } as const), + typeFeatureDisplay({ + type: 'boolean', + key: 'isOutOfTheMunicipality', + icon: IconDoorExit, + icons: { + true: IconDoorExit, + false: IconDoorEnter, + }, + } as const), + ], + }, { key: 'notes', featureDisplays: [ @@ -239,10 +342,15 @@ export const featureDisplayGroups = [ key: 'difficultyNotes', icon: IconAccessible, } as const), + typeFeatureDisplay({ + type: 'markdown', + key: 'allowedAccessNotes', + icon: IconBarrierBlock, + } as const), ], }, ] as const satisfies { - key: string + key: keyof IntlMessages['data']['features']['titles'] featureDisplays: AnyFeature[] }[] @@ -400,18 +508,50 @@ type CompositeFeature = { type: 'composite' keys: K[] icon: Icon - transformValues?: (values: { [Keys in K]: Features[Keys] }) => Record< - string, - string | number | boolean | Date | null | undefined - > + transformValues?: (values: { + [Keys in K]: Features[Keys] + }) => TranslationValues showIf?: (values: { [Keys in K]: Features[Keys] }) => boolean moreInfoFeatureKey?: FeaturesKeysOfType } -type AnyFeature = - | EnumFeature - | NumberFeature - | TextFeature - | BooleanFeature - | CompositeFeature - | MarkdownFeature +type NestedIntlKey = Leaves + +type TranslationValuesBasic = + | string + | number + | boolean + | Date + | null + | undefined + +type TranslationValues = Record< + string, + TranslationValuesBasic | [NestedIntlKey, TranslationValues] +> + +export function nestedT< + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends (...args: any[]) => string, + V extends TranslationValues, +>(t: T, key: Parameters[0], values: V) { + const tranlatedValues: Record = {} + + for (const [k, v] of Object.entries(values)) { + if (Array.isArray(v)) { + tranlatedValues[k] = nestedT(t, v[0], v[1]) + } else { + tranlatedValues[k] = v + } + } + + return t(key, tranlatedValues) +} + +type AnyFeature = + | (K extends FeaturesKeysOfType + ? MarkdownFeature | EnumFeature | TextFeature + : K extends FeaturesKeysOfType + ? BooleanFeature + : NumberFeature) + | CompositeFeature diff --git a/src/server/db/constants/features.ts b/src/server/db/constants/features.ts index 340e176c..7fea73da 100644 --- a/src/server/db/constants/features.ts +++ b/src/server/db/constants/features.ts @@ -32,6 +32,17 @@ export const groundType = [ ] as const export type GroundType = (typeof groundType)[number] +// Don't reorder these values, they are used to generate the database enum. +export const allowedAccess = [ + 'public', + 'permissive', + 'customers', + 'permit', + 'private', + 'mixed', +] as const +export type AllowedAccess = (typeof allowedAccess)[number] + // Don't reorder these values, they are used to generate the database enum. export const priceUnit = ['eur', 'eur/minute', 'eur/hour', 'eur/day'] as const export type PriceUnit = (typeof priceUnit)[number] diff --git a/src/server/db/schema/features.ts b/src/server/db/schema/features.ts index e31d24dc..ac2c5f6f 100644 --- a/src/server/db/schema/features.ts +++ b/src/server/db/schema/features.ts @@ -9,6 +9,7 @@ import { } from 'drizzle-orm/mysql-core' import { mysqlTableWithTranslations } from '../../helpers/translations/db-tables' import { + allowedAccess, amountOfPeople, difficulty, groundType, @@ -37,13 +38,17 @@ export const { hasShower: boolean('hasShower'), hasLifeguard: boolean('hasLifeguard'), hasLeisure: boolean('hasLeisure'), - + isNudist: boolean('isNudist'), + hasUnofficialName: boolean('hasUnofficialName'), + isOutOfTheMunicipality: boolean('isOutOfTheMunicipality'), + allowedAccess: mysqlEnum('allowedAccess', allowedAccess), dimensions: tinytext('dimensions'), - price: double('price'), priceUnit: mysqlEnum('priceUnit', priceUnit), - isCovered: boolean('isCovered'), + duration: int('duration'), // In minutes + distance: int('distance'), // In meters + slope: int('slope'), // In meters timeToArrive: int('timeToArrive'), // In minutes placeToArriveFrom: mysqlEnum('placeToArriveFrom', placeToArriveFrom), isFreeWithLocalStamp: boolean('isFreeWithLocalStamp'), @@ -51,6 +56,7 @@ export const { translatableColumns: { difficultyNotes: text('difficultyNotes'), // Markdown priceNotes: text('priceNotes'), // Markdown + allowedAccessNotes: text('allowedAccessNotes'), // Markdown }, })