diff --git a/CHANGELOG.md b/CHANGELOG.md index 391e711a3..5471366b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Migrated the style of `GfMarketDataDetailDialogModule` to `@angular/material` `15` (mdc) - Upgraded `ng-extract-i18n-merge` from version `2.1.2` to `2.5.0` +### Fixed + +- Fixed the `Upgrade Plan` button of the interstitial for the subscription + ## 1.231.0 - 2023-02-04 ### Added diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 87b9b9cc6..ad1620a23 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -244,6 +244,7 @@ export class AdminService { Analytics: { select: { activityCount: true, + country: true, updatedAt: true } }, @@ -277,6 +278,7 @@ export class AdminService { id, subscription, accountCount: _count.Account || 0, + country: Analytics.country, lastActivity: Analytics.updatedAt, transactionCount: _count.Order || 0 }; diff --git a/apps/api/src/app/auth/auth.service.ts b/apps/api/src/app/auth/auth.service.ts index 0be9f2877..2c2dc2fc7 100644 --- a/apps/api/src/app/auth/auth.service.ts +++ b/apps/api/src/app/auth/auth.service.ts @@ -61,8 +61,10 @@ export class AuthService { // Create new user if not found user = await this.userService.createUser({ - provider, - thirdPartyId: principalId + data: { + provider, + thirdPartyId: principalId + } }); } @@ -96,8 +98,10 @@ export class AuthService { // Create new user if not found user = await this.userService.createUser({ - provider, - thirdPartyId + data: { + provider, + thirdPartyId + } }); } diff --git a/apps/api/src/app/user/create-user.dto.ts b/apps/api/src/app/user/create-user.dto.ts new file mode 100644 index 000000000..7751f75fa --- /dev/null +++ b/apps/api/src/app/user/create-user.dto.ts @@ -0,0 +1,7 @@ +import { IsOptional, IsString } from 'class-validator'; + +export class CreateUserDto { + @IsString() + @IsOptional() + country?: string; +} diff --git a/apps/api/src/app/user/user.controller.ts b/apps/api/src/app/user/user.controller.ts index 6a1729b73..0eb37fb60 100644 --- a/apps/api/src/app/user/user.controller.ts +++ b/apps/api/src/app/user/user.controller.ts @@ -22,6 +22,7 @@ import { User as UserModel } from '@prisma/client'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { size } from 'lodash'; +import { CreateUserDto } from './create-user.dto'; import { UserItem } from './interfaces/user-item.interface'; import { UpdateUserSettingDto } from './update-user-setting.dto'; import { UserService } from './user.service'; @@ -65,7 +66,7 @@ export class UserController { } @Post() - public async signupUser(): Promise { + public async signupUser(@Body() data: CreateUserDto): Promise { const isUserSignupEnabled = await this.propertyService.isUserSignupEnabled(); @@ -79,7 +80,8 @@ export class UserController { const hasAdmin = await this.userService.hasAdmin(); const { accessToken, id, role } = await this.userService.createUser({ - role: hasAdmin ? 'USER' : 'ADMIN' + country: data.country, + data: { role: hasAdmin ? 'USER' : 'ADMIN' } }); return { diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 176de7004..b45d1849d 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -18,6 +18,8 @@ import { Injectable } from '@nestjs/common'; import { Prisma, Role, User } from '@prisma/client'; import { sortBy } from 'lodash'; +import { CreateUserDto } from './create-user.dto'; + const crypto = require('crypto'); @Injectable() @@ -231,7 +233,10 @@ export class UserService { return hash.digest('hex'); } - public async createUser(data: Prisma.UserCreateInput): Promise { + public async createUser({ + country, + data + }: CreateUserDto & { data: Prisma.UserCreateInput }): Promise { if (!data?.provider) { data.provider = 'ANONYMOUS'; } @@ -256,6 +261,15 @@ export class UserService { } }); + if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { + await this.prismaService.analytics.create({ + data: { + country, + User: { connect: { id: user.id } } + } + }); + } + if (data.provider === 'ANONYMOUS') { const accessToken = this.createAccessToken( user.id, diff --git a/apps/client/src/app/components/admin-users/admin-users.component.ts b/apps/client/src/app/components/admin-users/admin-users.component.ts index 7f2a34d2b..11ef91b8d 100644 --- a/apps/client/src/app/components/admin-users/admin-users.component.ts +++ b/apps/client/src/app/components/admin-users/admin-users.component.ts @@ -1,7 +1,8 @@ import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; -import { AdminData, User } from '@ghostfolio/common/interfaces'; +import { AdminData, InfoItem, User } from '@ghostfolio/common/interfaces'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { differenceInSeconds, formatDistanceToNowStrict, @@ -16,6 +17,8 @@ import { takeUntil } from 'rxjs/operators'; templateUrl: './admin-users.html' }) export class AdminUsersComponent implements OnDestroy, OnInit { + public hasPermissionForSubscription: boolean; + public info: InfoItem; public user: User; public users: AdminData['users']; @@ -26,6 +29,13 @@ export class AdminUsersComponent implements OnDestroy, OnInit { private dataService: DataService, private userService: UserService ) { + this.info = this.dataService.fetchInfo(); + + this.hasPermissionForSubscription = hasPermission( + this.info?.globalPermissions, + permissions.enableSubscription + ); + this.userService.stateChanged .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((state) => { diff --git a/apps/client/src/app/components/admin-users/admin-users.html b/apps/client/src/app/components/admin-users/admin-users.html index 53bb75a6f..15983f2f7 100644 --- a/apps/client/src/app/components/admin-users/admin-users.html +++ b/apps/client/src/app/components/admin-users/admin-users.html @@ -7,7 +7,13 @@ # User - + + Country + + Registration @@ -16,7 +22,10 @@ Activities - + Engagement per Day Last Request @@ -41,7 +50,13 @@ > - + + {{ userItem.country }} + + {{ formatDistanceToNow(userItem.createdAt) }} @@ -58,7 +73,10 @@ [value]="userItem.transactionCount" > - + ) {} - public onCancel() { + public closeDialog() { this.dialogRef.close({}); } } diff --git a/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html b/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html index a45bb42a8..22ba74715 100644 --- a/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html +++ b/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html @@ -34,8 +34,13 @@

Refine your personal investment strategy now.

- - + + Upgrade Plan diff --git a/apps/client/src/app/pages/register/register-page.component.ts b/apps/client/src/app/pages/register/register-page.component.ts index b9cdfcc71..9752c6012 100644 --- a/apps/client/src/app/pages/register/register-page.component.ts +++ b/apps/client/src/app/pages/register/register-page.component.ts @@ -4,6 +4,7 @@ import { Router } from '@angular/router'; import { DataService } from '@ghostfolio/client/services/data.service'; import { InternetIdentityService } from '@ghostfolio/client/services/internet-identity.service'; import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; +import { UserService } from '@ghostfolio/client/services/user/user.service'; import { InfoItem, LineChartItem } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { Role } from '@prisma/client'; @@ -37,7 +38,8 @@ export class RegisterPageComponent implements OnDestroy, OnInit { private dialog: MatDialog, private internetIdentityService: InternetIdentityService, private router: Router, - private tokenStorageService: TokenStorageService + private tokenStorageService: TokenStorageService, + private userService: UserService ) { this.info = this.dataService.fetchInfo(); @@ -61,7 +63,7 @@ export class RegisterPageComponent implements OnDestroy, OnInit { public async createAccount() { this.dataService - .postUser() + .postUser({ country: this.userService.getCountry() }) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(({ accessToken, authToken, role }) => { this.openShowAccessTokenDialog(accessToken, authToken, role); diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index d4071caeb..d34d54ded 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -405,8 +405,8 @@ export class DataService { return this.http.post(`/api/v1/order`, aOrder); } - public postUser() { - return this.http.post(`/api/v1/user`, {}); + public postUser({ country }: { country: string }) { + return this.http.post(`/api/v1/user`, { country }); } public putAccount(aAccount: UpdateAccountDto) { diff --git a/apps/client/src/app/services/user/user.service.ts b/apps/client/src/app/services/user/user.service.ts index 7f903df3a..fbbab5a1a 100644 --- a/apps/client/src/app/services/user/user.service.ts +++ b/apps/client/src/app/services/user/user.service.ts @@ -6,6 +6,7 @@ import { SubscriptionInterstitialDialogParams } from '@ghostfolio/client/compone import { SubscriptionInterstitialDialog } from '@ghostfolio/client/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component'; import { User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { timezoneCitiesToCountries } from '@ghostfolio/common/timezone-cities-to-countries'; import { DeviceDetectorService } from 'ngx-device-detector'; import { Subject, of } from 'rxjs'; import { throwError } from 'rxjs'; @@ -45,6 +46,20 @@ export class UserService extends ObservableStore { } } + public getCountry() { + let country: string; + + if (Intl) { + const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; + const timeZoneArray = timeZone.split('/'); + const city = timeZoneArray[timeZoneArray.length - 1]; + + country = timezoneCitiesToCountries[city]; + } + + return country; + } + public remove() { this.setState({ user: null }, UserStoreActions.RemoveUser); } diff --git a/libs/common/src/lib/interfaces/admin-data.interface.ts b/libs/common/src/lib/interfaces/admin-data.interface.ts index c51b2c8d7..b66676346 100644 --- a/libs/common/src/lib/interfaces/admin-data.interface.ts +++ b/libs/common/src/lib/interfaces/admin-data.interface.ts @@ -5,6 +5,7 @@ export interface AdminData { userCount: number; users: { accountCount: number; + country: string; createdAt: Date; engagement: number; id: string; diff --git a/libs/common/src/lib/timezone-cities-to-countries.ts b/libs/common/src/lib/timezone-cities-to-countries.ts new file mode 100644 index 000000000..6f6973179 --- /dev/null +++ b/libs/common/src/lib/timezone-cities-to-countries.ts @@ -0,0 +1,426 @@ +export const timezoneCitiesToCountries = { + Abidjan: 'CI', + Accra: 'GH', + Adak: 'US', + Addis_Ababa: 'ET', + Adelaide: 'AU', + Aden: 'YE', + Algiers: 'DZ', + Almaty: 'KZ', + Amman: 'JO', + Amsterdam: 'NL', + Anadyr: 'RU', + Anchorage: 'US', + Andorra: 'AD', + Anguilla: 'AI', + Antananarivo: 'MG', + Antigua: 'AG', + Apia: 'WS', + Aqtau: 'KZ', + Aqtobe: 'KZ', + Araguaina: 'BR', + Aruba: 'AW', + Ashgabat: 'TM', + Asmara: 'ER', + Astrakhan: 'RU', + Asuncion: 'PY', + Athens: 'GR', + Atikokan: 'CA', + Atyrau: 'KZ', + Auckland: 'NZ', + Azores: 'PT', + Baghdad: 'IQ', + Bahia: 'BR', + Bahia_Banderas: 'MX', + Bahrain: 'BH', + Baku: 'AZ', + Bamako: 'ML', + Bangkok: 'TH', + Bangui: 'CF', + Banjul: 'GM', + Barbados: 'BB', + Barnaul: 'RU', + Beirut: 'LB', + Belem: 'BR', + Belgrade: 'RS', + Belize: 'BZ', + Berlin: 'DE', + Bermuda: 'BM', + Beulah: 'US', + Bishkek: 'KG', + Bissau: 'GW', + 'Blanc-Sablon': 'CA', + Blantyre: 'MW', + Boa_Vista: 'BR', + Bogota: 'CO', + Boise: 'US', + Bougainville: 'PG', + Bratislava: 'SK', + Brazzaville: 'CG', + Brisbane: 'AU', + Broken_Hill: 'AU', + Brunei: 'BN', + Brussels: 'BE', + Bucharest: 'RO', + Budapest: 'HU', + Buenos_Aires: 'AR', + Bujumbura: 'BI', + Busingen: 'DE', + Cairo: 'EG', + Cambridge_Bay: 'CA', + Campo_Grande: 'BR', + Canary: 'ES', + Cancun: 'MX', + Cape_Verde: 'CV', + Caracas: 'VE', + Casablanca: 'MA', + Casey: 'AQ', + Catamarca: 'AR', + Cayenne: 'GF', + Cayman: 'KY', + Center: 'US', + Ceuta: 'ES', + Chagos: 'IO', + Chatham: 'NZ', + Chicago: 'US', + Chihuahua: 'MX', + Chisinau: 'MD', + Chita: 'RU', + Choibalsan: 'MN', + Christmas: 'CX', + Chuuk: 'FM', + Cocos: 'CC', + Colombo: 'LK', + Comoro: 'KM', + Conakry: 'GN', + Copenhagen: 'DK', + Cordoba: 'AR', + Costa_Rica: 'CR', + Creston: 'CA', + Cuiaba: 'BR', + Curacao: 'CW', + Dakar: 'SN', + Damascus: 'SY', + Danmarkshavn: 'GL', + Dar_es_Salaam: 'TZ', + Darwin: 'AU', + Davis: 'AQ', + Dawson: 'CA', + Dawson_Creek: 'CA', + Denver: 'US', + Detroit: 'US', + Dhaka: 'BD', + Dili: 'TL', + Djibouti: 'DJ', + Dominica: 'DM', + Douala: 'CM', + Dubai: 'AE', + Dublin: 'IE', + DumontDUrville: 'AQ', + Dushanbe: 'TJ', + Easter: 'CL', + Edmonton: 'CA', + Efate: 'VU', + Eirunepe: 'BR', + El_Aaiun: 'EH', + El_Salvador: 'SV', + Eucla: 'AU', + Fakaofo: 'TK', + Famagusta: 'CY', + Faroe: 'FO', + Fiji: 'FJ', + Fort_Nelson: 'CA', + Fortaleza: 'BR', + Freetown: 'SL', + Funafuti: 'TV', + Gaborone: 'BW', + Galapagos: 'EC', + Gambier: 'PF', + Gaza: 'PS', + Gibraltar: 'GI', + Glace_Bay: 'CA', + Goose_Bay: 'CA', + Grand_Turk: 'TC', + Grenada: 'GD', + Guadalcanal: 'SB', + Guadeloupe: 'GP', + Guam: 'GU', + Guatemala: 'GT', + Guayaquil: 'EC', + Guernsey: 'GG', + Guyana: 'GY', + Halifax: 'CA', + Harare: 'ZW', + Havana: 'CU', + Hebron: 'PS', + Helsinki: 'FI', + Hermosillo: 'MX', + Ho_Chi_Minh: 'VN', + Hobart: 'AU', + Hong_Kong: 'HK', + Honolulu: 'US', + Hovd: 'MN', + Indianapolis: 'US', + Inuvik: 'CA', + Iqaluit: 'CA', + Irkutsk: 'RU', + Isle_of_Man: 'IM', + Istanbul: 'TR', + Jakarta: 'ID', + Jamaica: 'JM', + Jayapura: 'ID', + Jersey: 'JE', + Jerusalem: 'IL', + Johannesburg: 'ZA', + Juba: 'SS', + Jujuy: 'AR', + Juneau: 'US', + Kabul: 'AF', + Kaliningrad: 'RU', + Kamchatka: 'RU', + Kampala: 'UG', + Kanton: 'KI', + Karachi: 'PK', + Kathmandu: 'NP', + Kerguelen: 'TF', + Khandyga: 'RU', + Khartoum: 'SD', + Kiev: 'UA', + Kigali: 'RW', + Kinshasa: 'CD', + Kiritimati: 'KI', + Kirov: 'RU', + Knox: 'US', + Kolkata: 'IN', + Kosrae: 'FM', + Kralendijk: 'NL', + Krasnoyarsk: 'RU', + Kuala_Lumpur: 'MY', + Kuching: 'MY', + Kuwait: 'KW', + Kwajalein: 'MH', + La_Paz: 'BO', + La_Rioja: 'AR', + Lagos: 'NG', + Libreville: 'GA', + Lima: 'PE', + Lindeman: 'AU', + Lisbon: 'PT', + Ljubljana: 'SI', + Lome: 'TG', + London: 'GB', + Longyearbyen: 'SJ', + Lord_Howe: 'AU', + Los_Angeles: 'US', + Louisville: 'US', + Lower_Princes: 'SX', + Luanda: 'AO', + Lubumbashi: 'CD', + Lusaka: 'ZM', + Luxembourg: 'LU', + Macau: 'MO', + Maceio: 'BR', + Macquarie: 'AU', + Madeira: 'PT', + Madrid: 'ES', + Magadan: 'RU', + Mahe: 'SC', + Majuro: 'MH', + Makassar: 'ID', + Malabo: 'GQ', + Maldives: 'MV', + Malta: 'MT', + Managua: 'NI', + Manaus: 'BR', + Manila: 'PH', + Maputo: 'MZ', + Marengo: 'US', + Mariehamn: 'AX', + Marigot: 'MF', + Marquesas: 'PF', + Martinique: 'MQ', + Maseru: 'LS', + Matamoros: 'MX', + Mauritius: 'MU', + Mawson: 'AQ', + Mayotte: 'YT', + Mazatlan: 'MX', + Mbabane: 'SZ', + McMurdo: 'AQ', + Melbourne: 'AU', + Mendoza: 'AR', + Menominee: 'US', + Merida: 'MX', + Metlakatla: 'US', + Mexico_City: 'MX', + Midway: 'UM', + Minsk: 'BY', + Miquelon: 'PM', + Mogadishu: 'SO', + Monaco: 'MC', + Moncton: 'CA', + Monrovia: 'LR', + Monterrey: 'MX', + Montevideo: 'UY', + Monticello: 'US', + Montserrat: 'MS', + Moscow: 'RU', + Muscat: 'OM', + Nairobi: 'KE', + Nassau: 'BS', + Nauru: 'NR', + Ndjamena: 'TD', + New_Salem: 'US', + New_York: 'US', + Niamey: 'NE', + Nicosia: 'CY', + Nipigon: 'CA', + Niue: 'NU', + Nome: 'US', + Norfolk: 'NF', + Noronha: 'BR', + Nouakchott: 'MR', + Noumea: 'NC', + Novokuznetsk: 'RU', + Novosibirsk: 'RU', + Nuuk: 'GL', + Ojinaga: 'MX', + Omsk: 'RU', + Oral: 'KZ', + Oslo: 'NO', + Ouagadougou: 'BF', + Pago_Pago: 'AS', + Palau: 'PW', + Palmer: 'AQ', + Panama: 'PA', + Pangnirtung: 'CA', + Paramaribo: 'SR', + Paris: 'FR', + Perth: 'AU', + Petersburg: 'US', + Phnom_Penh: 'KH', + Phoenix: 'US', + Pitcairn: 'PN', + Podgorica: 'ME', + Pohnpei: 'FM', + Pontianak: 'ID', + 'Port-au-Prince': 'HT', + Port_Moresby: 'PG', + Port_of_Spain: 'TT', + 'Porto-Novo': 'BJ', + Porto_Velho: 'BR', + Prague: 'CZ', + Puerto_Rico: 'PR', + Punta_Arenas: 'CL', + Pyongyang: 'KP', + Qatar: 'QA', + Qostanay: 'KZ', + Qyzylorda: 'KZ', + Rainy_River: 'CA', + Rankin_Inlet: 'CA', + Rarotonga: 'CK', + Recife: 'BR', + Regina: 'CA', + Resolute: 'CA', + Reunion: 'RE', + Reykjavik: 'IS', + Riga: 'LV', + Rio_Branco: 'BR', + Rio_Gallegos: 'AR', + Riyadh: 'SA', + Rome: 'IT', + Rothera: 'AQ', + Saipan: 'MP', + Sakhalin: 'RU', + Salta: 'AR', + Samara: 'RU', + Samarkand: 'UZ', + San_Juan: 'AR', + San_Luis: 'AR', + San_Marino: 'SM', + Santarem: 'BR', + Santiago: 'CL', + Santo_Domingo: 'DO', + Sao_Paulo: 'BR', + Sao_Tome: 'ST', + Sarajevo: 'BA', + Saratov: 'RU', + Scoresbysund: 'GL', + Seoul: 'KR', + Shanghai: 'CN', + Simferopol: 'RU', + Singapore: 'SG', + Sitka: 'US', + Skopje: 'MK', + Sofia: 'BG', + South_Georgia: 'GS', + Srednekolymsk: 'RU', + St_Barthelemy: 'BL', + St_Helena: 'SH', + St_Johns: 'CA', + St_Kitts: 'KN', + St_Lucia: 'LC', + St_Thomas: 'VI', + St_Vincent: 'VC', + Stanley: 'FK', + Stockholm: 'SE', + Swift_Current: 'CA', + Sydney: 'AU', + Syowa: 'AQ', + Tahiti: 'PF', + Taipei: 'TW', + Tallinn: 'EE', + Tarawa: 'KI', + Tashkent: 'UZ', + Tbilisi: 'GE', + Tegucigalpa: 'HN', + Tehran: 'IR', + Tell_City: 'US', + Thimphu: 'BT', + Thule: 'GL', + Thunder_Bay: 'CA', + Tijuana: 'MX', + Tirane: 'AL', + Tokyo: 'JP', + Tomsk: 'RU', + Tongatapu: 'TO', + Toronto: 'CA', + Tortola: 'VI (UK)', + Tripoli: 'LY', + Troll: 'AQ', + Tucuman: 'AR', + Tunis: 'TN', + Ulaanbaatar: 'MN', + Ulyanovsk: 'RU', + Urumqi: 'CN', + Ushuaia: 'AR', + 'Ust-Nera': 'RU', + Uzhgorod: 'UA', + Vaduz: 'LI', + Vancouver: 'CA', + Vatican: 'VA', + Vevay: 'US', + Vienna: 'AT', + Vientiane: 'LA', + Vilnius: 'LT', + Vincennes: 'US', + Vladivostok: 'RU', + Volgograd: 'RU', + Vostok: 'AQ', + Wake: 'UM', + Wallis: 'WF', + Warsaw: 'PL', + Whitehorse: 'CA', + Winamac: 'US', + Windhoek: 'NA', + Winnipeg: 'CA', + Yakutat: 'US', + Yakutsk: 'RU', + Yangon: 'MM', + Yekaterinburg: 'RU', + Yellowknife: 'CA', + Yerevan: 'AM', + Zagreb: 'HR', + Zaporozhye: 'UA', + Zurich: 'CH' +}; diff --git a/prisma/migrations/20230205173009_added_country_to_analytics/migration.sql b/prisma/migrations/20230205173009_added_country_to_analytics/migration.sql new file mode 100644 index 000000000..0312128b3 --- /dev/null +++ b/prisma/migrations/20230205173009_added_country_to_analytics/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Analytics" ADD COLUMN "country" TEXT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 3c252395e..ae5f29dee 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -41,6 +41,7 @@ model Account { model Analytics { activityCount Int @default(0) + country String? updatedAt DateTime @updatedAt userId String @id User User @relation(fields: [userId], references: [id])