diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/CommunitiesComponent.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/CommunitiesComponent.kt index 3491bae00..040ef827c 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/CommunitiesComponent.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/CommunitiesComponent.kt @@ -40,6 +40,9 @@ class CommunitiesComponent( fieldName = "Körök leírása", description = "Ez jelenik meg a körök lapon", type = SettingType.LONG_TEXT_MARKDOWN) + final var seachEnabled by BooleanSettingRef(defaultValue = false, fieldName = "Keresés engedélyezése", + description = "Engedélyezi a körök közötti keresést") + /// ------------------------------------------------------------------------------------------------------------------- val resortGroup by SettingGroup(fieldName = "Reszortok") @@ -57,6 +60,20 @@ class CommunitiesComponent( fieldName = "Körök leírása", description = "Ez jelenik meg a körök lapon", type = SettingType.LONG_TEXT_MARKDOWN) + final var seachEnabledResort by BooleanSettingRef(defaultValue = false, fieldName = "Keresés engedélyezése", + description = "Engedélyezi a reszortok közötti keresést") + + ///------------------------------------------------------------------------------------------------------------------- + + val tinderGroup by SettingGroup(fieldName = "Tinder") + + final var tinderEnabled by BooleanSettingRef(defaultValue = false, fieldName = "Tinder engedélyezése", + description = "Engedélyezi a körök és userek közötti tinder szerű párosítást") + + final var minRoleTinder by MinRoleSettingRef(defaultValue = setOf(), fieldName = "Jogosultságok", + description = "Melyik roleokkal nyitható meg az oldal") + + override fun getAdditionalMenus(role: RoleType): List { val result = mutableListOf() if (minRoleResort.isAvailableForRole(role) || role.isAdmin) { @@ -66,6 +83,13 @@ class CommunitiesComponent( visible = false, subMenu = false, external = false )) } + if (tinderEnabled && (minRoleTinder.isAvailableForRole(role) || role.isAdmin)) { + result.add(MenuSettingItem( + this.javaClass.simpleName + "@tinder", + "Tinder", "/tinder", 0, + visible = false, subMenu = false, external = false + )) + } return result } diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/CommunitiesController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/CommunitiesController.kt index fc910a213..4296fc615 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/CommunitiesController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/CommunitiesController.kt @@ -28,6 +28,7 @@ import kotlin.jvm.optionals.getOrNull @ConditionalOnBean(CommunitiesComponent::class) class CommunitiesController( val tinderService: TinderService, + val organizationService: OrganizationService, repo: CommunityRepository, importService: ImportService, adminMenuService: AdminMenuService, @@ -99,7 +100,7 @@ class CommunitiesController( wide = false ) - private val reader = objectMapper.readerFor(object: TypeReference>(){}) + private val reader = objectMapper.readerFor(object: TypeReference>(){}) @GetMapping("/tinder/show/{id}") fun showTinderAnswers(@PathVariable id: Int, model: Model, auth: Authentication): String { @@ -192,7 +193,7 @@ class CommunitiesController( private fun getTinderEditComponent(communityId: Int): DashboardComponent { val answerEntity = transactionManager.transaction(readOnly = true) { tinderService.getAnswerForCommunity(communityId).getOrNull() } .let { - reader.readValue>(it?.answers) + reader.readValue>(it?.answers) } ?: return DashboardFormCard( id = 3, @@ -210,11 +211,11 @@ class CommunitiesController( val formElements = mutableListOf() for (question in questions) { formElements.add(FormElement( - fieldName = "question_${question.id}", + fieldName = question.question, label = question.question, type = FormElementType.SELECT, values = ","+question.answerOptions, - defaultValue = answerEntity[question.id] ?: "" + defaultValue = answerEntity[question.question] ?: "" )) } @@ -259,7 +260,7 @@ class CommunitiesController( private fun getTinderShowComponent(communityId: Int): DashboardComponent { val answerEntity = transactionManager.transaction(readOnly = true) { tinderService.getAnswerForCommunity(communityId).getOrNull() } .let { - reader.readValue>(it?.answers) + reader.readValue>(it?.answers) } ?: return DashboardFormCard( id = 3, @@ -277,10 +278,10 @@ class CommunitiesController( for (i in 0.. { return tinderService.getAllQuestions().map{ TinderQuestionDto(it) } } - @PostMapping("/tinder/question") + @GetMapping("/tinder/question/answers") + fun getAnswers(auth: Authentication?): TinderAnswerStatus { + val user = auth?.getUserOrNull() ?: return TinderAnswerStatus() + val answer: Map = tinderService.getAnswerMapForUser(user.id) + .getOrElse{return TinderAnswerStatus() } + return TinderAnswerStatus(answered = true, answer = answer) + } + + @PostMapping("/tinder/question/answers") fun submitAnswers( - auth: Authentication?, - @RequestBody answers: TinderAnswerDto - ): ResponseEntity { - val user = auth?.getUserEntityFromDatabaseOrNull(userService) ?: return ResponseEntity.status(401).build() - tinderService.submitAnswers(false, user, answers) - return ResponseEntity.ok().build() + @RequestBody data: Map, + auth: Authentication? + ): TinderAnswerResponseStatus { + val user = auth?.getUserOrNull() + ?: return TinderAnswerResponseStatus.NO_PERMISSION + return tinderService.submitAnswers(false, user, data) } - @PutMapping("/tinder/question") + @PutMapping("/tinder/question/answers") fun updateAnswers( - auth: Authentication?, - @RequestBody answers: TinderAnswerDto - ): ResponseEntity { - val user = auth?.getUserEntityFromDatabaseOrNull(userService) ?: return ResponseEntity.status(401).build() - tinderService.submitAnswers(true, user, answers) - return ResponseEntity.ok().build() + @RequestBody answers: Map, + auth: Authentication? + ): TinderAnswerResponseStatus { + val user = auth?.getUserOrNull() + ?: return TinderAnswerResponseStatus.NO_PERMISSION + return tinderService.submitAnswers(true, user, answers) } - @GetMapping("tinder/communities") - fun getTinderCommunities(auth: Authentication?): ResponseEntity> { - val user = auth?.getUserEntityFromDatabaseOrNull(userService) ?: return ResponseEntity.status(401).build() - val res = tinderService.getTinderCommunities(user) - return ResponseEntity.ok(res) + @GetMapping("/tinder/community") + fun getTinderCommunities(auth: Authentication?): List { + val user = auth?.getUserEntityFromDatabaseOrNull(userService) ?: return emptyList() + return tinderService.getTinderCommunities(user) } - @PostMapping("tinder/communities/interact") + @PostMapping("/tinder/community/interact") fun interactWithCommunity( auth: Authentication?, @RequestBody interaction: TinderInteractionDto - ): ResponseEntity { - val user = auth?.getUserEntityFromDatabaseOrNull(userService) ?: return ResponseEntity.status(401).build() - tinderService.interactWithCommunity(user, interaction) - return ResponseEntity.ok().build() + ): Boolean { + val user = auth?.getUserEntityFromDatabaseOrNull(userService) ?: return false + return tinderService.interactWithCommunity(user, interaction) } } \ No newline at end of file diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderAnswerController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderAnswerController.kt new file mode 100644 index 000000000..67c7cc214 --- /dev/null +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderAnswerController.kt @@ -0,0 +1,72 @@ +package hu.bme.sch.cmsch.component.communities + +import hu.bme.sch.cmsch.controller.admin.OneDeepEntityPage +import hu.bme.sch.cmsch.controller.admin.calculateSearchSettings +import hu.bme.sch.cmsch.repository.ManualRepository +import hu.bme.sch.cmsch.service.* +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean +import org.springframework.core.env.Environment +import org.springframework.stereotype.Controller +import org.springframework.transaction.PlatformTransactionManager +import org.springframework.web.bind.annotation.RequestMapping +import tools.jackson.databind.ObjectMapper +import java.util.Optional + + +@Controller +@RequestMapping("/admin/control/tinder-answer") +@ConditionalOnBean(CommunitiesComponent::class) +class TinderAnswerController( + val tinderService: TinderService, + repo: TinderAnswerRepository, + importService: ImportService, + adminMenuService: AdminMenuService, + component: CommunitiesComponent, + auditLog: AuditLogService, + objectMapper: ObjectMapper, + transactionManager: PlatformTransactionManager, + env: Environment, + storageService: StorageService +) : OneDeepEntityPage( + "tinder-answer", + TinderAnswerEntity::class, ::TinderAnswerEntity, + "Tinder válasz", "Tinder válaszok", + "Tinder válaszok kezelése", + + transactionManager, + object: ManualRepository(){ + override fun findAll(): MutableIterable { + return repo.findAllWithUserIdNotNull() + } + override fun findById(id: Int): Optional { + return repo.findById(id) + } + override fun delete(entity: TinderAnswerEntity) { + repo.delete(entity) + } + }, + importService, + adminMenuService, + storageService, + component, + auditLog, + objectMapper, + env, + + showPermission = StaffPermissions.PERMISSION_SHOW_COMMUNITIES, + createPermission = StaffPermissions.PERMISSION_CREATE_COMMUNITIES, + editPermission = StaffPermissions.PERMISSION_EDIT_COMMUNITIES, + deletePermission = StaffPermissions.PERMISSION_DELETE_COMMUNITIES, + + createEnabled = true, + editEnabled = true, + deleteEnabled = true, + importEnabled = false, + exportEnabled = false, + + adminMenuIcon = "inbox", + adminMenuPriority = 4, + + searchSettings = calculateSearchSettings(false), +) { +} \ No newline at end of file diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderAnswerRepository.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderAnswerRepository.kt index e363e2934..9ce02a50d 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderAnswerRepository.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderAnswerRepository.kt @@ -1,5 +1,6 @@ package hu.bme.sch.cmsch.component.communities +import hu.bme.sch.cmsch.repository.EntityPageDataSource import org.springframework.boot.autoconfigure.condition.ConditionalOnBean import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.CrudRepository @@ -9,15 +10,15 @@ import java.util.* @Repository @ConditionalOnBean(CommunitiesComponent::class) -interface TinderAnswerRepository : CrudRepository { +interface TinderAnswerRepository : CrudRepository, EntityPageDataSource { fun findByCommunityId(communityId: Int): Optional fun findByUserId(userId: Int): Optional @Query("select t from TinderAnswerEntity t where t.communityId is not null") - fun findAllWithCommunityIdNotNull(): List + fun findAllWithCommunityIdNotNull(): MutableList @Query("select t from TinderAnswerEntity t where t.userId is not null") - fun findAllWithUserIdNotNull(): List + fun findAllWithUserIdNotNull(): MutableList } \ No newline at end of file diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderCommunityVirtualEntity.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderCommunityVirtualEntity.kt new file mode 100644 index 000000000..0272bebfa --- /dev/null +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderCommunityVirtualEntity.kt @@ -0,0 +1,20 @@ +package hu.bme.sch.cmsch.component.communities + +import hu.bme.sch.cmsch.admin.GenerateOverview +import hu.bme.sch.cmsch.admin.OverviewType +import hu.bme.sch.cmsch.model.IdentifiableEntity + +data class TinderCommunityVirtualEntity( + @property:GenerateOverview(renderer = OverviewType.ID, columnName = "ID", order = -1) + override var id: Int, + + @property:GenerateOverview(columnName = "Név", order = 1) + val name: String, + + @property:GenerateOverview(columnName = "Jobbra húzva", order = 2) + val likes: Int, + + @property:GenerateOverview(columnName = "Balra húzva", order = 3) + val dislikes: Int, + +) : IdentifiableEntity \ No newline at end of file diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderDtos.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderDtos.kt index 3e578f17f..11747fc30 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderDtos.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderDtos.kt @@ -3,20 +3,27 @@ package hu.bme.sch.cmsch.component.communities data class TinderQuestionDto( var id: Int = 0, var question: String = "", - var answers: List = emptyList() + var options: List = emptyList() ) { constructor(entity: TinderQuestionEntity) : this( id = entity.id, question = entity.question, - answers = entity.answerOptions.split(", *") + options = entity.answerOptions.split(",").map { it.trim() } ) } -data class TinderAnswerDto( - var userId: Int? = null, - var answers: Map = emptyMap() +class TinderAnswerStatus( + var answered: Boolean = false, + var answer: Map = emptyMap() ) +enum class TinderAnswerResponseStatus { + OK, + INVALID_ANSWER, + NO_PERMISSION, + ERROR +} + enum class TinderStatus{ NOT_SEEN, LIKED, diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderInteractionController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderInteractionController.kt new file mode 100644 index 000000000..aa18e87d5 --- /dev/null +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderInteractionController.kt @@ -0,0 +1,86 @@ +package hu.bme.sch.cmsch.component.communities + +import hu.bme.sch.cmsch.controller.admin.TwoDeepEntityPage +import hu.bme.sch.cmsch.repository.ManualRepository +import hu.bme.sch.cmsch.service.AdminMenuService +import hu.bme.sch.cmsch.service.AuditLogService +import hu.bme.sch.cmsch.service.ImportService +import hu.bme.sch.cmsch.service.StaffPermissions +import hu.bme.sch.cmsch.service.StorageService +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean +import org.springframework.core.env.Environment +import org.springframework.stereotype.Controller +import org.springframework.transaction.PlatformTransactionManager +import org.springframework.web.bind.annotation.RequestMapping +import tools.jackson.databind.ObjectMapper + +@Controller +@RequestMapping("/admin/control/tinder-interactions") +@ConditionalOnBean(CommunitiesComponent::class) +class TinderInteractionController( + private val communityRepository: CommunityRepository, + private val tinderService: TinderService, + tinderInteractionRepository: TinderInteractionRepository, + importService: ImportService, + adminMenuService: AdminMenuService, + component: CommunitiesComponent, + auditLog: AuditLogService, + objectMapper: ObjectMapper, + env: Environment, + transactionManager: PlatformTransactionManager, + storageService: StorageService +) : TwoDeepEntityPage( + "tinder-interactions", + TinderCommunityVirtualEntity::class, + TinderInteractionEntity::class, ::TinderInteractionEntity, + "Interakció", "Interakciók", + "Userek interakciói közösségekként csoportosítva", + + transactionManager, + object: ManualRepository() { + override fun findAll(): MutableIterable { + return tinderService.getAllInteractions() + .groupBy { it.communityId } + .map { it.value } + .filter { it.isNotEmpty() } + .mapNotNull { interactions -> + communityRepository.findById(interactions[0].communityId) + .map { community -> + TinderCommunityVirtualEntity( + community.id, + community.name, + interactions.count { it.liked }, + interactions.count { !it.liked } + ) + }.orElse(null) + }.toMutableList() + } + }, + tinderInteractionRepository, + importService, + adminMenuService, + storageService, + component, + auditLog, + objectMapper, + env, + + showPermission = StaffPermissions.PERMISSION_SHOW_COMMUNITIES, + createPermission = StaffPermissions.PERMISSION_CREATE_COMMUNITIES, + editPermission = StaffPermissions.PERMISSION_EDIT_COMMUNITIES, + deletePermission = StaffPermissions.PERMISSION_DELETE_COMMUNITIES, + + createEnabled = false, + editEnabled = true, + deleteEnabled = true, + importEnabled = false, + exportEnabled = false, + + adminMenuIcon = "sync_alt", + adminMenuPriority = 5, +) { + + override fun fetchSublist(id: Int): Iterable { + return tinderService.getInteractionsByCommunity(id) + } +} \ No newline at end of file diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderInteractionEntity.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderInteractionEntity.kt index 4cf95e328..5362628ac 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderInteractionEntity.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderInteractionEntity.kt @@ -1,5 +1,7 @@ package hu.bme.sch.cmsch.component.communities +import hu.bme.sch.cmsch.admin.GenerateOverview +import hu.bme.sch.cmsch.admin.OverviewType import hu.bme.sch.cmsch.component.EntityConfig import hu.bme.sch.cmsch.model.ManagedEntity import hu.bme.sch.cmsch.service.StaffPermissions @@ -21,15 +23,19 @@ data class TinderInteractionEntity( @Id @GeneratedValue @Column(nullable = false) + @property:GenerateOverview(renderer = OverviewType.ID, columnName = "ID", order = -1) override var id: Int = 0, @Column(nullable = false) + @property:GenerateOverview(columnName = "Közösség ID", order = 1) var communityId: Int = 0, @Column(nullable = false) + @property:GenerateOverview(columnName = "Felhasználó ID", order = 2) var userId: Int = 0, @Column(nullable = false) + @property:GenerateOverview(renderer = OverviewType.BOOLEAN, columnName = "Liked", order = 3) var liked: Boolean = true, ): ManagedEntity { diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderInteractionRepository.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderInteractionRepository.kt index 066365b81..0d8d3a96d 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderInteractionRepository.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderInteractionRepository.kt @@ -1,14 +1,15 @@ package hu.bme.sch.cmsch.component.communities +import hu.bme.sch.cmsch.repository.EntityPageDataSource import org.springframework.boot.autoconfigure.condition.ConditionalOnBean import org.springframework.data.repository.CrudRepository import org.springframework.stereotype.Repository -import java.util.Optional +import java.util.* @Repository @ConditionalOnBean(CommunitiesComponent::class) -interface TinderInteractionRepository : CrudRepository { +interface TinderInteractionRepository : CrudRepository, EntityPageDataSource { fun findByCommunityId(communityId: Int): List diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderService.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderService.kt index 90c5201d2..b126ea2b6 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderService.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/communities/TinderService.kt @@ -10,6 +10,8 @@ import org.springframework.transaction.annotation.Transactional import org.springframework.web.server.ResponseStatusException import tools.jackson.core.type.TypeReference import tools.jackson.databind.ObjectMapper +import java.util.Optional +import kotlin.collections.forEach import kotlin.collections.set import kotlin.jvm.optionals.getOrElse import kotlin.jvm.optionals.getOrNull @@ -26,7 +28,7 @@ class TinderService( private val tinderInteractionRepository: TinderInteractionRepository ) { - private val reader = objectMapper.readerFor(object: TypeReference>(){}) + private val reader = objectMapper.readerFor(object: TypeReference>(){}) @Transactional(readOnly = true) fun getAllQuestions() = questionRepository.findAll().toList() @@ -34,35 +36,39 @@ class TinderService( @Transactional(readOnly = true) fun getAnswerForCommunity(communityId: Int) = answerRepository.findByCommunityId(communityId) + @Transactional(readOnly = true) + fun getAnswerMapForUser(userId: Int): Optional> = answerRepository.findByUserId(userId) + .map { reader.readValue( it.answers ) } + @Transactional - fun submitAnswers(update: Boolean, user: UserEntity, answers: TinderAnswerDto) { - val questions = questionRepository.findAll().associateBy { it.id } - for (answer in answers.answers) { + fun submitAnswers(update: Boolean, user: CmschUser, answers: Map): TinderAnswerResponseStatus { + val questions = questionRepository.findAll().associateBy { it.question } + for (answer in answers) { val question = questions[answer.key] ?: continue - if (answer.value!="" && !question.answerOptions.split(", *").contains(answer.value)) { - throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Wrong answer option: ${answer.value}") + if (answer.value!="" && !question.answerOptions.split(",").map { it.trim() }.contains(answer.value)) { + return TinderAnswerResponseStatus.INVALID_ANSWER } } val existing = answerRepository.findByUserId(user.id) if (!update) { if (existing.isPresent){ - throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Answers already submitted") + return TinderAnswerResponseStatus.ERROR } val entity = TinderAnswerEntity( userId = user.id, - communityId = null, - answers = objectMapper.writeValueAsString(answers.answers) + userName = user.userName, + answers = objectMapper.writeValueAsString(answers) ) answerRepository.save(entity) } else { - val answer = mutableMapOf() + val answer = mutableMapOf() existing.ifPresent { - reader.readValue>(it.answers).forEach { (k, v) -> + reader.readValue>(it.answers).forEach { (k, v) -> answer[k] = v } } - for (ans in answers.answers) { + for (ans in answers) { answer[ans.key] = ans.value } existing.ifPresentOrElse( @@ -73,27 +79,28 @@ class TinderService( { val entity = TinderAnswerEntity( userId = user.id, - communityId = null, + userName = user.userName, answers = objectMapper.writeValueAsString(answer) ) answerRepository.save(entity) } ) } + return TinderAnswerResponseStatus.OK } @Transactional(readOnly = true) fun getTinderCommunities(user: UserEntity): List { val communities = communityRepository.findAll().toList() val answerList = answerRepository.findAllWithCommunityIdNotNull() - val answers = mutableMapOf>() + val answers = mutableMapOf>() for (answer in answerList) { - val ansMap = reader.readValue>(answer.answers) + val ansMap = reader.readValue>(answer.answers) answers[answer.communityId!!] = ansMap } - val userAnswer = reader.readValue>( + val userAnswer = reader.readValue>( answerRepository.findByUserId(user.id) - .orElseThrow { ResponseStatusException(HttpStatus.BAD_REQUEST, "User has not answered the questions") } + .getOrElse { return emptyList() } .answers ) val userInteractions = tinderInteractionRepository.findByUserId(user.id).associateBy { it.communityId } @@ -122,7 +129,7 @@ class TinderService( application = it.application, resortName = it.resortName, tinderAnswers = answers[it.id]?.values?.toList() ?: emptyList() - ) } + ) }.sortedBy { it.status } return communityProfiles } @@ -146,16 +153,16 @@ class TinderService( ?: return "redirect:/admin/control/community" val prevAnswer = ensureCommunityAnswer(community) - val answer = mutableMapOf() - reader.readValue>(prevAnswer.answers) + val answer = mutableMapOf() + reader.readValue>(prevAnswer.answers) .entries.forEach { answer[it.key] = it.value } for (question in questions) { - val ans = data["question_${question.id}"] ?: continue + val ans = data[question.question] ?: continue val options = question.answerOptions.split(',').map { it.trim() } if (options.contains(ans)) { - answer[question.id] = ans + answer[question.question] = ans } else if (ans != "") { throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Hibás válaszlehetőség: $ans") } @@ -170,18 +177,33 @@ class TinderService( } @Transactional - fun interactWithCommunity(user: UserEntity, interaction: TinderInteractionDto) { - val community = communityRepository.findById(interaction.communityId).orElseThrow { - ResponseStatusException(HttpStatus.BAD_REQUEST, "Community not found: ${interaction.communityId}") + fun interactWithCommunity(user: UserEntity, interaction: TinderInteractionDto): Boolean { + val community = communityRepository.findById(interaction.communityId).getOrNull() ?: return false + if (tinderInteractionRepository.findByCommunityIdAndUserId(community.id, user.id).isPresent){ + return false } - tinderInteractionRepository.findByCommunityIdAndUserId(community.id, user.id) - .ifPresent { throw ResponseStatusException(HttpStatus.BAD_REQUEST, "User has already swiped the community") } val entity = TinderInteractionEntity( communityId = community.id, userId = user.id, liked = interaction.liked ) tinderInteractionRepository.save(entity) + return true } + + @Transactional(readOnly = true) + fun getInteractionsByUser(userId: Int): List { + return tinderInteractionRepository.findByUserId(userId) + } + + @Transactional(readOnly = true) + fun getInteractionsByCommunity(communityId: Int): List { + return tinderInteractionRepository.findByCommunityId(communityId) + } + + @Transactional(readOnly = true) + fun getAllInteractions(): List { + return tinderInteractionRepository.findAll().toList() + } } diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js index 7834e1567..57c1f6513 100644 --- a/frontend/eslint.config.js +++ b/frontend/eslint.config.js @@ -2,11 +2,11 @@ import js from '@eslint/js' import prettierRecommended from 'eslint-plugin-prettier/recommended' import reactHooks from 'eslint-plugin-react-hooks' import reactRefresh from 'eslint-plugin-react-refresh' -import { globalIgnores } from 'eslint/config' +import { defineConfig, globalIgnores } from 'eslint/config' import globals from 'globals' import tseslint from 'typescript-eslint' -export default tseslint.config([ +export default defineConfig([ globalIgnores(['dist']), { files: ['**/*.{ts,tsx}'], @@ -22,7 +22,6 @@ export default tseslint.config([ globals: globals.browser }, rules: { - 'react/jsx-props-no-spreading': 'off', 'react/require-default-props': 'off', 'max-len': [ diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d9df595e4..a0545f8fb 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -15,65 +15,65 @@ "@chakra-ui/theme-tools": "2.2.9", "@emotion/react": "11.14.0", "@emotion/styled": "11.14.1", - "@firebase/app": "0.14.1", + "@firebase/app": "0.14.8", "@firebase/messaging": "0.12.23", "@nivo/bar": "0.99.0", - "@tanstack/react-query": "5.90.11", - "@tanstack/react-query-devtools": "5.91.1", + "@tanstack/react-query": "5.90.20", + "@tanstack/react-query-devtools": "5.91.3", "@zxing/browser": "0.1.5", "@zxing/library": "0.21.3", "axios": "1.13.2", "color": "5.0.3", "date-fns": "4.1.0", "deepmerge": "4.3.1", - "framer-motion": "12.23.24", + "framer-motion": "12.33.0", "js-cookie": "3.0.5", "pigeon-maps": "0.22.1", "prismjs": "1.30.0", - "react": "18.3.1", - "react-dom": "18.3.1", + "react": "19.2.4", + "react-dom": "19.2.4", "react-geolocated": "4.4.0", - "react-helmet-async": "2.0.5", - "react-hook-form": "7.66.1", + "react-hook-form": "7.71.1", "react-icons": "5.5.0", "react-markdown": "10.1.0", "react-qr-code": "2.0.18", - "react-router": "7.9.6", + "react-router": "7.13.0", "react-simple-code-editor": "0.14.1", "remark-gfm": "4.0.1", "values.js": "2.1.1" }, "devDependencies": { - "@eslint/js": "9.39.1", + "@eslint/js": "9.39.2", "@types/js-cookie": "3.0.6", - "@types/node": "24.10.1", + "@types/node": "24.10.12", "@types/prismjs": "1.26.5", - "@types/react": "18.3.27", - "@types/react-dom": "18.3.7", + "@types/react": "19.2.13", + "@types/react-dom": "19.2.3", "@vitejs/plugin-legacy": "7.2.1", - "@vitejs/plugin-react-swc": "4.2.2", - "eslint": "9.39.1", + "@vitejs/plugin-react": "5.1.3", + "babel-plugin-react-compiler": "1.0.0", + "eslint": "9.39.2", "eslint-config-prettier": "10.1.8", - "eslint-plugin-prettier": "5.5.4", + "eslint-plugin-prettier": "5.5.5", "eslint-plugin-react-hooks": "7.0.1", - "eslint-plugin-react-refresh": "0.4.24", - "globals": "16.5.0", + "eslint-plugin-react-refresh": "0.5.0", + "globals": "17.3.0", "npm-run-all": "4.1.5", - "prettier": "3.6.2", + "prettier": "3.8.1", "prettier-plugin-organize-imports": "4.3.0", - "terser": "5.44.1", + "terser": "5.46.0", "typescript": "5.9.3", - "typescript-eslint": "8.48.0", - "vite": "7.2.4" + "typescript-eslint": "8.54.0", + "vite": "npm:rolldown-vite@7.2.5" } }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -82,9 +82,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", "dev": true, "license": "MIT", "engines": { @@ -92,21 +92,21 @@ } }, "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -130,13 +130,13 @@ "license": "MIT" }, "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -159,13 +159,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", + "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -176,18 +176,18 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", - "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", + "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.5", + "@babel/traverse": "^7.28.6", "semver": "^6.3.1" }, "engines": { @@ -216,17 +216,17 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", - "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.6.tgz", + "integrity": "sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "debug": "^4.4.1", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", "lodash.debounce": "^4.0.8", - "resolve": "^1.22.10" + "resolve": "^1.22.11" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -256,28 +256,28 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -300,9 +300,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true, "license": "MIT", "engines": { @@ -328,15 +328,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -388,41 +388,41 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", - "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", + "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.3", - "@babel/types": "^7.28.2" + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "license": "MIT", "dependencies": { - "@babel/types": "^7.28.5" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -499,14 +499,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", - "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz", + "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -529,13 +529,13 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", - "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", + "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -545,13 +545,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -594,15 +594,15 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", - "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz", + "integrity": "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.29.0" }, "engines": { "node": ">=6.9.0" @@ -612,14 +612,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", - "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", + "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-remap-async-to-generator": "^7.27.1" }, "engines": { @@ -646,13 +646,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", - "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", + "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -662,14 +662,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", - "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", + "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -679,14 +679,14 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", - "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", + "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -696,18 +696,18 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", - "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", + "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.4" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -717,14 +717,14 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", - "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", + "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/template": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/template": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -751,14 +751,14 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", - "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz", + "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -784,14 +784,14 @@ } }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -817,14 +817,14 @@ } }, "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", - "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz", + "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -834,13 +834,13 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", - "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz", + "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -901,13 +901,13 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", - "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz", + "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -933,13 +933,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", - "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", + "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -982,14 +982,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", - "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", + "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -999,16 +999,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", - "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz", + "integrity": "sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.5" + "@babel/traverse": "^7.29.0" }, "engines": { "node": ">=6.9.0" @@ -1035,14 +1035,14 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1068,13 +1068,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", - "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", + "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1084,13 +1084,13 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", - "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", + "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1100,17 +1100,17 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", - "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", + "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.4" + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1137,13 +1137,13 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", - "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", + "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1153,13 +1153,13 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", - "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", + "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { @@ -1186,14 +1186,14 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", - "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", + "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1203,15 +1203,15 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", - "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", + "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1236,10 +1236,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", - "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", "dev": true, "license": "MIT", "dependencies": { @@ -1252,19 +1252,51 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-regexp-modifiers": { + "node_modules/@babel/plugin-transform-react-jsx-source": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", - "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz", + "integrity": "sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz", + "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, "peerDependencies": { "@babel/core": "^7.0.0" } @@ -1302,13 +1334,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", - "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", + "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { @@ -1383,14 +1415,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", - "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz", + "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1417,14 +1449,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", - "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz", + "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1434,81 +1466,81 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", - "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.0.tgz", + "integrity": "sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/compat-data": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.27.1", - "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-import-assertions": "^7.28.6", + "@babel/plugin-syntax-import-attributes": "^7.28.6", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.28.0", - "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.29.0", + "@babel/plugin-transform-async-to-generator": "^7.28.6", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.5", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-class-static-block": "^7.28.3", - "@babel/plugin-transform-classes": "^7.28.4", - "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.6", + "@babel/plugin-transform-class-properties": "^7.28.6", + "@babel/plugin-transform-class-static-block": "^7.28.6", + "@babel/plugin-transform-classes": "^7.28.6", + "@babel/plugin-transform-computed-properties": "^7.28.6", "@babel/plugin-transform-destructuring": "^7.28.5", - "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-dotall-regex": "^7.28.6", "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.0", "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.28.5", + "@babel/plugin-transform-explicit-resource-management": "^7.28.6", + "@babel/plugin-transform-exponentiation-operator": "^7.28.6", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.28.6", "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.6", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-modules-systemjs": "^7.28.5", + "@babel/plugin-transform-modules-commonjs": "^7.28.6", + "@babel/plugin-transform-modules-systemjs": "^7.29.0", "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", - "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.4", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", + "@babel/plugin-transform-numeric-separator": "^7.28.6", + "@babel/plugin-transform-object-rest-spread": "^7.28.6", "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.28.5", + "@babel/plugin-transform-optional-catch-binding": "^7.28.6", + "@babel/plugin-transform-optional-chaining": "^7.28.6", "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.27.1", - "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-private-methods": "^7.28.6", + "@babel/plugin-transform-private-property-in-object": "^7.28.6", "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.4", - "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.29.0", + "@babel/plugin-transform-regexp-modifiers": "^7.28.6", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-spread": "^7.28.6", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.28.6", "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.14", - "babel-plugin-polyfill-corejs3": "^0.13.0", - "babel-plugin-polyfill-regenerator": "^0.6.5", - "core-js-compat": "^3.43.0", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", "semver": "^6.3.1" }, "engines": { @@ -1518,6 +1550,20 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.0.tgz", + "integrity": "sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.6", + "core-js-compat": "^3.48.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/@babel/preset-modules": { "version": "0.1.6-no-external-plugins", "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", @@ -1534,40 +1580,40 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", - "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", "debug": "^4.3.1" }, "engines": { @@ -1575,9 +1621,9 @@ } }, "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -1694,6 +1740,40 @@ "react": ">=16.8.0" } }, + "node_modules/@emnapi/core": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", + "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emotion/babel-plugin": { "version": "11.13.5", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", @@ -1840,535 +1920,93 @@ "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", "license": "MIT" }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", - "cpu": [ - "ppc64" - ], + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "aix" - ], + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, "engines": { - "node": ">=18" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2378,7 +2016,7 @@ "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, @@ -2403,9 +2041,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", - "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true, "license": "MIT", "engines": { @@ -2440,9 +2078,9 @@ } }, "node_modules/@firebase/app": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.14.1.tgz", - "integrity": "sha512-jxTrDbxnGoX7cGz7aP9E7v9iKvBbQfZ8Gz4TH3SfrrkcyIojJM3+hJnlbGnGxHrABts844AxRcg00arMZEyA6Q==", + "version": "0.14.8", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.14.8.tgz", + "integrity": "sha512-WiE9uCGRLUnShdjb9iP20sA3ToWrBbNXr14/N5mow7Nls9dmKgfGaGX5cynLvrltxq2OrDLh1VDNaUgsnS/k/g==", "license": "Apache-2.0", "dependencies": { "@firebase/component": "0.7.0", @@ -2640,6 +2278,23 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", + "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, "node_modules/@nivo/annotations": { "version": "0.99.0", "resolved": "https://registry.npmjs.org/@nivo/annotations/-/annotations-0.99.0.tgz", @@ -2656,22 +2311,6 @@ "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, - "node_modules/@nivo/annotations/node_modules/@react-spring/web": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-10.0.3.tgz", - "integrity": "sha512-ndU+kWY81rHsT7gTFtCJ6mrVhaJ6grFmgTnENipzmKqot4HGf5smPNK+cZZJqoGeDsj9ZsiWPW4geT/NyD484A==", - "license": "MIT", - "dependencies": { - "@react-spring/animated": "~10.0.3", - "@react-spring/core": "~10.0.3", - "@react-spring/shared": "~10.0.3", - "@react-spring/types": "~10.0.3" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, "node_modules/@nivo/axes": { "version": "0.99.0", "resolved": "https://registry.npmjs.org/@nivo/axes/-/axes-0.99.0.tgz", @@ -2681,31 +2320,15 @@ "@nivo/core": "0.99.0", "@nivo/scales": "0.99.0", "@nivo/text": "0.99.0", - "@nivo/theming": "0.99.0", - "@react-spring/web": "9.4.5 || ^9.7.2 || ^10.0", - "@types/d3-format": "^1.4.1", - "@types/d3-time-format": "^2.3.1", - "d3-format": "^1.4.4", - "d3-time-format": "^3.0.0" - }, - "peerDependencies": { - "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" - } - }, - "node_modules/@nivo/axes/node_modules/@react-spring/web": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-10.0.3.tgz", - "integrity": "sha512-ndU+kWY81rHsT7gTFtCJ6mrVhaJ6grFmgTnENipzmKqot4HGf5smPNK+cZZJqoGeDsj9ZsiWPW4geT/NyD484A==", - "license": "MIT", - "dependencies": { - "@react-spring/animated": "~10.0.3", - "@react-spring/core": "~10.0.3", - "@react-spring/shared": "~10.0.3", - "@react-spring/types": "~10.0.3" + "@nivo/theming": "0.99.0", + "@react-spring/web": "9.4.5 || ^9.7.2 || ^10.0", + "@types/d3-format": "^1.4.1", + "@types/d3-time-format": "^2.3.1", + "d3-format": "^1.4.4", + "d3-time-format": "^3.0.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, "node_modules/@nivo/bar": { @@ -2735,22 +2358,6 @@ "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, - "node_modules/@nivo/bar/node_modules/@react-spring/web": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-10.0.3.tgz", - "integrity": "sha512-ndU+kWY81rHsT7gTFtCJ6mrVhaJ6grFmgTnENipzmKqot4HGf5smPNK+cZZJqoGeDsj9ZsiWPW4geT/NyD484A==", - "license": "MIT", - "dependencies": { - "@react-spring/animated": "~10.0.3", - "@react-spring/core": "~10.0.3", - "@react-spring/shared": "~10.0.3", - "@react-spring/types": "~10.0.3" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, "node_modules/@nivo/canvas": { "version": "0.99.0", "resolved": "https://registry.npmjs.org/@nivo/canvas/-/canvas-0.99.0.tgz", @@ -2806,32 +2413,6 @@ "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, - "node_modules/@nivo/core/node_modules/@react-spring/web": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-10.0.3.tgz", - "integrity": "sha512-ndU+kWY81rHsT7gTFtCJ6mrVhaJ6grFmgTnENipzmKqot4HGf5smPNK+cZZJqoGeDsj9ZsiWPW4geT/NyD484A==", - "license": "MIT", - "dependencies": { - "@react-spring/animated": "~10.0.3", - "@react-spring/core": "~10.0.3", - "@react-spring/shared": "~10.0.3", - "@react-spring/types": "~10.0.3" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@nivo/core/node_modules/react-virtualized-auto-sizer": { - "version": "1.0.26", - "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.26.tgz", - "integrity": "sha512-CblNyiNVw2o+hsa5/49NH2ogGxZ+t+3aweRvNSq7TVjDIlwk7ir4lencEg5HxHeSzwNarSkNkiu0qJSOXtxm5A==", - "license": "MIT", - "peerDependencies": { - "react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, "node_modules/@nivo/legends": { "version": "0.99.0", "resolved": "https://registry.npmjs.org/@nivo/legends/-/legends-0.99.0.tgz", @@ -2886,22 +2467,6 @@ "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, - "node_modules/@nivo/text/node_modules/@react-spring/web": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-10.0.3.tgz", - "integrity": "sha512-ndU+kWY81rHsT7gTFtCJ6mrVhaJ6grFmgTnENipzmKqot4HGf5smPNK+cZZJqoGeDsj9ZsiWPW4geT/NyD484A==", - "license": "MIT", - "dependencies": { - "@react-spring/animated": "~10.0.3", - "@react-spring/core": "~10.0.3", - "@react-spring/shared": "~10.0.3", - "@react-spring/types": "~10.0.3" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, "node_modules/@nivo/theming": { "version": "0.99.0", "resolved": "https://registry.npmjs.org/@nivo/theming/-/theming-0.99.0.tgz", @@ -2928,364 +2493,125 @@ "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" } }, - "node_modules/@nivo/tooltip/node_modules/@react-spring/web": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-10.0.3.tgz", - "integrity": "sha512-ndU+kWY81rHsT7gTFtCJ6mrVhaJ6grFmgTnENipzmKqot4HGf5smPNK+cZZJqoGeDsj9ZsiWPW4geT/NyD484A==", - "license": "MIT", - "dependencies": { - "@react-spring/animated": "~10.0.3", - "@react-spring/core": "~10.0.3", - "@react-spring/shared": "~10.0.3", - "@react-spring/types": "~10.0.3" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "node_modules/@oxc-project/runtime": { + "version": "0.97.0", + "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.97.0.tgz", + "integrity": "sha512-yH0zw7z+jEws4dZ4IUKoix5Lh3yhqIJWF9Dc8PWvhpo7U7O+lJrv7ZZL4BeRO0la8LBQFwcCewtLBnVV7hPe/w==", "dev": true, "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" - } - }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, - "node_modules/@react-spring/animated": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-10.0.3.tgz", - "integrity": "sha512-7MrxADV3vaUADn2V9iYhaIL6iOWRx9nCJjYrsk2AHD2kwPr6fg7Pt0v+deX5RnCDmCKNnD6W5fasiyM8D+wzJQ==", - "license": "MIT", - "dependencies": { - "@react-spring/shared": "~10.0.3", - "@react-spring/types": "~10.0.3" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@react-spring/core": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-10.0.3.tgz", - "integrity": "sha512-D4DwNO68oohDf/0HG2G0Uragzb9IA1oXblxrd6MZAcBcUQG2EHUWXewjdECMPLNmQvlYVyyBRH6gPxXM5DX7DQ==", - "license": "MIT", - "dependencies": { - "@react-spring/animated": "~10.0.3", - "@react-spring/shared": "~10.0.3", - "@react-spring/types": "~10.0.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/react-spring/donate" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@react-spring/rafz": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-10.0.3.tgz", - "integrity": "sha512-Ri2/xqt8OnQ2iFKkxKMSF4Nqv0LSWnxXT4jXFzBDsHgeeH/cHxTLupAWUwmV9hAGgmEhBmh5aONtj3J6R/18wg==", - "license": "MIT" - }, - "node_modules/@react-spring/shared": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-10.0.3.tgz", - "integrity": "sha512-geCal66nrkaQzUVhPkGomylo+Jpd5VPK8tPMEDevQEfNSWAQP15swHm+MCRG4wVQrQlTi9lOzKzpRoTL3CA84Q==", - "license": "MIT", - "dependencies": { - "@react-spring/rafz": "~10.0.3", - "@react-spring/types": "~10.0.3" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@react-spring/types": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-10.0.3.tgz", - "integrity": "sha512-H5Ixkd2OuSIgHtxuHLTt7aJYfhMXKXT/rK32HPD/kSrOB6q6ooeiWAXkBy7L8F3ZxdkBb9ini9zP9UwnEFzWgQ==", - "license": "MIT" - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.47", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.47.tgz", - "integrity": "sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz", - "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz", - "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz", - "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz", - "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz", - "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz", - "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz", - "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz", - "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz", - "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz", - "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz", - "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz", - "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==", - "cpu": [ - "ppc64" - ], + "node_modules/@oxc-project/types": { + "version": "0.97.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.97.0.tgz", + "integrity": "sha512-lxmZK4xFrdvU0yZiDwgVQTCvh2gHWBJCBk5ALsrtsBWhs0uDIi+FTOnXRQeQfs304imdvTdaakT/lqwQ8hkOXQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "funding": { + "url": "https://github.com/sponsors/Boshen" + } }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz", - "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==", - "cpu": [ - "riscv64" - ], + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz", - "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==", - "cpu": [ - "riscv64" - ], - "dev": true, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz", - "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==", - "cpu": [ - "s390x" - ], - "dev": true, + "node_modules/@react-spring/animated": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-10.0.3.tgz", + "integrity": "sha512-7MrxADV3vaUADn2V9iYhaIL6iOWRx9nCJjYrsk2AHD2kwPr6fg7Pt0v+deX5RnCDmCKNnD6W5fasiyM8D+wzJQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@react-spring/shared": "~10.0.3", + "@react-spring/types": "~10.0.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz", - "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@react-spring/core": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-10.0.3.tgz", + "integrity": "sha512-D4DwNO68oohDf/0HG2G0Uragzb9IA1oXblxrd6MZAcBcUQG2EHUWXewjdECMPLNmQvlYVyyBRH6gPxXM5DX7DQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@react-spring/animated": "~10.0.3", + "@react-spring/shared": "~10.0.3", + "@react-spring/types": "~10.0.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz", - "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@react-spring/rafz": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-10.0.3.tgz", + "integrity": "sha512-Ri2/xqt8OnQ2iFKkxKMSF4Nqv0LSWnxXT4jXFzBDsHgeeH/cHxTLupAWUwmV9hAGgmEhBmh5aONtj3J6R/18wg==", + "license": "MIT" + }, + "node_modules/@react-spring/shared": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-10.0.3.tgz", + "integrity": "sha512-geCal66nrkaQzUVhPkGomylo+Jpd5VPK8tPMEDevQEfNSWAQP15swHm+MCRG4wVQrQlTi9lOzKzpRoTL3CA84Q==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@react-spring/rafz": "~10.0.3", + "@react-spring/types": "~10.0.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz", - "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@react-spring/types": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-10.0.3.tgz", + "integrity": "sha512-H5Ixkd2OuSIgHtxuHLTt7aJYfhMXKXT/rK32HPD/kSrOB6q6ooeiWAXkBy7L8F3ZxdkBb9ini9zP9UwnEFzWgQ==", + "license": "MIT" + }, + "node_modules/@react-spring/web": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-10.0.3.tgz", + "integrity": "sha512-ndU+kWY81rHsT7gTFtCJ6mrVhaJ6grFmgTnENipzmKqot4HGf5smPNK+cZZJqoGeDsj9ZsiWPW4geT/NyD484A==", "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] + "dependencies": { + "@react-spring/animated": "~10.0.3", + "@react-spring/core": "~10.0.3", + "@react-spring/shared": "~10.0.3", + "@react-spring/types": "~10.0.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz", - "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.50.tgz", + "integrity": "sha512-XlEkrOIHLyGT3avOgzfTFSjG+f+dZMw+/qd+Y3HLN86wlndrB/gSimrJCk4gOhr1XtRtEKfszpadI3Md4Z4/Ag==", "cpu": [ "arm64" ], @@ -3293,27 +2619,33 @@ "license": "MIT", "optional": true, "os": [ - "win32" - ] + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz", - "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.50.tgz", + "integrity": "sha512-+JRqKJhoFlt5r9q+DecAGPLZ5PxeLva+wCMtAuoFMWPoZzgcYrr599KQ+Ix0jwll4B4HGP43avu9My8KtSOR+w==", "cpu": [ - "ia32" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" - ] + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz", - "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.50.tgz", + "integrity": "sha512-fFXDjXnuX7/gQZQm/1FoivVtRcyAzdjSik7Eo+9iwPQ9EgtA5/nB2+jmbzaKtMGG3q+BnZbdKHCtOacmNrkIDA==", "cpu": [ "x64" ], @@ -3321,13 +2653,16 @@ "license": "MIT", "optional": true, "os": [ - "win32" - ] + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz", - "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.50.tgz", + "integrity": "sha512-F1b6vARy49tjmT/hbloplzgJS7GIvwWZqt+tAHEstCh0JIh9sa8FAMVqEmYxDviqKBaAI8iVvUREm/Kh/PD26Q==", "cpu": [ "x64" ], @@ -3335,239 +2670,193 @@ "license": "MIT", "optional": true, "os": [ - "win32" - ] - }, - "node_modules/@swc/core": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.3.tgz", - "integrity": "sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q==", - "dev": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@swc/counter": "^0.1.3", - "@swc/types": "^0.1.25" - }, + "freebsd" + ], "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/swc" - }, - "optionalDependencies": { - "@swc/core-darwin-arm64": "1.15.3", - "@swc/core-darwin-x64": "1.15.3", - "@swc/core-linux-arm-gnueabihf": "1.15.3", - "@swc/core-linux-arm64-gnu": "1.15.3", - "@swc/core-linux-arm64-musl": "1.15.3", - "@swc/core-linux-x64-gnu": "1.15.3", - "@swc/core-linux-x64-musl": "1.15.3", - "@swc/core-win32-arm64-msvc": "1.15.3", - "@swc/core-win32-ia32-msvc": "1.15.3", - "@swc/core-win32-x64-msvc": "1.15.3" - }, - "peerDependencies": { - "@swc/helpers": ">=0.5.17" - }, - "peerDependenciesMeta": { - "@swc/helpers": { - "optional": true - } + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@swc/core-darwin-arm64": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.3.tgz", - "integrity": "sha512-AXfeQn0CvcQ4cndlIshETx6jrAM45oeUrK8YeEY6oUZU/qzz0Id0CyvlEywxkWVC81Ajpd8TQQ1fW5yx6zQWkQ==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.50.tgz", + "integrity": "sha512-U6cR76N8T8M6lHj7EZrQ3xunLPxSvYYxA8vJsBKZiFZkT8YV4kjgCO3KwMJL0NOjQCPGKyiXO07U+KmJzdPGRw==", "cpu": [ - "arm64" + "arm" ], "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "darwin" + "linux" ], "engines": { - "node": ">=10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@swc/core-darwin-x64": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.3.tgz", - "integrity": "sha512-p68OeCz1ui+MZYG4wmfJGvcsAcFYb6Sl25H9TxWl+GkBgmNimIiRdnypK9nBGlqMZAcxngNPtnG3kEMNnvoJ2A==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.50.tgz", + "integrity": "sha512-ONgyjofCrrE3bnh5GZb8EINSFyR/hmwTzZ7oVuyUB170lboza1VMCnb8jgE6MsyyRgHYmN8Lb59i3NKGrxrYjw==", "cpu": [ - "x64" + "arm64" ], "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "darwin" + "linux" ], "engines": { - "node": ">=10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.3.tgz", - "integrity": "sha512-Nuj5iF4JteFgwrai97mUX+xUOl+rQRHqTvnvHMATL/l9xE6/TJfPBpd3hk/PVpClMXG3Uvk1MxUFOEzM1JrMYg==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.50.tgz", + "integrity": "sha512-L0zRdH2oDPkmB+wvuTl+dJbXCsx62SkqcEqdM+79LOcB+PxbAxxjzHU14BuZIQdXcAVDzfpMfaHWzZuwhhBTcw==", "cpu": [ - "arm" + "arm64" ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.3.tgz", - "integrity": "sha512-2Nc/s8jE6mW2EjXWxO/lyQuLKShcmTrym2LRf5Ayp3ICEMX6HwFqB1EzDhwoMa2DcUgmnZIalesq2lG3krrUNw==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.50.tgz", + "integrity": "sha512-gyoI8o/TGpQd3OzkJnh1M2kxy1Bisg8qJ5Gci0sXm9yLFzEXIFdtc4EAzepxGvrT2ri99ar5rdsmNG0zP0SbIg==", "cpu": [ - "arm64" + "x64" ], "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.3.tgz", - "integrity": "sha512-j4SJniZ/qaZ5g8op+p1G9K1z22s/EYGg1UXIb3+Cg4nsxEpF5uSIGEE4mHUfA70L0BR9wKT2QF/zv3vkhfpX4g==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.50.tgz", + "integrity": "sha512-zti8A7M+xFDpKlghpcCAzyOi+e5nfUl3QhU023ce5NCgUxRG5zGP2GR9LTydQ1rnIPwZUVBWd4o7NjZDaQxaXA==", "cpu": [ - "arm64" + "x64" ], "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.3.tgz", - "integrity": "sha512-aKttAZnz8YB1VJwPQZtyU8Uk0BfMP63iDMkvjhJzRZVgySmqt/apWSdnoIcZlUoGheBrcqbMC17GGUmur7OT5A==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.50.tgz", + "integrity": "sha512-eZUssog7qljrrRU9Mi0eqYEPm3Ch0UwB+qlWPMKSUXHNqhm3TvDZarJQdTevGEfu3EHAXJvBIe0YFYr0TPVaMA==", "cpu": [ - "x64" + "arm64" ], "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ - "linux" + "openharmony" ], "engines": { - "node": ">=10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@swc/core-linux-x64-musl": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.3.tgz", - "integrity": "sha512-oe8FctPu1gnUsdtGJRO2rvOUIkkIIaHqsO9xxN0bTR7dFTlPTGi2Fhk1tnvXeyAvCPxLIcwD8phzKg6wLv9yug==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.50.tgz", + "integrity": "sha512-nmCN0nIdeUnmgeDXiQ+2HU6FT162o+rxnF7WMkBm4M5Ds8qTU7Dzv2Wrf22bo4ftnlrb2hKK6FSwAJSAe2FWLg==", "cpu": [ - "x64" + "wasm32" ], "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@napi-rs/wasm-runtime": "^1.0.7" + }, "engines": { - "node": ">=10" + "node": ">=14.0.0" } }, - "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.3.tgz", - "integrity": "sha512-L9AjzP2ZQ/Xh58e0lTRMLvEDrcJpR7GwZqAtIeNLcTK7JVE+QineSyHp0kLkO1rttCHyCy0U74kDTj0dRz6raA==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.50.tgz", + "integrity": "sha512-7kcNLi7Ua59JTTLvbe1dYb028QEPaJPJQHqkmSZ5q3tJueUeb6yjRtx8mw4uIqgWZcnQHAR3PrLN4XRJxvgIkA==", "cpu": [ "arm64" ], "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.3.tgz", - "integrity": "sha512-B8UtogMzErUPDWUoKONSVBdsgKYd58rRyv2sHJWKOIMCHfZ22FVXICR4O/VwIYtlnZ7ahERcjayBHDlBZpR0aw==", + "node_modules/@rolldown/binding-win32-ia32-msvc": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.50.tgz", + "integrity": "sha512-lL70VTNvSCdSZkDPPVMwWn/M2yQiYvSoXw9hTLgdIWdUfC3g72UaruezusR6ceRuwHCY1Ayu2LtKqXkBO5LIwg==", "cpu": [ "ia32" ], "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.3.tgz", - "integrity": "sha512-SpZKMR9QBTecHeqpzJdYEfgw30Oo8b/Xl6rjSzBt1g0ZsXyy60KLXrp6IagQyfTYqNYE/caDvwtF2FPn7pomog==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.50.tgz", + "integrity": "sha512-4qU4x5DXWB4JPjyTne/wBNPqkbQU8J45bl21geERBKtEittleonioACBL1R0PsBu0Aq21SwMK5a9zdBkWSlQtQ==", "cpu": [ "x64" ], "dev": true, - "license": "Apache-2.0 AND MIT", + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@swc/counter": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/@swc/types": { - "version": "0.1.25", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.25.tgz", - "integrity": "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==", + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.2", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", + "integrity": "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@swc/counter": "^0.1.3" - } + "license": "MIT" }, "node_modules/@tanstack/query-core": { - "version": "5.90.11", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.11.tgz", - "integrity": "sha512-f9z/nXhCgWDF4lHqgIE30jxLe4sYv15QodfdPDKYAk7nAEjNcndy4dHz3ezhdUaR23BpWa4I2EH4/DZ0//Uf8A==", + "version": "5.90.20", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.20.tgz", + "integrity": "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==", "license": "MIT", "funding": { "type": "github", @@ -3575,9 +2864,9 @@ } }, "node_modules/@tanstack/query-devtools": { - "version": "5.91.1", - "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.91.1.tgz", - "integrity": "sha512-l8bxjk6BMsCaVQH6NzQEE/bEgFy1hAs5qbgXl0xhzezlaQbPk6Mgz9BqEg2vTLPOHD8N4k+w/gdgCbEzecGyNg==", + "version": "5.93.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.93.0.tgz", + "integrity": "sha512-+kpsx1NQnOFTZsw6HAFCW3HkKg0+2cepGtAWXjiiSOJJ1CtQpt72EE2nyZb+AjAbLRPoeRmPJ8MtQd8r8gsPdg==", "license": "MIT", "funding": { "type": "github", @@ -3585,12 +2874,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.90.11", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.11.tgz", - "integrity": "sha512-3uyzz01D1fkTLXuxF3JfoJoHQMU2fxsfJwE+6N5hHy0dVNoZOvwKP8Z2k7k1KDeD54N20apcJnG75TBAStIrBA==", + "version": "5.90.20", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.20.tgz", + "integrity": "sha512-vXBxa+qeyveVO7OA0jX1z+DeyCA4JKnThKv411jd5SORpBKgkcVnYKCiBgECvADvniBX7tobwBmg01qq9JmMJw==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.90.11" + "@tanstack/query-core": "5.90.20" }, "funding": { "type": "github", @@ -3601,22 +2890,78 @@ } }, "node_modules/@tanstack/react-query-devtools": { - "version": "5.91.1", - "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.91.1.tgz", - "integrity": "sha512-tRnJYwEbH0kAOuToy8Ew7bJw1lX3AjkkgSlf/vzb+NpnqmHPdWM+lA2DSdGQSLi1SU0PDRrrCI1vnZnci96CsQ==", + "version": "5.91.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.91.3.tgz", + "integrity": "sha512-nlahjMtd/J1h7IzOOfqeyDh5LNfG0eULwlltPEonYy0QL+nqrBB+nyzJfULV+moL7sZyxc2sHdNJki+vLA9BSA==", "license": "MIT", "dependencies": { - "@tanstack/query-devtools": "5.91.1" + "@tanstack/query-devtools": "5.93.0" }, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/react-query": "^5.90.10", + "@tanstack/react-query": "^5.90.20", "react": "^18 || ^19" } }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, "node_modules/@types/d3-color": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", @@ -3660,9 +3005,9 @@ "license": "MIT" }, "node_modules/@types/d3-shape": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", - "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", "license": "MIT", "dependencies": { "@types/d3-path": "*" @@ -3728,9 +3073,9 @@ "license": "MIT" }, "node_modules/@types/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==", "license": "MIT" }, "node_modules/@types/lodash.mergewith": { @@ -3758,9 +3103,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", - "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "version": "24.10.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.12.tgz", + "integrity": "sha512-68e+T28EbdmLSTkPgs3+UacC6rzmqrcWFPQs1C8mwJhI/r5Uxr0yEuQotczNRROd1gq30NGxee+fo0rSIxpyAw==", "dev": true, "license": "MIT", "dependencies": { @@ -3780,30 +3125,23 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "license": "MIT" - }, "node_modules/@types/react": { - "version": "18.3.27", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", - "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", + "version": "19.2.13", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.13.tgz", + "integrity": "sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==", "license": "MIT", "dependencies": { - "@types/prop-types": "*", "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", "peerDependencies": { - "@types/react": "^18.0.0" + "@types/react": "^19.2.0" } }, "node_modules/@types/unist": { @@ -3813,21 +3151,20 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.0.tgz", - "integrity": "sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz", + "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.48.0", - "@typescript-eslint/type-utils": "8.48.0", - "@typescript-eslint/utils": "8.48.0", - "@typescript-eslint/visitor-keys": "8.48.0", - "graphemer": "^1.4.0", - "ignore": "^7.0.0", + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/type-utils": "8.54.0", + "@typescript-eslint/utils": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3837,7 +3174,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.48.0", + "@typescript-eslint/parser": "^8.54.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -3853,17 +3190,17 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.0.tgz", - "integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz", + "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.48.0", - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/typescript-estree": "8.48.0", - "@typescript-eslint/visitor-keys": "8.48.0", - "debug": "^4.3.4" + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3878,15 +3215,15 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.0.tgz", - "integrity": "sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz", + "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.48.0", - "@typescript-eslint/types": "^8.48.0", - "debug": "^4.3.4" + "@typescript-eslint/tsconfig-utils": "^8.54.0", + "@typescript-eslint/types": "^8.54.0", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3900,14 +3237,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.0.tgz", - "integrity": "sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz", + "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/visitor-keys": "8.48.0" + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3918,9 +3255,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.0.tgz", - "integrity": "sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz", + "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", "dev": true, "license": "MIT", "engines": { @@ -3935,17 +3272,17 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.0.tgz", - "integrity": "sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz", + "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/typescript-estree": "8.48.0", - "@typescript-eslint/utils": "8.48.0", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/utils": "8.54.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3960,9 +3297,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.0.tgz", - "integrity": "sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", + "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", "dev": true, "license": "MIT", "engines": { @@ -3974,21 +3311,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.0.tgz", - "integrity": "sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz", + "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.48.0", - "@typescript-eslint/tsconfig-utils": "8.48.0", - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/visitor-keys": "8.48.0", - "debug": "^4.3.4", - "minimatch": "^9.0.4", - "semver": "^7.6.0", + "@typescript-eslint/project-service": "8.54.0", + "@typescript-eslint/tsconfig-utils": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.1.0" + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4028,9 +3365,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -4041,16 +3378,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.0.tgz", - "integrity": "sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz", + "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.48.0", - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/typescript-estree": "8.48.0" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4065,13 +3402,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.0.tgz", - "integrity": "sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz", + "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -4119,21 +3456,25 @@ "vite": "^7.0.0" } }, - "node_modules/@vitejs/plugin-react-swc": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-4.2.2.tgz", - "integrity": "sha512-x+rE6tsxq/gxrEJN3Nv3dIV60lFflPj94c90b+NNo6n1QV1QQUTLoL0MpaOVasUZ0zqVBn7ead1B5ecx1JAGfA==", + "node_modules/@vitejs/plugin-react": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.3.tgz", + "integrity": "sha512-NVUnA6gQCl8jfoYqKqQU5Clv0aPw14KkZYCsX6T9Lfu9slI0LOU10OTwFHS/WmptsMMpshNd/1tuWsHQ2Uk+cg==", "dev": true, "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "1.0.0-beta.47", - "@swc/core": "^1.13.5" + "@babel/core": "^7.29.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-rc.2", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" }, "engines": { "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^4 || ^5 || ^6 || ^7" + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "node_modules/@zag-js/dom-query": { @@ -4384,14 +3725,14 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", - "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.15.tgz", + "integrity": "sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.7", - "@babel/helper-define-polyfill-provider": "^0.6.5", + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.6", "semver": "^6.3.1" }, "peerDependencies": { @@ -4413,18 +3754,28 @@ } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", - "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.6.tgz", + "integrity": "sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5" + "@babel/helper-define-polyfill-provider": "^0.6.6" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, + "node_modules/babel-plugin-react-compiler": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz", + "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + } + }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -4443,9 +3794,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.31", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.31.tgz", - "integrity": "sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==", + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4464,9 +3815,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", - "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "funding": [ { @@ -4484,11 +3835,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.8.25", - "caniuse-lite": "^1.0.30001754", - "electron-to-chromium": "^1.5.249", + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", - "update-browserslist-db": "^1.1.4" + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -4582,9 +3933,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001757", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz", - "integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==", + "version": "1.0.30001769", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", + "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", "dev": true, "funding": [ { @@ -4786,9 +4137,9 @@ } }, "node_modules/core-js": { - "version": "3.47.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz", - "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==", + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz", + "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4798,13 +4149,13 @@ } }, "node_modules/core-js-compat": { - "version": "3.47.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz", - "integrity": "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==", + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.48.0.tgz", + "integrity": "sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.28.0" + "browserslist": "^4.28.1" }, "funding": { "type": "opencollective", @@ -5055,9 +4406,9 @@ } }, "node_modules/decode-named-character-reference": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", - "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", "license": "MIT", "dependencies": { "character-entities": "^2.0.0" @@ -5137,6 +4488,16 @@ "node": ">=6" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", @@ -5171,9 +4532,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.261", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.261.tgz", - "integrity": "sha512-cmyHEWFqEt3ICUNF93ShneOF47DHoSDbLb7E/AonsWcbzg95N+kPXeLNfkdzgTT/vEUcoW76fxbLBkeYtfoM8A==", + "version": "1.5.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", "dev": true, "license": "ISC" }, @@ -5187,9 +4548,9 @@ } }, "node_modules/es-abstract": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", "dev": true, "license": "MIT", "dependencies": { @@ -5318,48 +4679,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" - } - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -5383,9 +4702,9 @@ } }, "node_modules/eslint": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", - "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", "dependencies": { @@ -5395,7 +4714,7 @@ "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.1", + "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -5459,14 +4778,14 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", - "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", + "version": "5.5.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", + "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", "dev": true, "license": "MIT", "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.11.7" + "prettier-linter-helpers": "^1.0.1", + "synckit": "^0.11.12" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -5510,13 +4829,13 @@ } }, "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.24.tgz", - "integrity": "sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.0.tgz", + "integrity": "sha512-ZYvmh7VfVgqR/7wR71I3Zl6hK/C5CcxdWYKZSpHawS5JCNgE4efhQWg/+/WPpgGAp9Ngp/rRZYyaIwmPQBq/lA==", "dev": true, "license": "MIT", "peerDependencies": { - "eslint": ">=8.40" + "eslint": ">=9" } }, "node_modules/eslint-scope": { @@ -5568,9 +4887,9 @@ } }, "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -5797,13 +5116,13 @@ } }, "node_modules/framer-motion": { - "version": "12.23.24", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.24.tgz", - "integrity": "sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==", + "version": "12.33.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.33.0.tgz", + "integrity": "sha512-ca8d+rRPcDP5iIF+MoT3WNc0KHJMjIyFAbtVLvM9eA7joGSpeqDfiNH/kCs1t4CHi04njYvWyj0jS4QlEK/rJQ==", "license": "MIT", "dependencies": { - "motion-dom": "^12.23.23", - "motion-utils": "^12.23.6", + "motion-dom": "^12.33.0", + "motion-utils": "^12.29.2", "tslib": "^2.4.0" }, "peerDependencies": { @@ -5991,9 +5310,9 @@ } }, "node_modules/globals": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", - "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.3.0.tgz", + "integrity": "sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==", "dev": true, "license": "MIT", "engines": { @@ -6039,13 +5358,6 @@ "dev": true, "license": "ISC" }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, "node_modules/has-bigints": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", @@ -6304,15 +5616,6 @@ "node": ">=12" } }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, "node_modules/is-alphabetical": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", @@ -6881,6 +6184,267 @@ "node": ">= 0.8.0" } }, + "node_modules/lightningcss": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", + "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.31.1", + "lightningcss-darwin-arm64": "1.31.1", + "lightningcss-darwin-x64": "1.31.1", + "lightningcss-freebsd-x64": "1.31.1", + "lightningcss-linux-arm-gnueabihf": "1.31.1", + "lightningcss-linux-arm64-gnu": "1.31.1", + "lightningcss-linux-arm64-musl": "1.31.1", + "lightningcss-linux-x64-gnu": "1.31.1", + "lightningcss-linux-x64-musl": "1.31.1", + "lightningcss-win32-arm64-msvc": "1.31.1", + "lightningcss-win32-x64-msvc": "1.31.1" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", + "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", + "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", + "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", + "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", + "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", + "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", + "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", + "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", + "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", + "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", + "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -6934,9 +6498,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "license": "MIT" }, "node_modules/lodash.debounce": { @@ -7948,18 +7512,18 @@ } }, "node_modules/motion-dom": { - "version": "12.23.23", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz", - "integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==", + "version": "12.33.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.33.0.tgz", + "integrity": "sha512-XRPebVypsl0UM+7v0Hr8o9UAj0S2djsQWRdHBd5iVouVpMrQqAI0C/rDAT3QaYnXnHuC5hMcwDHCboNeyYjPoQ==", "license": "MIT", "dependencies": { - "motion-utils": "^12.23.6" + "motion-utils": "^12.29.2" } }, "node_modules/motion-utils": { - "version": "12.23.6", - "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz", - "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==", + "version": "12.29.2", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.29.2.tgz", + "integrity": "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A==", "license": "MIT" }, "node_modules/ms": { @@ -8536,9 +8100,9 @@ } }, "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", "bin": { @@ -8552,9 +8116,9 @@ } }, "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", "dev": true, "license": "MIT", "dependencies": { @@ -8640,13 +8204,10 @@ "license": "MIT" }, "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, "engines": { "node": ">=0.10.0" } @@ -8664,16 +8225,15 @@ } }, "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^18.3.1" + "react": "^19.2.4" } }, "node_modules/react-fast-compare": { @@ -8683,9 +8243,9 @@ "license": "MIT" }, "node_modules/react-focus-lock": { - "version": "2.13.6", - "resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.13.6.tgz", - "integrity": "sha512-ehylFFWyYtBKXjAO9+3v8d0i+cnc1trGS0vlTGhzFW1vbFXVUTmR8s2tt/ZQG8x5hElg6rhENlLG1H3EZK0Llg==", + "version": "2.13.7", + "resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.13.7.tgz", + "integrity": "sha512-20lpZHEQrXPb+pp1tzd4ULL6DyO5D2KnR0G69tTDdydrmNhU7pdFmbQUYVyHUgp+xN29IuFR0PVuhOmvaZL9Og==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.0.0", @@ -8714,24 +8274,10 @@ "react": ">= 16.8.0 < 20.0.0" } }, - "node_modules/react-helmet-async": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-2.0.5.tgz", - "integrity": "sha512-rYUYHeus+i27MvFE+Jaa4WsyBKGkL6qVgbJvSBoX8mbsWoABJXdEO0bZyi0F6i+4f0NuIb8AvqPMj3iXFHkMwg==", - "license": "Apache-2.0", - "dependencies": { - "invariant": "^2.2.4", - "react-fast-compare": "^3.2.2", - "shallowequal": "^1.1.0" - }, - "peerDependencies": { - "react": "^16.6.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/react-hook-form": { - "version": "7.66.1", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.66.1.tgz", - "integrity": "sha512-2KnjpgG2Rhbi+CIiIBQQ9Df6sMGH5ExNyFl4Hw9qO7pIqMBR8Bvu9RQyjl3JM4vehzCh9soiNUM/xYMswb2EiA==", + "version": "7.71.1", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.71.1.tgz", + "integrity": "sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w==", "license": "MIT", "engines": { "node": ">=18.0.0" @@ -8799,10 +8345,20 @@ "react": "*" } }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-remove-scroll": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", - "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", "license": "MIT", "dependencies": { "react-remove-scroll-bar": "^2.3.7", @@ -8847,9 +8403,9 @@ } }, "node_modules/react-router": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.6.tgz", - "integrity": "sha512-Y1tUp8clYRXpfPITyuifmSoE2vncSME18uVLgaqyxh9H35JWpIfzHo+9y3Fzh5odk/jxPW29IgLgzcdwxGqyNA==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.0.tgz", + "integrity": "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -8900,6 +8456,16 @@ } } }, + "node_modules/react-virtualized-auto-sizer": { + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.26.tgz", + "integrity": "sha512-CblNyiNVw2o+hsa5/49NH2ogGxZ+t+3aweRvNSq7TVjDIlwk7ir4lencEg5HxHeSzwNarSkNkiu0qJSOXtxm5A==", + "license": "MIT", + "peerDependencies": { + "react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -9132,47 +8698,45 @@ "node": ">=4" } }, - "node_modules/rollup": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz", - "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", + "node_modules/rolldown": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.50.tgz", + "integrity": "sha512-JFULvCNl/anKn99eKjOSEubi0lLmNqQDAjyEMME2T4CwezUDL0i6t1O9xZsu2OMehPnV2caNefWpGF+8TnzB6A==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.8" + "@oxc-project/types": "=0.97.0", + "@rolldown/pluginutils": "1.0.0-beta.50" }, "bin": { - "rollup": "dist/bin/rollup" + "rolldown": "bin/cli.mjs" }, "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" + "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.53.3", - "@rollup/rollup-android-arm64": "4.53.3", - "@rollup/rollup-darwin-arm64": "4.53.3", - "@rollup/rollup-darwin-x64": "4.53.3", - "@rollup/rollup-freebsd-arm64": "4.53.3", - "@rollup/rollup-freebsd-x64": "4.53.3", - "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", - "@rollup/rollup-linux-arm-musleabihf": "4.53.3", - "@rollup/rollup-linux-arm64-gnu": "4.53.3", - "@rollup/rollup-linux-arm64-musl": "4.53.3", - "@rollup/rollup-linux-loong64-gnu": "4.53.3", - "@rollup/rollup-linux-ppc64-gnu": "4.53.3", - "@rollup/rollup-linux-riscv64-gnu": "4.53.3", - "@rollup/rollup-linux-riscv64-musl": "4.53.3", - "@rollup/rollup-linux-s390x-gnu": "4.53.3", - "@rollup/rollup-linux-x64-gnu": "4.53.3", - "@rollup/rollup-linux-x64-musl": "4.53.3", - "@rollup/rollup-openharmony-arm64": "4.53.3", - "@rollup/rollup-win32-arm64-msvc": "4.53.3", - "@rollup/rollup-win32-ia32-msvc": "4.53.3", - "@rollup/rollup-win32-x64-gnu": "4.53.3", - "@rollup/rollup-win32-x64-msvc": "4.53.3", - "fsevents": "~2.3.2" - } + "@rolldown/binding-android-arm64": "1.0.0-beta.50", + "@rolldown/binding-darwin-arm64": "1.0.0-beta.50", + "@rolldown/binding-darwin-x64": "1.0.0-beta.50", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.50", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.50", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.50", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.50", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.50", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.50", + "@rolldown/binding-openharmony-arm64": "1.0.0-beta.50", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.50", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.50", + "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.50", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.50" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.50", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.50.tgz", + "integrity": "sha512-5e76wQiQVeL1ICOZVUg4LSOVYg9jyhGCin+icYozhsUzM+fHE7kddi1bdiE0jwVqTfkjba3jUFbEkoC9WkdvyA==", + "dev": true, + "license": "MIT" }, "node_modules/safe-array-concat": { "version": "1.1.3", @@ -9230,13 +8794,10 @@ } }, "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" }, "node_modules/semver": { "version": "6.3.1", @@ -9303,12 +8864,6 @@ "node": ">= 0.4" } }, - "node_modules/shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", - "license": "MIT" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -9686,9 +9241,9 @@ } }, "node_modules/synckit": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", - "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9709,9 +9264,9 @@ "license": "MIT" }, "node_modules/terser": { - "version": "5.44.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz", - "integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==", + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -9771,9 +9326,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", "dev": true, "license": "MIT", "engines": { @@ -9904,16 +9459,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.0.tgz", - "integrity": "sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.54.0.tgz", + "integrity": "sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.48.0", - "@typescript-eslint/parser": "8.48.0", - "@typescript-eslint/typescript-estree": "8.48.0", - "@typescript-eslint/utils": "8.48.0" + "@typescript-eslint/eslint-plugin": "8.54.0", + "@typescript-eslint/parser": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/utils": "8.54.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -10056,9 +9611,9 @@ } }, "node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -10085,9 +9640,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", - "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -10147,9 +9702,9 @@ } }, "node_modules/use-debounce": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.6.tgz", - "integrity": "sha512-C5OtPyhAZgVoteO9heXMTdW7v/IbFI+8bSVKYCJrSmiWWCLsbUxiBSp4t9v0hNBTGY97bT72ydDIDyGSFWfwXg==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.1.0.tgz", + "integrity": "sha512-lu87Za35V3n/MyMoEpD5zJv0k7hCn0p+V/fK2kWD+3k2u3kOCwO593UArbczg1fhfs2rqPEnHpULJ3KmGdDzvg==", "license": "MIT", "engines": { "node": ">= 16.0.0" @@ -10231,17 +9786,19 @@ } }, "node_modules/vite": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.4.tgz", - "integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==", + "name": "rolldown-vite", + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.2.5.tgz", + "integrity": "sha512-u09tdk/huMiN8xwoiBbig197jKdCamQTtOruSalOzbqGje3jdHiV0njQlAW0YvzoahkirFePNQ4RYlfnRQpXZA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", + "@oxc-project/runtime": "0.97.0", "fdir": "^6.5.0", + "lightningcss": "^1.30.2", "picomatch": "^4.0.3", "postcss": "^8.5.6", - "rollup": "^4.43.0", + "rolldown": "1.0.0-beta.50", "tinyglobby": "^0.2.15" }, "bin": { @@ -10258,9 +9815,9 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", + "esbuild": "^0.25.0", "jiti": ">=1.21.0", "less": "^4.0.0", - "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", @@ -10273,13 +9830,13 @@ "@types/node": { "optional": true }, - "jiti": { + "esbuild": { "optional": true }, - "less": { + "jiti": { "optional": true }, - "lightningcss": { + "less": { "optional": true }, "sass": { @@ -10389,9 +9946,9 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", "dev": true, "license": "MIT", "dependencies": { @@ -10441,9 +9998,9 @@ } }, "node_modules/zod": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", - "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "dev": true, "license": "MIT", "funding": { diff --git a/frontend/package.json b/frontend/package.json index 74ce4d4c7..c93dbeef0 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,56 +11,59 @@ "@chakra-ui/theme-tools": "2.2.9", "@emotion/react": "11.14.0", "@emotion/styled": "11.14.1", - "@firebase/app": "0.14.1", + "@firebase/app": "0.14.8", "@firebase/messaging": "0.12.23", "@nivo/bar": "0.99.0", - "@tanstack/react-query": "5.90.11", - "@tanstack/react-query-devtools": "5.91.1", + "@tanstack/react-query": "5.90.20", + "@tanstack/react-query-devtools": "5.91.3", "@zxing/browser": "0.1.5", "@zxing/library": "0.21.3", "axios": "1.13.2", "color": "5.0.3", "date-fns": "4.1.0", "deepmerge": "4.3.1", - "framer-motion": "12.23.24", + "framer-motion": "12.33.0", "js-cookie": "3.0.5", "pigeon-maps": "0.22.1", "prismjs": "1.30.0", - "react": "18.3.1", - "react-dom": "18.3.1", + "react": "19.2.4", + "react-dom": "19.2.4", "react-geolocated": "4.4.0", - "react-helmet-async": "2.0.5", - "react-hook-form": "7.66.1", + "react-hook-form": "7.71.1", "react-icons": "5.5.0", "react-markdown": "10.1.0", "react-qr-code": "2.0.18", - "react-router": "7.9.6", + "react-router": "7.13.0", "react-simple-code-editor": "0.14.1", "remark-gfm": "4.0.1", "values.js": "2.1.1" }, "devDependencies": { - "@eslint/js": "9.39.1", + "@eslint/js": "9.39.2", "@types/js-cookie": "3.0.6", - "@types/node": "24.10.1", + "@types/node": "24.10.12", "@types/prismjs": "1.26.5", - "@types/react": "18.3.27", - "@types/react-dom": "18.3.7", + "@types/react": "19.2.13", + "@types/react-dom": "19.2.3", "@vitejs/plugin-legacy": "7.2.1", - "@vitejs/plugin-react-swc": "4.2.2", - "eslint": "9.39.1", + "@vitejs/plugin-react": "5.1.3", + "babel-plugin-react-compiler": "1.0.0", + "eslint": "9.39.2", "eslint-config-prettier": "10.1.8", - "eslint-plugin-prettier": "5.5.4", + "eslint-plugin-prettier": "5.5.5", "eslint-plugin-react-hooks": "7.0.1", - "eslint-plugin-react-refresh": "0.4.24", - "globals": "16.5.0", + "eslint-plugin-react-refresh": "0.5.0", + "globals": "17.3.0", "npm-run-all": "4.1.5", - "prettier": "3.6.2", + "prettier": "3.8.1", "prettier-plugin-organize-imports": "4.3.0", - "terser": "5.44.1", + "terser": "5.46.0", "typescript": "5.9.3", - "typescript-eslint": "8.48.0", - "vite": "7.2.4" + "typescript-eslint": "8.54.0", + "vite": "npm:rolldown-vite@7.2.5" + }, + "overrides": { + "vite": "npm:rolldown-vite@7.2.5" }, "scripts": { "dev": "vite", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index bd6291f9e..9374a7e3a 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,11 +1,16 @@ import { Suspense } from 'react' import { Route, Routes } from 'react-router' +import { useConfigContext } from './api/contexts/config/ConfigContext.tsx' import { CmschLayout } from './common-components/layout/CmschLayout' import AccessKeyPage from './pages/access-key/accessKey.page.tsx' import CommunityPage from './pages/communities/community.page.tsx' import CommunityListPage from './pages/communities/communityList.page.tsx' +import LikedCommunityListPage from './pages/communities/likedCommunityList.page.tsx' import OrganizationPage from './pages/communities/organization.page.tsx' import OrganizationListPage from './pages/communities/organizationList.page.tsx' +import TinderPage from './pages/communities/tinder.page.tsx' +import TinderQuestionsPage from './pages/communities/tinderQuestions.page.tsx' +import TinderRouter from './pages/communities/tinderRouter.tsx' import CountdownPage from './pages/countdown/countdown.page' import DebtPage from './pages/debt/debt.page.tsx' import { ErrorPage } from './pages/error/error.page' @@ -46,101 +51,111 @@ import TokenScanPage from './pages/token/tokenScan.page.tsx' import TokenScanResultPage from './pages/token/tokenScanResult.page.tsx' import { l } from './util/language' import { Paths } from './util/paths.ts' +import { TitleProvider } from './util/TitleProvider.tsx' export function App() { + const appName = useConfigContext()?.components?.app?.siteName || 'CMSch' return ( - - - - - - - } /> - - } /> - - } /> - } /> - - - } /> - - - } /> - } /> - - - } /> - } /> - } /> - - - } /> - - - } /> - - - } /> - - } /> - - } /> - - - } /> - } /> - - - } /> - } /> - } /> - - } /> - - } /> - } /> - } /> - - - } /> - } /> - } /> - } /> - - - } /> - } /> - } /> - - } /> - } /> - - } /> - } /> - - - } /> - - } /> + (title ? `${appName} | ${title}` : appName)}> + + + + + + + } /> + + } /> + + } /> + } /> + + + } /> + + + } /> + } /> + + + } /> + } /> + } /> + } /> + + + } /> + } /> + } /> + + + } /> + + + } /> + + + } /> + + } /> + + } /> + + + } /> + } /> + + + } /> + } /> + } /> + + } /> + + } /> + } /> + } /> + + + } /> + } /> + } /> + } /> + + + } /> + } /> + } /> + + } /> + } /> + + } /> } /> - - } /> - - } /> - } /> - - } /> - } /> - } /> - {/** Error handling pages */} - } /> - } /> - - - - - + + } /> + + } /> + } /> + + + } /> + + } /> + } /> + + } /> + } /> + } /> + {/** Error handling pages */} + } /> + } /> + + + + + + ) } diff --git a/frontend/src/api/contexts/auth/AuthContext.tsx b/frontend/src/api/contexts/auth/AuthContext.tsx index 9fcfa0e9a..b2fc118d4 100644 --- a/frontend/src/api/contexts/auth/AuthContext.tsx +++ b/frontend/src/api/contexts/auth/AuthContext.tsx @@ -1,6 +1,6 @@ -import { createContext, PropsWithChildren, useCallback, useEffect, useState } from 'react' +import { createContext, type PropsWithChildren, useCallback, useEffect, useState } from 'react' import { API_BASE_URL } from '../../../util/configs/environment.config' -import { AuthState, UserAuthInfoView } from '../../../util/views/authInfo.view.ts' +import { AuthState, type UserAuthInfoView } from '../../../util/views/authInfo.view.ts' import { useAuthInfo } from '../../hooks/auth/useAuthInfo.ts' import { useTokenRefresh } from '../../hooks/useTokenRefresh.ts' diff --git a/frontend/src/api/contexts/auth/useAuthContext.ts b/frontend/src/api/contexts/auth/useAuthContext.ts index 4312e742a..e038bd8b1 100644 --- a/frontend/src/api/contexts/auth/useAuthContext.ts +++ b/frontend/src/api/contexts/auth/useAuthContext.ts @@ -1,5 +1,5 @@ import { useContext } from 'react' -import { AuthContext, AuthContextType } from './AuthContext' +import { AuthContext, type AuthContextType } from './AuthContext' export const useAuthContext = () => { return useContext(AuthContext) diff --git a/frontend/src/api/contexts/config/ConfigContext.tsx b/frontend/src/api/contexts/config/ConfigContext.tsx index a024b9ef5..e95659001 100644 --- a/frontend/src/api/contexts/config/ConfigContext.tsx +++ b/frontend/src/api/contexts/config/ConfigContext.tsx @@ -1,9 +1,9 @@ -import { createContext, PropsWithChildren, useContext, useEffect } from 'react' +import { createContext, type PropsWithChildren, useContext, useEffect } from 'react' import { LoadingView } from '../../../util/LoadingView.tsx' import { usePersistentStyleSetting } from '../../../util/configs/themeStyle.config.ts' import { l } from '../../../util/language.ts' import { useConfigQuery } from '../../hooks/config/useConfigQuery' -import { ConfigDto } from './types' +import type { ConfigDto } from './types' // eslint-disable-next-line react-refresh/only-export-components export const ConfigContext = createContext(undefined) diff --git a/frontend/src/api/contexts/config/types.ts b/frontend/src/api/contexts/config/types.ts index 8ab591874..9bba280dd 100644 --- a/frontend/src/api/contexts/config/types.ts +++ b/frontend/src/api/contexts/config/types.ts @@ -280,6 +280,7 @@ export type UserHandling = object export type ExtraPage = object export interface Location { + title: string topMessage: string bottomMessage: string } @@ -353,6 +354,9 @@ export interface Signup { export interface Communities { title: string description: string + searchEnabled: boolean titleResort: string descriptionResort: string + searchEnabledResort: boolean + tinderEnabled: boolean } diff --git a/frontend/src/api/contexts/service/ServiceContext.tsx b/frontend/src/api/contexts/service/ServiceContext.tsx index 4f882bb81..3968752b7 100644 --- a/frontend/src/api/contexts/service/ServiceContext.tsx +++ b/frontend/src/api/contexts/service/ServiceContext.tsx @@ -1,14 +1,15 @@ import { useToast } from '@chakra-ui/react' -import { createContext, PropsWithChildren, useContext, useEffect, useState } from 'react' +import { createContext, type PropsWithChildren, useContext, useEffect, useState } from 'react' import { useNavigate } from 'react-router' import { l } from '../../../util/language' import { AbsolutePaths } from '../../../util/paths' // eslint-disable-next-line react-refresh/only-export-components -export enum MessageTypes { - GENERAL = 'general', - AUTHENTICATION = 'authentication' +export const MessageTypes = { + GENERAL: 'general', + AUTHENTICATION: 'authentication' } +export type MessageTypes = (typeof MessageTypes)[keyof typeof MessageTypes] export interface MessageOptions { toast?: boolean diff --git a/frontend/src/api/contexts/themeConfig/ThemeConfig.tsx b/frontend/src/api/contexts/themeConfig/ThemeConfig.tsx index 944e50aa7..7aeba99dd 100644 --- a/frontend/src/api/contexts/themeConfig/ThemeConfig.tsx +++ b/frontend/src/api/contexts/themeConfig/ThemeConfig.tsx @@ -1,17 +1,20 @@ import { ChakraProvider, useColorMode } from '@chakra-ui/react' -import { PropsWithChildren, useEffect, useMemo, useState } from 'react' +import { type PropsWithChildren, useEffect, useMemo, useState } from 'react' import { getCustomTheme } from '../../../util/configs/theme.config.ts' import { getPersistentStyle, PersistentStyleSettingContext, savePersistentStyle } from '../../../util/configs/themeStyle.config.ts' -import { Style } from '../config/types.ts' +import type { Style } from '../config/types.ts' const ColorModeSetter = ({ children, style }: PropsWithChildren & { style?: Style }) => { const { colorMode, setColorMode } = useColorMode() useEffect(() => { + console.log(colorMode, setColorMode, style, style?.deviceTheme, style?.forceDarkMode) if (!setColorMode) return if (!style) return if (colorMode !== 'dark' && style.forceDarkMode) { setColorMode('dark') - } else if (!style.darkModeEnabled) setColorMode('white') + } else if (!style.darkModeEnabled && !style.forceDarkMode) { + setColorMode('white') + } }, [colorMode, setColorMode, style, style?.deviceTheme, style?.forceDarkMode]) return <>{children} diff --git a/frontend/src/api/hooks/access-key/useAccessKeyMutation.ts b/frontend/src/api/hooks/access-key/useAccessKeyMutation.ts index ac195eda2..c7a71df4b 100644 --- a/frontend/src/api/hooks/access-key/useAccessKeyMutation.ts +++ b/frontend/src/api/hooks/access-key/useAccessKeyMutation.ts @@ -2,7 +2,7 @@ import { useMutation } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { AccessKeyRequest, AccessKeyResponse } from '../../../util/views/accessKey' +import type { AccessKeyRequest, AccessKeyResponse } from '../../../util/views/accessKey' import { QueryKeys } from '../queryKeys.ts' export function useAccessKeyMutation(onSuccess: (data: AccessKeyResponse) => void, onError: () => void) { diff --git a/frontend/src/api/hooks/access-key/useAccessKeyQuery.ts b/frontend/src/api/hooks/access-key/useAccessKeyQuery.ts index 5b8df9b89..d7dd703d5 100644 --- a/frontend/src/api/hooks/access-key/useAccessKeyQuery.ts +++ b/frontend/src/api/hooks/access-key/useAccessKeyQuery.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { AccessKey } from '../../../util/views/accessKey' +import type { AccessKey } from '../../../util/views/accessKey' import { QueryKeys } from '../queryKeys' export const useAccessKey = () => { diff --git a/frontend/src/api/hooks/auth/useAuthInfo.ts b/frontend/src/api/hooks/auth/useAuthInfo.ts index 8551c5dff..a94aaa0c6 100644 --- a/frontend/src/api/hooks/auth/useAuthInfo.ts +++ b/frontend/src/api/hooks/auth/useAuthInfo.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { UserAuthInfoView } from '../../../util/views/authInfo.view.ts' +import type { UserAuthInfoView } from '../../../util/views/authInfo.view.ts' import { QueryKeys } from '../queryKeys' export const useAuthInfo = () => { diff --git a/frontend/src/api/hooks/community/useCommunity.ts b/frontend/src/api/hooks/community/useCommunity.ts index df0cd36fc..7d96b5659 100644 --- a/frontend/src/api/hooks/community/useCommunity.ts +++ b/frontend/src/api/hooks/community/useCommunity.ts @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { Community } from '../../../util/views/organization' +import type { Community } from '../../../util/views/organization' import { QueryKeys } from '../queryKeys' export const useCommunity = (id: string) => { diff --git a/frontend/src/api/hooks/community/useCommunityList.ts b/frontend/src/api/hooks/community/useCommunityList.ts index 8af2b15b5..a0861e31d 100644 --- a/frontend/src/api/hooks/community/useCommunityList.ts +++ b/frontend/src/api/hooks/community/useCommunityList.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { Community } from '../../../util/views/organization' +import type { Community } from '../../../util/views/organization' import { QueryKeys } from '../queryKeys' export const useCommunityList = () => { diff --git a/frontend/src/api/hooks/community/useOrganization.ts b/frontend/src/api/hooks/community/useOrganization.ts index 43d57414b..6eab63ee2 100644 --- a/frontend/src/api/hooks/community/useOrganization.ts +++ b/frontend/src/api/hooks/community/useOrganization.ts @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { Organization } from '../../../util/views/organization' +import type { Organization } from '../../../util/views/organization' import { QueryKeys } from '../queryKeys' export const useOrganization = (id: string) => { diff --git a/frontend/src/api/hooks/community/useOrganizationList.ts b/frontend/src/api/hooks/community/useOrganizationList.ts index 57d49e27c..21a286d36 100644 --- a/frontend/src/api/hooks/community/useOrganizationList.ts +++ b/frontend/src/api/hooks/community/useOrganizationList.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { Organization } from '../../../util/views/organization' +import type { Organization } from '../../../util/views/organization' import { QueryKeys } from '../queryKeys' export const useOrganizationList = () => { diff --git a/frontend/src/api/hooks/community/useTinderAnswerSend.ts b/frontend/src/api/hooks/community/useTinderAnswerSend.ts new file mode 100644 index 000000000..544e3d0b0 --- /dev/null +++ b/frontend/src/api/hooks/community/useTinderAnswerSend.ts @@ -0,0 +1,22 @@ +import axios from 'axios' +import { useState } from 'react' +import { ApiPaths } from '../../../util/paths.ts' +import { SendAnswerResponseStatus } from '../../../util/views/tinder.ts' + +export const useTinderAnswerSend = () => { + const [data, setData] = useState() + const submit = (answers: object, edit?: boolean) => { + if (edit) { + axios + .put(ApiPaths.TINDER_ANSWERS, answers) + .then((res) => setData(res.data)) + .catch(console.error) + } else { + axios + .post(ApiPaths.TINDER_ANSWERS, answers) + .then((res) => setData(res.data)) + .catch(console.error) + } + } + return { response: data, submit } +} diff --git a/frontend/src/api/hooks/community/useTinderAnswers.ts b/frontend/src/api/hooks/community/useTinderAnswers.ts new file mode 100644 index 000000000..9937f9440 --- /dev/null +++ b/frontend/src/api/hooks/community/useTinderAnswers.ts @@ -0,0 +1,19 @@ +import { useQuery } from '@tanstack/react-query' +import axios from 'axios' +import { ApiPaths } from '../../../util/paths.ts' +import { QueryKeys } from '../queryKeys.ts' + +interface TinderAnswerStatus { + answered: boolean + answer: Record +} + +export const useTinderAnswers = () => { + return useQuery({ + queryKey: [QueryKeys.TINDER_ANSWERS], + queryFn: async () => { + const res = await axios.get(ApiPaths.TINDER_ANSWERS) + return res.data + } + }) +} diff --git a/frontend/src/api/hooks/community/useTinderCommunity.ts b/frontend/src/api/hooks/community/useTinderCommunity.ts new file mode 100644 index 000000000..602ecb1d9 --- /dev/null +++ b/frontend/src/api/hooks/community/useTinderCommunity.ts @@ -0,0 +1,15 @@ +import { useQuery } from '@tanstack/react-query' +import axios from 'axios' +import { ApiPaths } from '../../../util/paths.ts' +import type { TinderCommunity } from '../../../util/views/tinder.ts' +import { QueryKeys } from '../queryKeys.ts' + +export const useTinderCommunity = () => { + return useQuery({ + queryKey: [QueryKeys.TINDER], + queryFn: async () => { + const response = await axios.get(ApiPaths.TINDER) + return response.data + } + }) +} diff --git a/frontend/src/api/hooks/community/useTinderInteractionSend.ts b/frontend/src/api/hooks/community/useTinderInteractionSend.ts new file mode 100644 index 000000000..55f8ace96 --- /dev/null +++ b/frontend/src/api/hooks/community/useTinderInteractionSend.ts @@ -0,0 +1,19 @@ +import { useMutation } from '@tanstack/react-query' +import axios from 'axios' +import { ApiPaths } from '../../../util/paths.ts' +import type { TinderInteractionDto } from '../../../util/views/tinder.ts' +import { QueryKeys } from '../queryKeys.ts' + +interface TinderInteractionResponse { + success: boolean +} + +export const useTinderInteractionSend = () => { + return useMutation({ + mutationKey: [QueryKeys.TINDER_INTERACTION], + mutationFn: async (data: TinderInteractionDto) => { + const res = await axios.post(ApiPaths.TINDER_INTERACTION, data) + return res.data + } + }) +} diff --git a/frontend/src/api/hooks/community/useTinderQuestions.ts b/frontend/src/api/hooks/community/useTinderQuestions.ts new file mode 100644 index 000000000..34fea2a9f --- /dev/null +++ b/frontend/src/api/hooks/community/useTinderQuestions.ts @@ -0,0 +1,15 @@ +import { useQuery } from '@tanstack/react-query' +import axios from 'axios' +import { ApiPaths } from '../../../util/paths.ts' +import type { TinderQuestion } from '../../../util/views/tinder.ts' +import { QueryKeys } from '../queryKeys.ts' + +export const useTinderQuestions = () => { + return useQuery({ + queryKey: [QueryKeys.TINDER_QUESTION], + queryFn: async () => { + const response = await axios.get(ApiPaths.TINDER_QUESTION) + return response.data + } + }) +} diff --git a/frontend/src/api/hooks/config/useConfigQuery.ts b/frontend/src/api/hooks/config/useConfigQuery.ts index 3bcae6377..2f94309ca 100644 --- a/frontend/src/api/hooks/config/useConfigQuery.ts +++ b/frontend/src/api/hooks/config/useConfigQuery.ts @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query' import axios, { AxiosError } from 'axios' import { APP_CONFIG_CACHE_TTL_SECONDS, DISABLE_APP_CONFIG_CACHE } from '../../../util/configs/environment.config.ts' import { ApiPaths } from '../../../util/paths' -import { ConfigDto } from '../../contexts/config/types' +import type { ConfigDto } from '../../contexts/config/types' import { QueryKeys } from '../queryKeys' export const useConfigQuery = () => { diff --git a/frontend/src/api/hooks/debt/useDebtQuery.ts b/frontend/src/api/hooks/debt/useDebtQuery.ts index 3a9fb97f9..e31806b7b 100644 --- a/frontend/src/api/hooks/debt/useDebtQuery.ts +++ b/frontend/src/api/hooks/debt/useDebtQuery.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { DebtDto } from '../../../util/views/debt.view.ts' +import type { DebtDto } from '../../../util/views/debt.view.ts' import { QueryKeys } from '../queryKeys' export const useDebtQuery = () => { diff --git a/frontend/src/api/hooks/event/useEventListQuery.ts b/frontend/src/api/hooks/event/useEventListQuery.ts index 5dbfc2a8b..eb0978748 100644 --- a/frontend/src/api/hooks/event/useEventListQuery.ts +++ b/frontend/src/api/hooks/event/useEventListQuery.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { EventListView } from '../../../util/views/event.view' +import type { EventListView } from '../../../util/views/event.view' import { QueryKeys } from '../queryKeys' export const useEventListQuery = () => { diff --git a/frontend/src/api/hooks/event/useEventQuery.ts b/frontend/src/api/hooks/event/useEventQuery.ts index 78c910e5e..f1a310483 100644 --- a/frontend/src/api/hooks/event/useEventQuery.ts +++ b/frontend/src/api/hooks/event/useEventQuery.ts @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { EventView } from '../../../util/views/event.view' +import type { EventView } from '../../../util/views/event.view' import { QueryKeys } from '../queryKeys' export const useEventQuery = (path: string) => { diff --git a/frontend/src/api/hooks/extra/useExtraPage.tsx b/frontend/src/api/hooks/extra/useExtraPage.tsx index 81537ed1c..105070230 100644 --- a/frontend/src/api/hooks/extra/useExtraPage.tsx +++ b/frontend/src/api/hooks/extra/useExtraPage.tsx @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { ExtraPageDto, ExtraPageView } from '../../../util/views/extraPage.view' +import type { ExtraPageDto, ExtraPageView } from '../../../util/views/extraPage.view' import { QueryKeys } from '../queryKeys' export const useExtraPage = (slug: string) => { diff --git a/frontend/src/api/hooks/form/useFormPage.tsx b/frontend/src/api/hooks/form/useFormPage.tsx index 89d17cd6f..43bf63412 100644 --- a/frontend/src/api/hooks/form/useFormPage.tsx +++ b/frontend/src/api/hooks/form/useFormPage.tsx @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { FormData } from '../../../util/views/form.view' +import type { FormData } from '../../../util/views/form.view' import { QueryKeys } from '../queryKeys' export const useFormPage = (slug: string) => { diff --git a/frontend/src/api/hooks/gallery/useHomeGallery.ts b/frontend/src/api/hooks/gallery/useHomeGallery.ts index 9fa3adf8b..90ea4c92c 100644 --- a/frontend/src/api/hooks/gallery/useHomeGallery.ts +++ b/frontend/src/api/hooks/gallery/useHomeGallery.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths.ts' -import { GalleryView } from '../../../util/views/gallery.view.ts' +import type { GalleryView } from '../../../util/views/gallery.view.ts' import { QueryKeys } from '../queryKeys.ts' export const useHomeGallery = () => { diff --git a/frontend/src/api/hooks/group-change/useGroupChangeMutation.ts b/frontend/src/api/hooks/group-change/useGroupChangeMutation.ts index 8eb55994f..024d5e015 100644 --- a/frontend/src/api/hooks/group-change/useGroupChangeMutation.ts +++ b/frontend/src/api/hooks/group-change/useGroupChangeMutation.ts @@ -3,7 +3,7 @@ import axios from 'axios' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { GroupChangeDTO } from '../../../util/views/groupChange.view' +import type { GroupChangeDTO } from '../../../util/views/groupChange.view' export function useGroupChangeMutation(onSuccess: (data: GroupChangeDTO) => void, onError: () => void) { return useMutation({ diff --git a/frontend/src/api/hooks/home/useHomeNews.tsx b/frontend/src/api/hooks/home/useHomeNews.tsx index dcb8e6ee6..693a04b00 100644 --- a/frontend/src/api/hooks/home/useHomeNews.tsx +++ b/frontend/src/api/hooks/home/useHomeNews.tsx @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { NewsArticleView } from '../../../util/views/news.view' +import type { NewsArticleView } from '../../../util/views/news.view' import { QueryKeys } from '../queryKeys' export const useHomeNews = () => { diff --git a/frontend/src/api/hooks/leaderboard/useLeaderBoardQuery.ts b/frontend/src/api/hooks/leaderboard/useLeaderBoardQuery.ts index 68d06a522..7afa37649 100644 --- a/frontend/src/api/hooks/leaderboard/useLeaderBoardQuery.ts +++ b/frontend/src/api/hooks/leaderboard/useLeaderBoardQuery.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { joinPath } from '../../../util/core-functions.util' -import { LeaderBoardView } from '../../../util/views/leaderBoardView' +import type { LeaderBoardView } from '../../../util/views/leaderBoardView' import { QueryKeys } from '../queryKeys' type TempLeaderBoardItemView = { diff --git a/frontend/src/api/hooks/location/useLocationQuery.ts b/frontend/src/api/hooks/location/useLocationQuery.ts index 22078a545..832e3e5f1 100644 --- a/frontend/src/api/hooks/location/useLocationQuery.ts +++ b/frontend/src/api/hooks/location/useLocationQuery.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { MapDataItemView } from '../../../util/views/map.view' +import type { MapDataItemView } from '../../../util/views/map.view' import { QueryKeys } from '../queryKeys' export const useLocationQuery = () => { diff --git a/frontend/src/api/hooks/news/useNewsListQuery.ts b/frontend/src/api/hooks/news/useNewsListQuery.ts index 6b67a6ede..ef518bcda 100644 --- a/frontend/src/api/hooks/news/useNewsListQuery.ts +++ b/frontend/src/api/hooks/news/useNewsListQuery.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { NewsArticleView } from '../../../util/views/news.view' +import type { NewsArticleView } from '../../../util/views/news.view' import { QueryKeys } from '../queryKeys' export const useNewsListQuery = () => { diff --git a/frontend/src/api/hooks/news/useNewsQuery.ts b/frontend/src/api/hooks/news/useNewsQuery.ts index b1b32b02f..557091ef1 100644 --- a/frontend/src/api/hooks/news/useNewsQuery.ts +++ b/frontend/src/api/hooks/news/useNewsQuery.ts @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { NewsArticleView } from '../../../util/views/news.view' +import type { NewsArticleView } from '../../../util/views/news.view' import { QueryKeys } from '../queryKeys' export const useNewsQuery = (id: string) => { diff --git a/frontend/src/api/hooks/profile/useProfileQuery.ts b/frontend/src/api/hooks/profile/useProfileQuery.ts index b883747e3..4e07e84ac 100644 --- a/frontend/src/api/hooks/profile/useProfileQuery.ts +++ b/frontend/src/api/hooks/profile/useProfileQuery.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { ProfileView } from '../../../util/views/profile.view' +import type { ProfileView } from '../../../util/views/profile.view' import { QueryKeys } from '../queryKeys' export const useProfileQuery = () => { diff --git a/frontend/src/api/hooks/qr/useQrLevelsQuery.ts b/frontend/src/api/hooks/qr/useQrLevelsQuery.ts index 16d727278..f5e5485c2 100644 --- a/frontend/src/api/hooks/qr/useQrLevelsQuery.ts +++ b/frontend/src/api/hooks/qr/useQrLevelsQuery.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { QrDto } from '../../../util/views/qrFight.view' +import type { QrDto } from '../../../util/views/qrFight.view' import { QueryKeys } from '../queryKeys' export const useQrLevelsQuery = () => { diff --git a/frontend/src/api/hooks/queryKeys.ts b/frontend/src/api/hooks/queryKeys.ts index 8cb2c082a..ea2b73a3c 100644 --- a/frontend/src/api/hooks/queryKeys.ts +++ b/frontend/src/api/hooks/queryKeys.ts @@ -1,34 +1,39 @@ -export enum QueryKeys { - ALIAS_CHANGE = 'ALIAS_CHANGE', - FORM = 'FORM', - EXTRA = 'EXTRA', - EVENTS = 'EVENTS', - CONFIG = 'CONFIG', - WARNING = 'WARNING', - NEWS = 'NEWS', - USER = 'USER', - WHO_AM_I = 'WHO_AM_I', - RACE = 'RACE', - FREESTYLE_RACE = 'FREESTYLE_RACE', - RIDDLE_HINT = 'RIDDLE_HINT', - RIDDLE_HISTORY = 'RIDDLE_HISTORY', - RIDDLE = 'RIDDLE', - RIDDLE_SUBMIT = 'RIDDLE_SUBMIT', - QR_LEVELS = 'QR_LEVELS', - LOCATIONS = 'LOCATIONS', - TASK_CATEGORIES = 'TASK_CATEGORIES', - TASK_DETAILS = 'TASK_DETAILS', - TASK_SUBMIT = 'TASK_SUBMIT', - TASKS_IN_CATEGORY = 'TASKS_IN_CATEGORY', - TEAM_LIST = 'TEAM_LIST', - TEAM_DETAILS = 'TEAM_DETAILS', - TEAM_MY = 'TEAM_MY', - LEADERBOARD = 'LEADERBOARD', - TOKEN = 'TOKEN', - COMMUNITY = 'COMMUNITY', - ORGANIZATION = 'ORGANIZATION', - ACCESS_KEY = 'ACCESS_KEY', - HOME_NEWS = 'HOME_NEWS', - DEBTS = 'DEBTS', - HOME_GALLERY = 'HOME_GALLERY' +export const QueryKeys = { + ALIAS_CHANGE: 'ALIAS_CHANGE', + FORM: 'FORM', + EXTRA: 'EXTRA', + EVENTS: 'EVENTS', + CONFIG: 'CONFIG', + WARNING: 'WARNING', + NEWS: 'NEWS', + USER: 'USER', + WHO_AM_I: 'WHO_AM_I', + RACE: 'RACE', + FREESTYLE_RACE: 'FREESTYLE_RACE', + RIDDLE_HINT: 'RIDDLE_HINT', + RIDDLE_HISTORY: 'RIDDLE_HISTORY', + RIDDLE: 'RIDDLE', + RIDDLE_SUBMIT: 'RIDDLE_SUBMIT', + QR_LEVELS: 'QR_LEVELS', + LOCATIONS: 'LOCATIONS', + TASK_CATEGORIES: 'TASK_CATEGORIES', + TASK_DETAILS: 'TASK_DETAILS', + TASK_SUBMIT: 'TASK_SUBMIT', + TASKS_IN_CATEGORY: 'TASKS_IN_CATEGORY', + TEAM_LIST: 'TEAM_LIST', + TEAM_DETAILS: 'TEAM_DETAILS', + TEAM_MY: 'TEAM_MY', + LEADERBOARD: 'LEADERBOARD', + TOKEN: 'TOKEN', + COMMUNITY: 'COMMUNITY', + ORGANIZATION: 'ORGANIZATION', + TINDER: 'TINDER', + TINDER_QUESTION: 'TINDER_QUESTION', + TINDER_ANSWERS: 'TINDER_ANSWERS', + TINDER_INTERACTION: 'TINDER_INTERACTION', + ACCESS_KEY: 'ACCESS_KEY', + HOME_NEWS: 'HOME_NEWS', + DEBTS: 'DEBTS', + HOME_GALLERY: 'HOME_GALLERY' } +export type QueryKeys = (typeof QueryKeys)[keyof typeof QueryKeys] diff --git a/frontend/src/api/hooks/race/useFreestyleRaceQuery.ts b/frontend/src/api/hooks/race/useFreestyleRaceQuery.ts index fd72234eb..ce6ace848 100644 --- a/frontend/src/api/hooks/race/useFreestyleRaceQuery.ts +++ b/frontend/src/api/hooks/race/useFreestyleRaceQuery.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { RaceView } from '../../../util/views/race.view' +import type { RaceView } from '../../../util/views/race.view' import { QueryKeys } from '../queryKeys' export const useFreestyleRaceQuery = () => { diff --git a/frontend/src/api/hooks/race/useRaceByTeamQuery.ts b/frontend/src/api/hooks/race/useRaceByTeamQuery.ts index 82d5c2c5e..bf2a6d704 100644 --- a/frontend/src/api/hooks/race/useRaceByTeamQuery.ts +++ b/frontend/src/api/hooks/race/useRaceByTeamQuery.ts @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { RaceView } from '../../../util/views/race.view' +import type { RaceView } from '../../../util/views/race.view' import { QueryKeys } from '../queryKeys' export const useRaceByTeamQuery = (teamId: string) => { diff --git a/frontend/src/api/hooks/race/useRaceQuery.ts b/frontend/src/api/hooks/race/useRaceQuery.ts index 4ba72add6..17a577d30 100644 --- a/frontend/src/api/hooks/race/useRaceQuery.ts +++ b/frontend/src/api/hooks/race/useRaceQuery.ts @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { RaceView } from '../../../util/views/race.view' +import type { RaceView } from '../../../util/views/race.view' import { QueryKeys } from '../queryKeys' export const useRaceQuery = (category: string) => { diff --git a/frontend/src/api/hooks/riddle/useRiddleDeatilsQuery.ts b/frontend/src/api/hooks/riddle/useRiddleDeatilsQuery.ts index 747a79988..1dc7af559 100644 --- a/frontend/src/api/hooks/riddle/useRiddleDeatilsQuery.ts +++ b/frontend/src/api/hooks/riddle/useRiddleDeatilsQuery.ts @@ -3,7 +3,7 @@ import axios from 'axios' import { NEW_RIDDLE_ENDPOINTS } from '../../../util/configs/environment.config' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { Riddle } from '../../../util/views/riddle.view' +import type { Riddle } from '../../../util/views/riddle.view' import { QueryKeys } from '../queryKeys' export const useRiddleDetailsQuery = (id: string) => { diff --git a/frontend/src/api/hooks/riddle/useRiddleHintQuery.ts b/frontend/src/api/hooks/riddle/useRiddleHintQuery.ts index a56a27f61..464f69070 100644 --- a/frontend/src/api/hooks/riddle/useRiddleHintQuery.ts +++ b/frontend/src/api/hooks/riddle/useRiddleHintQuery.ts @@ -3,7 +3,7 @@ import axios from 'axios' import { NEW_RIDDLE_ENDPOINTS } from '../../../util/configs/environment.config' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { Hint } from '../../../util/views/riddle.view' +import type { Hint } from '../../../util/views/riddle.view' import { QueryKeys } from '../queryKeys' export const useRiddleHintQuery = (id: string) => { diff --git a/frontend/src/api/hooks/riddle/useRiddleHistoryQuery.ts b/frontend/src/api/hooks/riddle/useRiddleHistoryQuery.ts index 58e8ad8e6..57223a48d 100644 --- a/frontend/src/api/hooks/riddle/useRiddleHistoryQuery.ts +++ b/frontend/src/api/hooks/riddle/useRiddleHistoryQuery.ts @@ -3,7 +3,7 @@ import axios from 'axios' import { NEW_RIDDLE_ENDPOINTS } from '../../../util/configs/environment.config' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { RiddleCategoryHistory } from '../../../util/views/riddle.view' +import type { RiddleCategoryHistory } from '../../../util/views/riddle.view' import { QueryKeys } from '../queryKeys.ts' export const useRiddleHistoryQuery = () => { diff --git a/frontend/src/api/hooks/riddle/useRiddleListQuery.ts b/frontend/src/api/hooks/riddle/useRiddleListQuery.ts index 5152ce3c4..6f1ce0db9 100644 --- a/frontend/src/api/hooks/riddle/useRiddleListQuery.ts +++ b/frontend/src/api/hooks/riddle/useRiddleListQuery.ts @@ -3,7 +3,7 @@ import axios from 'axios' import { NEW_RIDDLE_ENDPOINTS } from '../../../util/configs/environment.config' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { RiddleCategory } from '../../../util/views/riddle.view' +import type { RiddleCategory } from '../../../util/views/riddle.view' import { QueryKeys } from '../queryKeys' export const useRiddleListQuery = () => { diff --git a/frontend/src/api/hooks/riddle/useRiddleSkipMutation.ts b/frontend/src/api/hooks/riddle/useRiddleSkipMutation.ts index 4822690d2..4f3d87e4f 100644 --- a/frontend/src/api/hooks/riddle/useRiddleSkipMutation.ts +++ b/frontend/src/api/hooks/riddle/useRiddleSkipMutation.ts @@ -3,7 +3,7 @@ import axios from 'axios' import { NEW_RIDDLE_ENDPOINTS } from '../../../util/configs/environment.config' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { RiddleSubmissionResult } from '../../../util/views/riddle.view' +import type { RiddleSubmissionResult } from '../../../util/views/riddle.view' import { QueryKeys } from '../queryKeys' export const useRiddleSkipMutation = () => { diff --git a/frontend/src/api/hooks/riddle/useRiddleSubmitMutation.ts b/frontend/src/api/hooks/riddle/useRiddleSubmitMutation.ts index 92065e7f8..b18cafb39 100644 --- a/frontend/src/api/hooks/riddle/useRiddleSubmitMutation.ts +++ b/frontend/src/api/hooks/riddle/useRiddleSubmitMutation.ts @@ -3,7 +3,7 @@ import axios, { AxiosError } from 'axios' import { NEW_RIDDLE_ENDPOINTS } from '../../../util/configs/environment.config' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { RiddleSubmissionResult } from '../../../util/views/riddle.view' +import type { RiddleSubmissionResult } from '../../../util/views/riddle.view' import { QueryKeys } from '../queryKeys' interface RiddleSubmissionParams { diff --git a/frontend/src/api/hooks/task/useTaskCategoriesQuery.ts b/frontend/src/api/hooks/task/useTaskCategoriesQuery.ts index 78b31e09e..bc6ecb4c7 100644 --- a/frontend/src/api/hooks/task/useTaskCategoriesQuery.ts +++ b/frontend/src/api/hooks/task/useTaskCategoriesQuery.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { AllTaskCategories, TaskCategoryPreview } from '../../../util/views/task.view' +import type { AllTaskCategories, TaskCategoryPreview } from '../../../util/views/task.view' import { QueryKeys } from '../queryKeys' export const useTaskCategoriesQuery = () => { diff --git a/frontend/src/api/hooks/task/useTaskFullDetailsQuery.ts b/frontend/src/api/hooks/task/useTaskFullDetailsQuery.ts index 7659e4fdd..249204d30 100644 --- a/frontend/src/api/hooks/task/useTaskFullDetailsQuery.ts +++ b/frontend/src/api/hooks/task/useTaskFullDetailsQuery.ts @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { TaskFullDetailsView } from '../../../util/views/task.view' +import type { TaskFullDetailsView } from '../../../util/views/task.view' import { QueryKeys } from '../queryKeys' export const useTaskFullDetailsQuery = (taskId: string) => { diff --git a/frontend/src/api/hooks/task/useTaskSubmissionMutation.ts b/frontend/src/api/hooks/task/useTaskSubmissionMutation.ts index 043586f38..8a1f1c807 100644 --- a/frontend/src/api/hooks/task/useTaskSubmissionMutation.ts +++ b/frontend/src/api/hooks/task/useTaskSubmissionMutation.ts @@ -1,11 +1,11 @@ import { useMutation } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { taskSubmissionStatus } from '../../../util/views/task.view' +import type { TaskSubmissionStatus } from '../../../util/views/task.view.ts' import { QueryKeys } from '../queryKeys' interface TaskSubmissionResponse { - status: taskSubmissionStatus + status: TaskSubmissionStatus } export const useTaskSubmissionMutation = () => { diff --git a/frontend/src/api/hooks/task/useTasksInCategoryQuery.ts b/frontend/src/api/hooks/task/useTasksInCategoryQuery.ts index e2ac0b078..0cb1942ea 100644 --- a/frontend/src/api/hooks/task/useTasksInCategoryQuery.ts +++ b/frontend/src/api/hooks/task/useTasksInCategoryQuery.ts @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { joinPath } from '../../../util/core-functions.util' import { ApiPaths } from '../../../util/paths' -import { TaskCategoryFullDetails } from '../../../util/views/task.view' +import type { TaskCategoryFullDetails } from '../../../util/views/task.view' import { QueryKeys } from '../queryKeys' export const useTasksInCategoryQuery = (categoryId: string) => { diff --git a/frontend/src/api/hooks/team/actions/useTeamCreate.ts b/frontend/src/api/hooks/team/actions/useTeamCreate.ts index 966822762..1d6ba3ff3 100644 --- a/frontend/src/api/hooks/team/actions/useTeamCreate.ts +++ b/frontend/src/api/hooks/team/actions/useTeamCreate.ts @@ -1,6 +1,6 @@ import axios from 'axios' import { useState } from 'react' -import { CreateTeamDto, TeamResponses } from '../../../../util/views/team.view' +import { type CreateTeamDto, TeamResponses } from '../../../../util/views/team.view' export const useTeamCreate = (onResponse: (response: TeamResponses) => void) => { const [loading, setLoading] = useState(false) diff --git a/frontend/src/api/hooks/team/actions/useTeamEdit.ts b/frontend/src/api/hooks/team/actions/useTeamEdit.ts index 2e4e76a06..e0ef868af 100644 --- a/frontend/src/api/hooks/team/actions/useTeamEdit.ts +++ b/frontend/src/api/hooks/team/actions/useTeamEdit.ts @@ -1,6 +1,6 @@ import axios from 'axios' import { useState } from 'react' -import { TeamEditDto, TeamResponses } from '../../../../util/views/team.view' +import { type TeamEditDto, TeamResponses } from '../../../../util/views/team.view' export const useTeamEdit = (onResponse: (response: TeamResponses) => void) => { const [loading, setLoading] = useState(false) diff --git a/frontend/src/api/hooks/team/queries/useMyTeam.ts b/frontend/src/api/hooks/team/queries/useMyTeam.ts index aca206a70..ce5ce8622 100644 --- a/frontend/src/api/hooks/team/queries/useMyTeam.ts +++ b/frontend/src/api/hooks/team/queries/useMyTeam.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../../util/paths.ts' -import { OptionalTeamView } from '../../../../util/views/team.view' +import type { OptionalTeamView } from '../../../../util/views/team.view' import { QueryKeys } from '../../queryKeys.ts' export const useMyTeam = () => { diff --git a/frontend/src/api/hooks/team/queries/useTeamDetails.ts b/frontend/src/api/hooks/team/queries/useTeamDetails.ts index 07c4d0230..6a0375f7d 100644 --- a/frontend/src/api/hooks/team/queries/useTeamDetails.ts +++ b/frontend/src/api/hooks/team/queries/useTeamDetails.ts @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { joinPath } from '../../../../util/core-functions.util.ts' import { ApiPaths } from '../../../../util/paths.ts' -import { OptionalTeamView } from '../../../../util/views/team.view' +import type { OptionalTeamView } from '../../../../util/views/team.view' import { QueryKeys } from '../../queryKeys.ts' export const useTeamDetails = (id: string) => { diff --git a/frontend/src/api/hooks/team/queries/useTeamList.ts b/frontend/src/api/hooks/team/queries/useTeamList.ts index a1e4de853..6af579557 100644 --- a/frontend/src/api/hooks/team/queries/useTeamList.ts +++ b/frontend/src/api/hooks/team/queries/useTeamList.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../../util/paths.ts' -import { TeamListItemView } from '../../../../util/views/team.view' +import type { TeamListItemView } from '../../../../util/views/team.view' import { QueryKeys } from '../../queryKeys.ts' export const useTeamList = () => { diff --git a/frontend/src/api/hooks/token/useScanTokenMutation.ts b/frontend/src/api/hooks/token/useScanTokenMutation.ts index 8248e2948..74af168d4 100644 --- a/frontend/src/api/hooks/token/useScanTokenMutation.ts +++ b/frontend/src/api/hooks/token/useScanTokenMutation.ts @@ -1,7 +1,7 @@ import { useMutation } from '@tanstack/react-query' import axios from 'axios' import { joinPath } from '../../../util/core-functions.util' -import { ScanResponseView } from '../../../util/views/token.view' +import type { ScanResponseView } from '../../../util/views/token.view' export function useScanTokenMutation(onSuccess?: () => void, onError?: () => void) { return useMutation({ diff --git a/frontend/src/api/hooks/token/useTokensQuery.ts b/frontend/src/api/hooks/token/useTokensQuery.ts index 2a0f16ebb..1499b376a 100644 --- a/frontend/src/api/hooks/token/useTokensQuery.ts +++ b/frontend/src/api/hooks/token/useTokensQuery.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { ApiPaths } from '../../../util/paths' -import { TokenProgress } from '../../../util/views/token.view' +import type { TokenProgress } from '../../../util/views/token.view' import { QueryKeys } from '../queryKeys' export const useTokensQuery = () => { diff --git a/frontend/src/assets/kir-dev-logo.tsx b/frontend/src/assets/kir-dev-logo.tsx index 2b8feefe2..50792ede5 100644 --- a/frontend/src/assets/kir-dev-logo.tsx +++ b/frontend/src/assets/kir-dev-logo.tsx @@ -50,7 +50,6 @@ export const KirDevLogo = ({ ...props }: SVGProps) => ( } `} - kirdev diff --git a/frontend/src/common-components/EventIndicator.tsx b/frontend/src/common-components/EventIndicator.tsx index 4e0a7ce97..b67051853 100644 --- a/frontend/src/common-components/EventIndicator.tsx +++ b/frontend/src/common-components/EventIndicator.tsx @@ -1,4 +1,4 @@ -import { BoxProps, HStack, Text, useColorModeValue } from '@chakra-ui/react' +import { type BoxProps, HStack, Text, useColorModeValue } from '@chakra-ui/react' import { PulsingDot } from './PulsingDot' interface EventIndicatorProps extends BoxProps { diff --git a/frontend/src/common-components/LeaderboardTable.tsx b/frontend/src/common-components/LeaderboardTable.tsx index 247282f36..882509794 100644 --- a/frontend/src/common-components/LeaderboardTable.tsx +++ b/frontend/src/common-components/LeaderboardTable.tsx @@ -1,7 +1,7 @@ import { Box, Text } from '@chakra-ui/react' import { useCallback, useMemo } from 'react' import { useSearch } from '../util/useSearch' -import { LeaderBoardItemView } from '../util/views/leaderBoardView' +import type { LeaderBoardItemView } from '../util/views/leaderBoardView' import { CollapsableTableRow } from './CollapsableTableRow' import { SearchBar } from './SearchBar' diff --git a/frontend/src/common-components/LinkButton.tsx b/frontend/src/common-components/LinkButton.tsx index b65d80e4a..ba37007f8 100644 --- a/frontend/src/common-components/LinkButton.tsx +++ b/frontend/src/common-components/LinkButton.tsx @@ -1,5 +1,5 @@ -import { Button, ButtonProps } from '@chakra-ui/react' -import { FC } from 'react' +import { Button, type ButtonProps } from '@chakra-ui/react' +import type { FC } from 'react' import { useNavigate } from 'react-router' export type LinkProps = { diff --git a/frontend/src/common-components/Loading.tsx b/frontend/src/common-components/Loading.tsx index 75e17e7c4..ef3bca084 100644 --- a/frontend/src/common-components/Loading.tsx +++ b/frontend/src/common-components/Loading.tsx @@ -1,5 +1,5 @@ import { Center, Spinner } from '@chakra-ui/react' -import { ReactNode, useEffect, useState } from 'react' +import { type ReactNode, useEffect, useState } from 'react' import { useBrandColor } from '../util/core-functions.util.ts' type LoadingProps = { diff --git a/frontend/src/common-components/PresenceAlert.tsx b/frontend/src/common-components/PresenceAlert.tsx index d9f120974..e001c4117 100644 --- a/frontend/src/common-components/PresenceAlert.tsx +++ b/frontend/src/common-components/PresenceAlert.tsx @@ -1,5 +1,5 @@ import { Alert, AlertIcon } from '@chakra-ui/react' -import { FC } from 'react' +import type { FC } from 'react' import { useConfigContext } from '../api/contexts/config/ConfigContext' type PresenceAlertProps = { diff --git a/frontend/src/common-components/PulsingDot.tsx b/frontend/src/common-components/PulsingDot.tsx index 116f94a93..f89196c3c 100644 --- a/frontend/src/common-components/PulsingDot.tsx +++ b/frontend/src/common-components/PulsingDot.tsx @@ -1,4 +1,4 @@ -import { Box, BoxProps } from '@chakra-ui/react' +import { Box, type BoxProps } from '@chakra-ui/react' export function PulsingDot({ color, ...props }: BoxProps) { return ( diff --git a/frontend/src/common-components/PushNotificationHandler.tsx b/frontend/src/common-components/PushNotificationHandler.tsx index 17a50171f..b9b7830c5 100644 --- a/frontend/src/common-components/PushNotificationHandler.tsx +++ b/frontend/src/common-components/PushNotificationHandler.tsx @@ -1,7 +1,7 @@ import { ExternalLinkIcon } from '@chakra-ui/icons' import { Alert, AlertDescription, AlertTitle, Box, Button, CloseButton, useToast } from '@chakra-ui/react' -import { MessagePayload } from '@firebase/messaging' -import { FC, PropsWithChildren, useEffect } from 'react' +import type { MessagePayload } from '@firebase/messaging' +import { type FC, type PropsWithChildren, useEffect } from 'react' import { useAuthContext } from '../api/contexts/auth/useAuthContext.ts' import { useConfigContext } from '../api/contexts/config/ConfigContext.tsx' import { areNotificationsSupported, disableNotifications, getCloudMessaging, initNotifications } from '../util/configs/firebase.config.ts' diff --git a/frontend/src/common-components/QrReader.tsx b/frontend/src/common-components/QrReader.tsx index 570dd027a..2a6e95f0b 100644 --- a/frontend/src/common-components/QrReader.tsx +++ b/frontend/src/common-components/QrReader.tsx @@ -1,4 +1,4 @@ -import { BrowserCodeReader, BrowserQRCodeReader, IScannerControls } from '@zxing/browser' +import { BrowserCodeReader, BrowserQRCodeReader, type IScannerControls } from '@zxing/browser' import { useEffect, useRef } from 'react' interface QrReaderProps { diff --git a/frontend/src/common-components/SearchBar.tsx b/frontend/src/common-components/SearchBar.tsx index 81da1f958..cec4bd362 100644 --- a/frontend/src/common-components/SearchBar.tsx +++ b/frontend/src/common-components/SearchBar.tsx @@ -1,5 +1,5 @@ import { CloseIcon, SearchIcon } from '@chakra-ui/icons' -import { Input, InputGroup, InputGroupProps, InputLeftElement, InputRightElement } from '@chakra-ui/react' +import { Input, InputGroup, type InputGroupProps, InputLeftElement, InputRightElement } from '@chakra-ui/react' import { useSearch } from '../util/useSearch' interface SearchBarProps extends ReturnType, InputGroupProps {} diff --git a/frontend/src/common-components/VotingField.tsx b/frontend/src/common-components/VotingField.tsx index 7b0413c8c..dc15eff92 100644 --- a/frontend/src/common-components/VotingField.tsx +++ b/frontend/src/common-components/VotingField.tsx @@ -1,6 +1,6 @@ import { Button, Collapse, Heading, HStack, Image, Radio, Stack, Text, VStack } from '@chakra-ui/react' import { useBrandColor } from '../util/core-functions.util.ts' -import { VotingFieldOption } from '../util/views/form.view' +import type { VotingFieldOption } from '../util/views/form.view' interface VotingFieldProps { onChange: (value?: string) => void diff --git a/frontend/src/common-components/chakra-md-renderer.tsx b/frontend/src/common-components/chakra-md-renderer.tsx index a20647884..124d09852 100644 --- a/frontend/src/common-components/chakra-md-renderer.tsx +++ b/frontend/src/common-components/chakra-md-renderer.tsx @@ -20,7 +20,7 @@ import { } from '@chakra-ui/react' import deepmerge from 'deepmerge' import * as React from 'react' -import { Components } from 'react-markdown' +import type { Components } from 'react-markdown' type GetCoreProps = { children?: React.ReactNode diff --git a/frontend/src/common-components/cmsch-ui-renderer.tsx b/frontend/src/common-components/cmsch-ui-renderer.tsx index ef0ee422f..967bfefbe 100644 --- a/frontend/src/common-components/cmsch-ui-renderer.tsx +++ b/frontend/src/common-components/cmsch-ui-renderer.tsx @@ -1,6 +1,6 @@ import { Divider, ListItem, OrderedList, Table, TableContainer, UnorderedList } from '@chakra-ui/react' -import { PropsWithChildren, ReactNode } from 'react' -import { Components } from 'react-markdown' +import type { PropsWithChildren, ReactNode } from 'react' +import type { Components } from 'react-markdown' import { CLIENT_BASE_URL } from '../util/configs/environment.config' import { useBrandColor } from '../util/core-functions.util.ts' import ChakraUIRenderer from './chakra-md-renderer' diff --git a/frontend/src/common-components/footer/OrganizerLogo.tsx b/frontend/src/common-components/footer/OrganizerLogo.tsx index f6edc8364..250a7b39b 100644 --- a/frontend/src/common-components/footer/OrganizerLogo.tsx +++ b/frontend/src/common-components/footer/OrganizerLogo.tsx @@ -17,7 +17,7 @@ export function OrganizerLogo({ imageSrc, minimalistic, websiteUrl, contactUrl, const color = useBrandColor(500, 500) return ( - + {imageSrc && } {!minimalistic && hasUrls && ( <> diff --git a/frontend/src/common-components/layout/AppBackground.tsx b/frontend/src/common-components/layout/AppBackground.tsx index e5aff511f..cd64c195f 100644 --- a/frontend/src/common-components/layout/AppBackground.tsx +++ b/frontend/src/common-components/layout/AppBackground.tsx @@ -1,5 +1,5 @@ import { Box, useColorModeValue } from '@chakra-ui/react' -import { FC, PropsWithChildren } from 'react' +import type { FC, PropsWithChildren } from 'react' import { usePersistentStyleSetting } from '../../util/configs/themeStyle.config.ts' export const AppBackground: FC = ({ children }) => { diff --git a/frontend/src/common-components/layout/CmschContainer.tsx b/frontend/src/common-components/layout/CmschContainer.tsx index 55405c073..377afee94 100644 --- a/frontend/src/common-components/layout/CmschContainer.tsx +++ b/frontend/src/common-components/layout/CmschContainer.tsx @@ -1,4 +1,4 @@ -import { Card, CardBody, CardHeader, CardProps, Heading, useColorModeValue } from '@chakra-ui/react' +import { Card, CardBody, CardHeader, type CardProps, Heading, useColorModeValue } from '@chakra-ui/react' import { useStyle } from '../../api/contexts/config/ConfigContext.tsx' export interface CmschContainerProps extends CardProps { diff --git a/frontend/src/common-components/layout/CmschLayout.tsx b/frontend/src/common-components/layout/CmschLayout.tsx index 1a43df767..d8325ce87 100644 --- a/frontend/src/common-components/layout/CmschLayout.tsx +++ b/frontend/src/common-components/layout/CmschLayout.tsx @@ -1,6 +1,5 @@ import { Box, Flex } from '@chakra-ui/react' -import { PropsWithChildren, useEffect } from 'react' -import { Helmet } from 'react-helmet-async' +import { type PropsWithChildren, useEffect } from 'react' import { Navigate } from 'react-router' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useServiceContext } from '../../api/contexts/service/ServiceContext' @@ -28,7 +27,6 @@ export const CmschLayout = ({ children }: PropsWithChildren) => { return ( <> - diff --git a/frontend/src/common-components/layout/CmschPage.tsx b/frontend/src/common-components/layout/CmschPage.tsx index fb9ee2f50..e88e37fbe 100644 --- a/frontend/src/common-components/layout/CmschPage.tsx +++ b/frontend/src/common-components/layout/CmschPage.tsx @@ -1,16 +1,17 @@ import { Navigate, Outlet } from 'react-router' import { useAuthContext } from '../../api/contexts/auth/useAuthContext' import { LoadingPage } from '../../pages/loading/loading.page' +import { Title } from '../../util/TitleProvider.tsx' import { RoleType } from '../../util/views/profile.view' import { LoginRequired } from '../LoginRequired' -import { CmschContainer, CmschContainerProps } from './CmschContainer' +import { CmschContainer, type CmschContainerProps } from './CmschContainer' interface CmschPageProps extends CmschContainerProps { loginRequired?: boolean minRole?: RoleType } -export const CmschPage = ({ loginRequired, children, minRole, ...props }: CmschPageProps) => { +export const CmschPage = ({ children, loginRequired, minRole, title, ...props }: CmschPageProps) => { const { authInfo, authInfoLoading, isLoggedIn } = useAuthContext() if (loginRequired) { if (authInfoLoading) return @@ -24,6 +25,7 @@ export const CmschPage = ({ loginRequired, children, minRole, ...props }: CmschP return ( + <Outlet /> {children} </CmschContainer> diff --git a/frontend/src/common-components/map/MapContent.tsx b/frontend/src/common-components/map/MapContent.tsx index 6c33068c3..a915514f1 100644 --- a/frontend/src/common-components/map/MapContent.tsx +++ b/frontend/src/common-components/map/MapContent.tsx @@ -3,7 +3,7 @@ import { Map, Marker, ZoomControl } from 'pigeon-maps' import { useEffect, useState } from 'react' import { useGeolocated } from 'react-geolocated' import { l } from '../../util/language' -import { MapDataItemView, MapMarkerShape } from '../../util/views/map.view' +import { type MapDataItemView, MapMarkerShape } from '../../util/views/map.view' import { MapMarker } from './MapMarker' interface MapContentProps { diff --git a/frontend/src/common-components/map/MapMarker.tsx b/frontend/src/common-components/map/MapMarker.tsx index d4eb99720..dd35ea324 100644 --- a/frontend/src/common-components/map/MapMarker.tsx +++ b/frontend/src/common-components/map/MapMarker.tsx @@ -1,5 +1,5 @@ -import { Box, BoxProps, Center, Text, useColorModeValue, VStack } from '@chakra-ui/react' -import { FunctionComponent } from 'react' +import { Box, type BoxProps, Center, Text, useColorModeValue, VStack } from '@chakra-ui/react' +import type { FunctionComponent } from 'react' import { getTextColorFromLuminance } from '../../util/color.utils' import { useBrandColor } from '../../util/core-functions.util.ts' import { MapMarkerIcons, MapMarkerShape } from '../../util/views/map.view' diff --git a/frontend/src/common-components/navigation/ColorModeSwitcher.tsx b/frontend/src/common-components/navigation/ColorModeSwitcher.tsx index 971c122ad..80bcf316c 100644 --- a/frontend/src/common-components/navigation/ColorModeSwitcher.tsx +++ b/frontend/src/common-components/navigation/ColorModeSwitcher.tsx @@ -1,5 +1,5 @@ import { MoonIcon, SunIcon } from '@chakra-ui/icons' -import { IconButton, IconButtonProps, useColorMode, useColorModeValue } from '@chakra-ui/react' +import { IconButton, type IconButtonProps, useColorMode, useColorModeValue } from '@chakra-ui/react' import { useConfigContext } from '../../api/contexts/config/ConfigContext' type Props = Omit<IconButtonProps, 'aria-label'> diff --git a/frontend/src/common-components/navigation/LinkComponent.tsx b/frontend/src/common-components/navigation/LinkComponent.tsx index a4338024d..125cd5d20 100644 --- a/frontend/src/common-components/navigation/LinkComponent.tsx +++ b/frontend/src/common-components/navigation/LinkComponent.tsx @@ -1,4 +1,4 @@ -import { PropsWithChildren } from 'react' +import type { PropsWithChildren } from 'react' import { Link } from 'react-router' interface LinkComponentProps extends PropsWithChildren { diff --git a/frontend/src/common-components/navigation/desktop/ChildNavItem.tsx b/frontend/src/common-components/navigation/desktop/ChildNavItem.tsx index b3a0a63be..63fbccec4 100644 --- a/frontend/src/common-components/navigation/desktop/ChildNavItem.tsx +++ b/frontend/src/common-components/navigation/desktop/ChildNavItem.tsx @@ -1,6 +1,6 @@ import { Box, Flex, Icon, Stack, Text } from '@chakra-ui/react' import { FaChevronRight } from 'react-icons/fa' -import { Menu } from '../../../api/contexts/config/types' +import type { Menu } from '../../../api/contexts/config/types' import { useBrandColor } from '../../../util/core-functions.util.ts' import LinkComponent from '../LinkComponent' diff --git a/frontend/src/common-components/navigation/desktop/NavItemNoChildren.tsx b/frontend/src/common-components/navigation/desktop/NavItemNoChildren.tsx index d435d5910..b62de344b 100644 --- a/frontend/src/common-components/navigation/desktop/NavItemNoChildren.tsx +++ b/frontend/src/common-components/navigation/desktop/NavItemNoChildren.tsx @@ -1,5 +1,5 @@ import { Box, chakra } from '@chakra-ui/react' -import { Menu } from '../../../api/contexts/config/types' +import type { Menu } from '../../../api/contexts/config/types' import { useBrandColor } from '../../../util/core-functions.util.ts' import LinkComponent from '../LinkComponent' diff --git a/frontend/src/common-components/navigation/desktop/NavItemWithChildren.tsx b/frontend/src/common-components/navigation/desktop/NavItemWithChildren.tsx index f25ccc4c4..d68e5f137 100644 --- a/frontend/src/common-components/navigation/desktop/NavItemWithChildren.tsx +++ b/frontend/src/common-components/navigation/desktop/NavItemWithChildren.tsx @@ -1,6 +1,6 @@ import { Box, chakra, HStack, Icon, Popover, PopoverContent, PopoverTrigger, Stack, useColorModeValue } from '@chakra-ui/react' import { FaChevronDown } from 'react-icons/fa' -import { Menu } from '../../../api/contexts/config/types' +import type { Menu } from '../../../api/contexts/config/types' import { useBrandColor } from '../../../util/core-functions.util.ts' import LinkComponent from '../LinkComponent' import { ChildNavItem } from './ChildNavItem' diff --git a/frontend/src/common-components/navigation/mobile/NavItemNoChildren.tsx b/frontend/src/common-components/navigation/mobile/NavItemNoChildren.tsx index 18b6ce6c8..1fd9bffa6 100644 --- a/frontend/src/common-components/navigation/mobile/NavItemNoChildren.tsx +++ b/frontend/src/common-components/navigation/mobile/NavItemNoChildren.tsx @@ -1,5 +1,5 @@ import { chakra, Flex } from '@chakra-ui/react' -import { Menu } from '../../../api/contexts/config/types' +import type { Menu } from '../../../api/contexts/config/types' import LinkComponent from '../LinkComponent' type Props = { diff --git a/frontend/src/common-components/navigation/mobile/NavItemWithChildren.tsx b/frontend/src/common-components/navigation/mobile/NavItemWithChildren.tsx index 8cf558873..bf2c45cee 100644 --- a/frontend/src/common-components/navigation/mobile/NavItemWithChildren.tsx +++ b/frontend/src/common-components/navigation/mobile/NavItemWithChildren.tsx @@ -1,7 +1,7 @@ import { Collapse, Flex, Icon, Stack, Text, useColorModeValue, useDisclosure } from '@chakra-ui/react' import { FaChevronDown } from 'react-icons/fa' import { Link } from 'react-router' -import { Menu } from '../../../api/contexts/config/types' +import type { Menu } from '../../../api/contexts/config/types' import LinkComponent from '../LinkComponent' type Props = { diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 64b1e2ef9..15a746897 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -6,7 +6,6 @@ import { BrowserRouter } from 'react-router' import { AuthProvider } from './api/contexts/auth/AuthContext' import { createRoot } from 'react-dom/client' -import { HelmetProvider } from 'react-helmet-async' import { App } from './App' import { ConfigProvider } from './api/contexts/config/ConfigContext' import { ServiceProvider } from './api/contexts/service/ServiceContext' @@ -26,22 +25,20 @@ root.render( <ThemeConfig> <AppBackground> <QueryClientProvider client={queryClient}> - <HelmetProvider> - <BrowserRouter> - <ServiceProvider> - <ErrorBoundary> - <ConfigProvider> - <AuthProvider> - <PushNotificationHandler> - <App /> - <ReactQueryDevtools /> - </PushNotificationHandler> - </AuthProvider> - </ConfigProvider> - </ErrorBoundary> - </ServiceProvider> - </BrowserRouter> - </HelmetProvider> + <BrowserRouter> + <ServiceProvider> + <ErrorBoundary> + <ConfigProvider> + <AuthProvider> + <PushNotificationHandler> + <App /> + <ReactQueryDevtools /> + </PushNotificationHandler> + </AuthProvider> + </ConfigProvider> + </ErrorBoundary> + </ServiceProvider> + </BrowserRouter> </QueryClientProvider> </AppBackground> </ThemeConfig> diff --git a/frontend/src/pages/access-key/accessKey.page.tsx b/frontend/src/pages/access-key/accessKey.page.tsx index 8c7efd6bf..3764d7137 100644 --- a/frontend/src/pages/access-key/accessKey.page.tsx +++ b/frontend/src/pages/access-key/accessKey.page.tsx @@ -12,8 +12,7 @@ import { useToast, VStack } from '@chakra-ui/react' -import { FormEvent, useState } from 'react' -import { Helmet } from 'react-helmet-async' +import { type SubmitEvent, useState } from 'react' import { useNavigate } from 'react-router' import { useAuthContext } from '../../api/contexts/auth/useAuthContext' import { useAccessKeyMutation } from '../../api/hooks/access-key/useAccessKeyMutation' @@ -25,7 +24,7 @@ import { PageStatus } from '../../common-components/PageStatus' import { useBrandColor } from '../../util/core-functions.util.ts' import { l } from '../../util/language' import { AbsolutePaths } from '../../util/paths' -import { AccessKeyResponse } from '../../util/views/accessKey' +import type { AccessKeyResponse } from '../../util/views/accessKey' function AccessKeyPage() { const { refetch } = useAuthContext() @@ -55,7 +54,7 @@ function AccessKeyPage() { const mutation = useAccessKeyMutation(onData, onError) const query = useAccessKey() - const onSubmit = (e: FormEvent<HTMLFormElement>) => { + const onSubmit = (e: SubmitEvent<HTMLFormElement>) => { e.preventDefault() if (value) { mutation.mutate({ key: value }) @@ -69,8 +68,7 @@ function AccessKeyPage() { } return ( - <CmschPage> - <Helmet title={query.data.title} /> + <CmschPage title={query.data.title}> <Heading as="h1" variant="main-title"> {query.data.title} </Heading> diff --git a/frontend/src/pages/communities/community.page.tsx b/frontend/src/pages/communities/community.page.tsx index fd9716c04..609a87d9a 100644 --- a/frontend/src/pages/communities/community.page.tsx +++ b/frontend/src/pages/communities/community.page.tsx @@ -1,5 +1,4 @@ import { Image } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { useParams } from 'react-router' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useCommunity } from '../../api/hooks/community/useCommunity' @@ -10,12 +9,12 @@ import { DataSheet } from './components/DataSheet' import { Frame } from './components/Frame' export default function CommunityPage() { - const config = useConfigContext()?.components?.communities + const communities = useConfigContext()?.components?.communities const params = useParams() const { data, isLoading, isError } = useCommunity(params.id || 'UNKNOWN') const breadcrumbItems = [ { - title: config?.title, + title: communities?.title, to: '/community' }, { @@ -23,14 +22,12 @@ export default function CommunityPage() { } ] - if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={config?.title} /> + if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={communities?.title} /> return ( - <CmschPage> - <Helmet title={data.name} /> + <CmschPage title={data.name}> <CustomBreadcrumb items={breadcrumbItems} mt={5} /> <DataSheet organization={data} /> - {data.videoIds?.map((id) => ( <Frame key={id} id={id} /> ))} diff --git a/frontend/src/pages/communities/communityList.page.tsx b/frontend/src/pages/communities/communityList.page.tsx index f2439dd9d..c6460c683 100644 --- a/frontend/src/pages/communities/communityList.page.tsx +++ b/frontend/src/pages/communities/communityList.page.tsx @@ -1,24 +1,24 @@ import { SearchIcon } from '@chakra-ui/icons' import { Box, Heading, Input, InputGroup, InputLeftElement } from '@chakra-ui/react' -import { createRef, useEffect, useState } from 'react' -import { Helmet } from 'react-helmet-async' +import { useEffect, useRef, useState } from 'react' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useCommunityList } from '../../api/hooks/community/useCommunityList' +import { ComponentUnavailable } from '../../common-components/ComponentUnavailable.tsx' import { CmschPage } from '../../common-components/layout/CmschPage' import Markdown from '../../common-components/Markdown.tsx' import { PageStatus } from '../../common-components/PageStatus' import { AbsolutePaths } from '../../util/paths' -import { Community } from '../../util/views/organization' +import type { Community } from '../../util/views/organization' import { CardListItem } from './components/CardListItem' export default function CommunityListPage() { - const config = useConfigContext()?.components?.communities + const communities = useConfigContext()?.components?.communities const { data, isLoading, isError } = useCommunityList() const [filteredCommunities, setFilteredCommunities] = useState<Community[]>(data || []) - const inputRef = createRef<HTMLInputElement>() + const inputRef = useRef<HTMLInputElement>(null) const handleInput = () => { - const search = inputRef?.current?.value.toLowerCase() + const search = inputRef.current?.value?.toLowerCase() || '' if (!data) { setFilteredCommunities([]) } else if (!search) setFilteredCommunities(data) @@ -27,7 +27,7 @@ export default function CommunityListPage() { data.filter((c) => { if (c.searchKeywords?.find((s) => s.toLowerCase().includes(search))) return true if (c.interests?.find((i) => i.toLowerCase().includes(search))) return true - return c.name.toLocaleLowerCase().includes(search) + return c.name.toLowerCase().includes(search) }) ) } @@ -38,15 +38,16 @@ export default function CommunityListPage() { setFilteredCommunities(data) if (inputRef.current) inputRef.current.value = '' } - }, [data, inputRef]) + }, [data]) - if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={config?.title} /> + if (!communities) return <ComponentUnavailable /> + + if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={communities?.title} /> return ( - <CmschPage> - <Helmet title={config?.title} /> + <CmschPage title={communities?.title}> <Heading as="h1" variant="main-title"> - {config?.title} + {communities?.title} </Heading> <InputGroup mt={5}> <InputLeftElement h="100%"> @@ -61,9 +62,9 @@ export default function CommunityListPage() { autoFocus={true} /> </InputGroup> - {config?.description && ( + {communities?.description && ( <Box mt={5}> - <Markdown text={config?.description} /> + <Markdown text={communities?.description} /> </Box> )} {filteredCommunities?.map((community) => ( diff --git a/frontend/src/pages/communities/components/CardListItem.tsx b/frontend/src/pages/communities/components/CardListItem.tsx index 70de9240a..330f4b8e4 100644 --- a/frontend/src/pages/communities/components/CardListItem.tsx +++ b/frontend/src/pages/communities/components/CardListItem.tsx @@ -1,7 +1,7 @@ import { ChevronRightIcon } from '@chakra-ui/icons' import { Box, Heading, HStack, Image, Spacer, Text, useColorModeValue, VStack } from '@chakra-ui/react' import { Link } from 'react-router' -import { Organization } from '../../../util/views/organization' +import type { Organization } from '../../../util/views/organization' type CardListItemProps = { data: Organization @@ -20,28 +20,44 @@ export const CardListItem = ({ data, link }: CardListItemProps) => { <Link to={link}> <Box borderRadius="lg" - padding={4} + padding={{ base: 3, md: 4 }} backgroundColor={useColorModeValue('gray.100', 'gray.700')} - marginTop={5} + marginTop={{ base: 3, md: 5 }} transition="transform .2s ease-in-out" _hover={{ transform: 'translateX(0.5em)' }} > - <HStack spacing={4}> + <HStack spacing={{ base: 3, md: 4 }}> {logoSource && ( - <Image src={logoSource} alt={data.name} minW={{ base: 12, sm: 16 }} boxSize={{ base: 12, sm: 16 }} objectFit="contain" /> + <Box + bg="white" + borderRadius="full" + padding={{ base: 2, md: 4 }} + display="flex" + alignItems="center" + justifyContent="center" + flexShrink={0} + > + <Image + src={logoSource} + alt={data.name} + minW={{ base: 10, sm: 12, md: 16 }} + boxSize={{ base: 10, sm: 12, md: 16 }} + objectFit="contain" + /> + </Box> )} - <VStack align="flex-start" overflow="hidden"> - <Heading as="h3" size="md" marginY={0} maxWidth="100%"> + <VStack align="flex-start" overflow="hidden" flex={1} spacing={{ base: 0, md: 1 }}> + <Heading as="h3" size={{ base: 'sm', md: 'md' }} marginY={0} maxWidth="100%" noOfLines={2}> {data.name} </Heading> {data.shortDescription && ( - <Text maxWidth="100%" display={['none', 'block']}> + <Text maxWidth="100%" display={['none', 'none', 'block']} fontSize="sm" noOfLines={2}> {data.shortDescription} </Text> )} </VStack> <Spacer /> - <ChevronRightIcon boxSize={{ base: 10, md: 16 }} color="gray.300" /> + <ChevronRightIcon boxSize={{ base: 6, md: 10, lg: 16 }} color="gray.300" flexShrink={0} /> </HStack> </Box> </Link> diff --git a/frontend/src/pages/communities/components/DataSheet.tsx b/frontend/src/pages/communities/components/DataSheet.tsx index 109d939a9..4e1734e53 100644 --- a/frontend/src/pages/communities/components/DataSheet.tsx +++ b/frontend/src/pages/communities/components/DataSheet.tsx @@ -1,13 +1,13 @@ import { EditIcon, LinkIcon } from '@chakra-ui/icons' import { Box, Flex, Heading, HStack, Image, Link, Tag, useColorModeValue, VStack, Wrap } from '@chakra-ui/react' -import { FC, ReactNode } from 'react' +import type { FC, ReactNode } from 'react' import { FaAt, FaBuilding, FaBusinessTime, FaFacebook, FaInstagram, FaUsers } from 'react-icons/fa' import { LinkButton } from '../../../common-components/LinkButton' import Markdown from '../../../common-components/Markdown' import { joinPath, useBrandColor } from '../../../util/core-functions.util' import { AbsolutePaths } from '../../../util/paths' -import { Community, Organization } from '../../../util/views/organization' +import type { Community, Organization } from '../../../util/views/organization' type DataSheetProps = { organization: Organization | Community diff --git a/frontend/src/pages/communities/components/Frame.tsx b/frontend/src/pages/communities/components/Frame.tsx index 313d4cc76..09ca229f6 100644 --- a/frontend/src/pages/communities/components/Frame.tsx +++ b/frontend/src/pages/communities/components/Frame.tsx @@ -1,5 +1,5 @@ import { Box } from '@chakra-ui/react' -import { FC } from 'react' +import type { FC } from 'react' type FrameProps = { id: string diff --git a/frontend/src/pages/communities/components/TinderCard.tsx b/frontend/src/pages/communities/components/TinderCard.tsx new file mode 100644 index 000000000..2aa21f9fd --- /dev/null +++ b/frontend/src/pages/communities/components/TinderCard.tsx @@ -0,0 +1,130 @@ +import { Box, Heading, HStack, IconButton, Image, Text, useColorModeValue, VStack } from '@chakra-ui/react' +import { FaHeart, FaTimes } from 'react-icons/fa' + +import type { TinderCommunity } from '../../../util/views/tinder' + +type Props = { + data: TinderCommunity + depth?: number + onLike?: (c: TinderCommunity) => void + onDislike?: (c: TinderCommunity) => void + className?: string +} + +export const TinderCard = ({ data, depth = 0, onLike, onDislike, className }: Props) => { + // Prefer the typed `TinderCommunity` fields and use optional chaining/fallbacks. + const title = data?.name || 'Unknown community' + const description = data?.shortDescription || '' + const image = data?.logo || '' + const tags = data?.tinderAnswers || [] + const tagColor = useColorModeValue('cyan.100', 'cyan.700') + + const bg = useColorModeValue('white', 'gray.800') + const infoColor = useColorModeValue('gray.600', 'gray.300') + const placeholderBg = useColorModeValue('#efefef', '#2A2A2A') + + return ( + <Box + className={className} + role="article" + aria-label={title} + data-depth={depth} + bg={bg} + w={{ base: 'calc(100vw - 2rem)', sm: '380px', md: '416px' }} + maxW="416px" + h={{ base: 'min(598px, calc(100vh - 200px))', md: '598px' }} + borderRadius="16px" /* ~12 * 1.3 */ + boxShadow="lg" + overflow="hidden" + sx={{ WebkitOverflowScrolling: 'touch' }} + userSelect="none" + transition="transform 160ms ease" + display="flex" + flexDirection="column" + > + {image ? ( + <Image src={image} alt={title} width="100%" height="100%" marginTop={{ base: 4, md: 10 }} objectFit="contain" /> + ) : ( + <Box bg={placeholderBg} width="100%" height="100%" /> + )} + + {/* VStack becomes a column flex container. The top part scrolls, buttons stay outside the scroll area. */} + <VStack align="stretch" p={{ base: 2, md: 3 }} flex="1" display="flex" flexDirection="column"> + <HStack justify="space-around" mt={2}> + <Box flex="1" overflowY="auto"> + <Heading as="h3" size={{ base: 'sm', md: 'md' }}> + {title} + </Heading> + + <Text fontSize={{ base: 'xs', md: 'sm' }} color={infoColor} mt={2}> + Alapítva: {data?.established ?? '—'} + <br /> + Reszort: {data?.resortName ?? '—'} + </Text> + + <Box + mt={2} + /* let the description area size naturally inside the scrollable box */ + color={useColorModeValue('#555', '#ccc')} + fontSize={{ base: 'xs', md: 'sm' }} + lineHeight="1.4" + aria-hidden={description.length === 0} + > + {description ? <Text whiteSpace="normal">{description}</Text> : <Text color="gray.400">No description</Text>} + </Box> + </Box> + + <Box> + {tags.length > 0 && ( + <VStack align="flex-start" spacing={1} mt={2}> + {tags.slice(0, 5).map((tag, index) => ( + <Box key={index} bg={tagColor} px={2} py={1} borderRadius="md" fontSize={{ base: '2xs', md: 'xs' }}> + {tag} + </Box> + ))} + </VStack> + )} + </Box> + </HStack> + + {/* Buttons stay outside the scrollable Box so they're always visible */} + <HStack justify="space-around" mt={2}> + <IconButton + data-no-drag + onPointerDown={(e) => e.stopPropagation()} + aria-label="Dislike" + title="Dislike" + icon={<FaTimes />} + onClick={() => onDislike && onDislike(data)} + variant="outline" + colorScheme="red" + borderRadius="full" + w={{ base: '48px', md: '56px' }} + h={{ base: '48px', md: '56px' }} + minW={{ base: '48px', md: '56px' }} + minH={{ base: '48px', md: '56px' }} + p={0} + /> + + <IconButton + data-no-drag + onPointerDown={(e) => e.stopPropagation()} + aria-label="Like" + title="Like" + icon={<FaHeart />} + onClick={() => onLike && onLike(data)} + bg="cyan.500" + color="white" + _hover={{ bg: 'cyan.600' }} + borderRadius="full" + w={{ base: '48px', md: '56px' }} + h={{ base: '48px', md: '56px' }} + minW={{ base: '48px', md: '56px' }} + minH={{ base: '48px', md: '56px' }} + p={0} + /> + </HStack> + </VStack> + </Box> + ) +} diff --git a/frontend/src/pages/communities/likedCommunityList.page.tsx b/frontend/src/pages/communities/likedCommunityList.page.tsx new file mode 100644 index 000000000..7b7619107 --- /dev/null +++ b/frontend/src/pages/communities/likedCommunityList.page.tsx @@ -0,0 +1,71 @@ +import { Box, Button, Flex, Heading, Text } from '@chakra-ui/react' +import { Link } from 'react-router' +import { useConfigContext } from '../../api/contexts/config/ConfigContext.tsx' +import { useTinderCommunity } from '../../api/hooks/community/useTinderCommunity.ts' +import { ComponentUnavailable } from '../../common-components/ComponentUnavailable.tsx' +import { CmschPage } from '../../common-components/layout/CmschPage.tsx' +import { PageStatus } from '../../common-components/PageStatus.tsx' +import { AbsolutePaths } from '../../util/paths.ts' +import { TinderStatus } from '../../util/views/tinder.ts' +import { CardListItem } from './components/CardListItem.tsx' + +export default function LikedCommunityListPage() { + const communities = useConfigContext()?.components?.communities + const { data, isLoading, isError } = useTinderCommunity() + + if (!communities || !communities.tinderEnabled) return <ComponentUnavailable /> + if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} /> + + const likedCommunities = data.filter((c) => c.status === TinderStatus.LIKED) + + return ( + <CmschPage loginRequired={true} title="Kedvelt közösségek"> + <Box w="100%" mx="auto" px={{ base: 2, md: 4 }}> + <Box + position="relative" + mb={6} + display="flex" + flexDirection={{ base: 'column', sm: 'row' }} + alignItems={{ base: 'center', md: 'flex-start' }} + gap={4} + > + <Heading as="h1" variant="main-title" textAlign={{ base: 'center', sm: 'left' }} flex={{ base: 'none', sm: 1 }}> + Kör tinder + </Heading> + <Flex + flexDirection={{ base: 'column', md: 'row' }} + gap={3} + width={{ base: 'full', sm: 'auto' }} + position={{ base: 'relative', sm: 'absolute' }} + top={{ base: 'auto', sm: '50%' }} + right={{ base: 'auto', sm: 2 }} + transform={{ base: 'none', sm: 'translateY(-30%)', md: 'translateY(-50%)' }} + > + <Button + as={Link} + to={`${AbsolutePaths.TINDER}/community`} + size={{ base: 'md', md: 'lg' }} + aria-label="Tinder-matches-button" + width={{ base: 'full', sm: 'auto' }} + > + Tinder + </Button> + <Button as={Link} to={`${AbsolutePaths.COMMUNITY}`} size={{ base: 'md', md: 'lg' }} width={{ base: 'full', sm: 'auto' }}> + Összes kör megtekintése + </Button> + </Flex> + </Box> + </Box> + {likedCommunities.length === 0 && ( + <Box px={{ base: 4, md: 0 }} py={8} textAlign="center"> + <Text>Nem kedveltél még egy kört sem. A fenti Tinder gombra kattintva kereshetsz a még nem látott körök közt.</Text> + </Box> + )} + <Box px={{ base: 2, md: 0 }}> + {likedCommunities?.map((community) => ( + <CardListItem key={community.id} data={community} link={`${AbsolutePaths.COMMUNITY}/${community.id}`} /> + ))} + </Box> + </CmschPage> + ) +} diff --git a/frontend/src/pages/communities/organization.page.tsx b/frontend/src/pages/communities/organization.page.tsx index c6ee2f832..be56eb388 100644 --- a/frontend/src/pages/communities/organization.page.tsx +++ b/frontend/src/pages/communities/organization.page.tsx @@ -1,5 +1,4 @@ import { Image } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { useParams } from 'react-router' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useOrganization } from '../../api/hooks/community/useOrganization' @@ -11,13 +10,13 @@ import { DataSheet } from './components/DataSheet' import { Frame } from './components/Frame' export default function OrganizationPage() { - const config = useConfigContext()?.components?.communities + const communities = useConfigContext()?.components?.communities const params = useParams() const { data, isLoading, isError } = useOrganization(params.id || 'UNKNOWN') const breadcrumbItems = [ { - title: config?.titleResort, + title: communities?.titleResort, to: AbsolutePaths.ORGANIZATION }, { @@ -25,11 +24,10 @@ export default function OrganizationPage() { } ] - if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={config?.titleResort} /> + if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={communities?.titleResort} /> return ( - <CmschPage> - <Helmet title={data.name} /> + <CmschPage title={data.name}> <CustomBreadcrumb items={breadcrumbItems} mt={5} /> <DataSheet organization={data} /> diff --git a/frontend/src/pages/communities/organizationList.page.tsx b/frontend/src/pages/communities/organizationList.page.tsx index a001b5e59..9d644c42b 100644 --- a/frontend/src/pages/communities/organizationList.page.tsx +++ b/frontend/src/pages/communities/organizationList.page.tsx @@ -1,18 +1,17 @@ import { SearchIcon } from '@chakra-ui/icons' import { Box, Heading, Input, InputGroup, InputLeftElement } from '@chakra-ui/react' import { createRef, useEffect, useState } from 'react' -import { Helmet } from 'react-helmet-async' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useOrganizationList } from '../../api/hooks/community/useOrganizationList' import { CmschPage } from '../../common-components/layout/CmschPage' import Markdown from '../../common-components/Markdown.tsx' import { PageStatus } from '../../common-components/PageStatus' import { AbsolutePaths } from '../../util/paths' -import { Organization } from '../../util/views/organization' +import type { Organization } from '../../util/views/organization' import { CardListItem } from './components/CardListItem' export default function OrganizationListPage() { - const config = useConfigContext()?.components?.communities + const communities = useConfigContext()?.components?.communities const { data, isLoading, isError } = useOrganizationList() const [filteredOrganizations, setFilteredOrganizations] = useState<Organization[]>(data || []) const inputRef = createRef<HTMLInputElement>() @@ -38,13 +37,12 @@ export default function OrganizationListPage() { } }, [data, inputRef]) - if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={config?.title} /> + if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={communities?.title} /> return ( - <CmschPage> - <Helmet title={config?.titleResort} /> + <CmschPage title={communities?.titleResort}> <Heading as="h1" variant="main-title"> - {config?.titleResort} + {communities?.titleResort} </Heading> <InputGroup mt={5}> <InputLeftElement h="100%"> @@ -59,9 +57,9 @@ export default function OrganizationListPage() { autoFocus={true} /> </InputGroup> - {config?.descriptionResort && ( + {communities?.descriptionResort && ( <Box mt={5}> - <Markdown text={config?.descriptionResort} /> + <Markdown text={communities?.descriptionResort} /> </Box> )} {filteredOrganizations.map((organization) => ( diff --git a/frontend/src/pages/communities/tinder.page.tsx b/frontend/src/pages/communities/tinder.page.tsx new file mode 100644 index 000000000..ae04805e7 --- /dev/null +++ b/frontend/src/pages/communities/tinder.page.tsx @@ -0,0 +1,438 @@ +import { Box, Button, Flex, Heading, Text } from '@chakra-ui/react' +import React, { useRef, useState } from 'react' +import { Link } from 'react-router' +import { useConfigContext } from '../../api/contexts/config/ConfigContext.tsx' +import { useTinderCommunity } from '../../api/hooks/community/useTinderCommunity.ts' +import { useTinderInteractionSend } from '../../api/hooks/community/useTinderInteractionSend.ts' +import { ComponentUnavailable } from '../../common-components/ComponentUnavailable.tsx' +import { CmschPage } from '../../common-components/layout/CmschPage.tsx' +import { PageStatus } from '../../common-components/PageStatus.tsx' +import { AbsolutePaths } from '../../util/paths' +import { type TinderCommunity } from '../../util/views/tinder.ts' +import { TinderCard } from './components/TinderCard' + +const SWIPE_THRESHOLD = 220 + +const TinderPage = () => { + const config = useConfigContext()?.components + const component = config?.communities + + const { data: communities, isLoading, isError } = useTinderCommunity() + const interact = useTinderInteractionSend() + + const [swipe, setSwipe] = useState<{ id: number; dir: 'left' | 'right' } | null>(null) + const [removedIds, setRemovedIds] = useState<Set<number>>(new Set()) + + const [drag, setDrag] = useState<{ id: number; x: number } | null>(null) + const dragStartX = useRef<number | null>(null) + const dragStartY = useRef<number | null>(null) + const pendingDragId = useRef<number | null>(null) + const activePointerId = useRef<number | null>(null) + + if (!component || !component.tinderEnabled) return <ComponentUnavailable /> + + if (isError || isLoading || !communities) return <PageStatus isLoading={isLoading} isError={isError} /> + + const unseen = communities.filter((c) => c.status === 'NOT_SEEN') + const displayed = unseen.filter((c) => !removedIds.has(c.id)) + + const isMobile = typeof window !== 'undefined' && window.innerWidth < 768 + const containerHeight = isMobile ? Math.min(598, window.innerHeight - 200) : 598 + + const stackContainerStyle: React.CSSProperties = { + width: '100%', + maxWidth: 416, + height: containerHeight, + position: 'relative', + margin: '1rem auto', + padding: '0 0.5rem' + } + + const cardWrapperBase = (index: number, total: number): React.CSSProperties => ({ + position: 'absolute', + top: 0, + left: 0, + right: 0, + bottom: 0, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + zIndex: total - index, + transform: 'translateY(0)' + }) + + const removeCardAfterAnimation = (id: number) => { + window.setTimeout(() => { + setRemovedIds((prev) => { + const copy = new Set(prev) + copy.add(id) + return copy + }) + setSwipe(null) + }, 340) + } + + const doLike = (c: TinderCommunity) => { + setSwipe({ id: c.id, dir: 'right' }) + removeCardAfterAnimation(c.id) + interact.mutate({ communityId: c.id, liked: true }) + } + + const doDislike = (c: TinderCommunity) => { + setSwipe({ id: c.id, dir: 'left' }) + removeCardAfterAnimation(c.id) + interact.mutate({ communityId: c.id, liked: false }) + } + + const START_THRESHOLD = 10 + + const handlePointerDown = (e: React.PointerEvent, c: TinderCommunity) => { + if (swipe) return + let targetNode: Node | null = e.target as Node | null + while (targetNode && targetNode.nodeType !== Node.ELEMENT_NODE) { + targetNode = targetNode.parentNode + } + const el = targetNode as Element | null + if (el && el.closest && (el.closest('button, a, [role="button"], input, textarea, select') || el.closest('[data-no-drag]'))) { + return + } + dragStartX.current = e.clientX + dragStartY.current = e.clientY + pendingDragId.current = c.id + activePointerId.current = null + } + + const handlePointerMove = (e: React.PointerEvent, c: TinderCommunity) => { + const startX = dragStartX.current + const startY = dragStartY.current + if (startX == null || startY == null) return + + const dx = e.clientX - startX + const dy = e.clientY - startY + + if (!drag) { + const absDx = Math.abs(dx) + const absDy = Math.abs(dy) + if (absDx < START_THRESHOLD && absDy < START_THRESHOLD) return + + if (absDx > absDy && absDx >= START_THRESHOLD && pendingDragId.current === c.id) { + try { + e.currentTarget.setPointerCapture(e.pointerId) + } catch { + /* ignore capture failures */ + } + activePointerId.current = e.pointerId + pendingDragId.current = null + setDrag({ id: c.id, x: dx }) + e.preventDefault() + return + } + + if (absDy > absDx) { + pendingDragId.current = null + return + } + } + + if (!drag || activePointerId.current !== e.pointerId) return + + setDrag({ id: c.id, x: dx }) + e.preventDefault() + + if (!swipe) { + if (dx > SWIPE_THRESHOLD) { + try { + e.currentTarget.releasePointerCapture(e.pointerId) + } catch { + /* empty */ + } + setDrag(null) + dragStartX.current = null + dragStartY.current = null + activePointerId.current = null + doLike(c) + return + } + if (dx < -SWIPE_THRESHOLD) { + try { + e.currentTarget.releasePointerCapture(e.pointerId) + } catch { + // ignore + } + setDrag(null) + dragStartX.current = null + dragStartY.current = null + activePointerId.current = null + doDislike(c) + return + } + } + } + + const handlePointerUp = (e: React.PointerEvent, c: TinderCommunity) => { + if (!drag) { + dragStartX.current = null + dragStartY.current = null + pendingDragId.current = null + return + } + + if (activePointerId.current !== null && activePointerId.current !== e.pointerId) return + + try { + e.currentTarget.releasePointerCapture(e.pointerId) + } catch { + // ignore if not captured + } + const startX = dragStartX.current + if (startX == null) { + setDrag(null) + dragStartX.current = null + dragStartY.current = null + activePointerId.current = null + return + } + const dx = e.clientX - startX + setDrag(null) + dragStartX.current = null + dragStartY.current = null + activePointerId.current = null + + if (dx > SWIPE_THRESHOLD) { + doLike(c) + return + } + if (dx < -SWIPE_THRESHOLD) { + doDislike(c) + return + } + } + + const handlePointerCancel = () => { + setDrag(null) + dragStartX.current = null + dragStartY.current = null + pendingDragId.current = null + activePointerId.current = null + } + + const handleTouchStart = (e: React.TouchEvent, c: TinderCommunity) => { + if (swipe) return + let targetNode: Node | null = e.target as Node | null + while (targetNode && targetNode.nodeType !== Node.ELEMENT_NODE) { + targetNode = targetNode.parentNode + } + const el = targetNode as Element | null + if (el && el.closest && (el.closest('button, a, [role="button"], input, textarea, select') || el.closest('[data-no-drag]'))) { + return + } + const t = e.touches && e.touches[0] + if (!t) return + dragStartX.current = t.clientX + dragStartY.current = t.clientY + pendingDragId.current = c.id + } + + const handleTouchMove = (e: React.TouchEvent, c: TinderCommunity) => { + const startX = dragStartX.current + const startY = dragStartY.current + const t = e.touches && e.touches[0] + if (startX == null || startY == null || !t) return + + const dx = t.clientX - startX + const dy = t.clientY - startY + + if (!drag) { + const absDx = Math.abs(dx) + const absDy = Math.abs(dy) + if (absDx < START_THRESHOLD && absDy < START_THRESHOLD) return + + if (absDx > absDy && absDx >= START_THRESHOLD && pendingDragId.current === c.id) { + pendingDragId.current = null + setDrag({ id: c.id, x: dx }) + e.preventDefault() + return + } + + if (absDy > absDx) { + pendingDragId.current = null + return + } + } + + if (!drag || drag.id !== c.id) return + + setDrag({ id: c.id, x: dx }) + e.preventDefault() + + if (!swipe) { + if (dx > SWIPE_THRESHOLD) { + setDrag(null) + dragStartX.current = null + dragStartY.current = null + doLike(c) + return + } + if (dx < -SWIPE_THRESHOLD) { + setDrag(null) + dragStartX.current = null + dragStartY.current = null + doDislike(c) + return + } + } + } + + const handleTouchEnd = (e: React.TouchEvent, c: TinderCommunity) => { + if (!drag) { + dragStartX.current = null + dragStartY.current = null + pendingDragId.current = null + return + } + + const startX = dragStartX.current + const t = e.changedTouches && e.changedTouches[0] + if (startX == null || !t) { + setDrag(null) + dragStartX.current = null + dragStartY.current = null + return + } + const dx = t.clientX - startX + setDrag(null) + dragStartX.current = null + dragStartY.current = null + + if (dx > SWIPE_THRESHOLD) { + doLike(c) + return + } + if (dx < -SWIPE_THRESHOLD) { + doDislike(c) + return + } + } + + const handleTouchCancel = () => { + setDrag(null) + dragStartX.current = null + dragStartY.current = null + pendingDragId.current = null + } + + return ( + <CmschPage loginRequired={true} title="Tinder"> + <Box w="100%" mx="auto" px={{ base: 2, md: 4 }}> + <Box + position="relative" + mb={6} + display="flex" + flexDirection={{ base: 'column', sm: 'row' }} + alignItems={{ base: 'center', md: 'flex-start' }} + pb={10} + gap={4} + > + <Heading as="h1" variant="main-title" textAlign={{ base: 'center', sm: 'left' }} flex={{ base: 'none', md: 1 }}> + Kör tinder + </Heading> + <Flex + flexDirection={{ base: 'column', md: 'row' }} + gap={3} + width={{ base: 'full', sm: 'auto' }} + position={{ base: 'relative', sm: 'absolute' }} + top={{ base: 'auto', sm: '50%' }} + right={{ base: 'auto', sm: 2 }} + transform={{ base: 'none', sm: 'translateY(-50%)' }} + > + <Button + as={Link} + to={`${AbsolutePaths.TINDER}/liked`} + size={{ base: 'md', md: 'lg' }} + aria-label="Tinder-matches-button" + width={{ base: 'full', sm: 'auto' }} + > + Kedvelt körök + </Button> + <Button + as={Link} + to={`${AbsolutePaths.TINDER}/question`} + size={{ base: 'md', md: 'lg' }} + width={{ base: 'full', sm: 'auto' }} + aria-label="Tinder-questions-button" + > + Válaszaid + </Button> + </Flex> + </Box> + {displayed.length === 0 ? ( + <Box px={4} py={8} textAlign="center"> + <Text>Minden kört megtekintettél már. A kedvelt köröket megtekintheted összegyűjtve a fenti gombra kattintva.</Text> + </Box> + ) : ( + <div style={stackContainerStyle} aria-live="polite"> + {displayed.map((c, idx) => { + const base = cardWrapperBase(idx, displayed.length) + const isTop = idx === 0 + const isSwiping = swipe?.id === c.id + + let style: React.CSSProperties = { + ...base, + transition: 'transform 320ms ease, opacity 320ms ease' + } + + if (isSwiping && swipe) { + const dir = swipe.dir === 'right' ? 1 : -1 + style = { + ...style, + transform: `translateX(${dir * 480}px) rotate(${dir * 18}deg)`, + opacity: 0 + } + } + + if (drag?.id === c.id && !isSwiping) { + const dx = drag.x + const rot = dx * 0.06 + const opacity = Math.max(0.25, 1 - Math.abs(dx) / 800) + style = { + ...style, + transform: `translateX(${dx}px) rotate(${rot}deg)`, + opacity + } + } + + let handlers: React.DOMAttributes<HTMLDivElement> = {} + if (isTop) { + handlers = { + onPointerDown: (e: React.PointerEvent) => handlePointerDown(e, c), + onPointerMove: (e: React.PointerEvent) => handlePointerMove(e, c), + onPointerUp: (e: React.PointerEvent) => handlePointerUp(e, c), + onPointerCancel: handlePointerCancel, + // touch fallbacks for mobile + onTouchStart: (e: React.TouchEvent) => handleTouchStart(e, c), + onTouchMove: (e: React.TouchEvent) => handleTouchMove(e, c), + onTouchEnd: (e: React.TouchEvent) => handleTouchEnd(e, c), + onTouchCancel: handleTouchCancel + } + } + + if (!isTop) { + style.pointerEvents = 'none' + } else { + style.touchAction = 'pan-y' + } + + return ( + <div key={c.id} style={style} {...handlers}> + <TinderCard data={c} depth={idx} onLike={() => doLike(c)} onDislike={() => doDislike(c)} /> + </div> + ) + })} + </div> + )} + </Box> + </CmschPage> + ) +} + +export default TinderPage diff --git a/frontend/src/pages/communities/tinderQuestions.page.tsx b/frontend/src/pages/communities/tinderQuestions.page.tsx new file mode 100644 index 000000000..c099cb02c --- /dev/null +++ b/frontend/src/pages/communities/tinderQuestions.page.tsx @@ -0,0 +1,134 @@ +import { Box, Button, FormControl, FormLabel, Heading, useToast, Wrap, WrapItem } from '@chakra-ui/react' +import { useEffect } from 'react' +import { FormProvider, useForm } from 'react-hook-form' +import { Link } from 'react-router' +import { useConfigContext } from '../../api/contexts/config/ConfigContext.tsx' +import { useTinderAnswers } from '../../api/hooks/community/useTinderAnswers.ts' +import { useTinderAnswerSend } from '../../api/hooks/community/useTinderAnswerSend.ts' +import { useTinderQuestions } from '../../api/hooks/community/useTinderQuestions.ts' +import { ComponentUnavailable } from '../../common-components/ComponentUnavailable.tsx' +import { CmschPage } from '../../common-components/layout/CmschPage.tsx' +import { PageStatus } from '../../common-components/PageStatus.tsx' +import { useBrandColor } from '../../util/core-functions.util.ts' +import { AbsolutePaths } from '../../util/paths.ts' +import { SendAnswerResponseMessage, SendAnswerResponseStatus } from '../../util/views/tinder.ts' + +const TinderQuestionsPage = () => { + const brandColor = useBrandColor() + const toast = useToast() + const formMethods = useForm<Record<string, string>>() + const { setValue, watch } = formMethods + + const component = useConfigContext()?.components?.communities + + const { data: questions, isLoading: questionsLoading, isError: questionsError } = useTinderQuestions() + const { data: answersStatus, isLoading: answersLoading, isError: answersError, refetch: refetchAnswers } = useTinderAnswers() + const { response, submit } = useTinderAnswerSend() + + useEffect(() => { + if (!questions || !answersStatus) return + const defaults: Record<string, string> = {} + const existing = answersStatus?.answer || {} + for (const [k, v] of Object.entries(existing)) { + defaults[String(k)] = String(v) + } + formMethods.reset(defaults) + }, [questions, answersStatus, formMethods]) + + useEffect(() => { + if (!response) return + + const success = response === SendAnswerResponseStatus.OK + const title = SendAnswerResponseMessage[response as SendAnswerResponseStatus] + toast({ title, status: success ? 'success' : 'error' }) + if (success && answersStatus?.answered) { + //redirect to /tinder/community + window.location.href = `${AbsolutePaths.TINDER}/community` + return + } + refetchAnswers() + }, [response, refetchAnswers, toast, answersStatus?.answered]) + + // If the feature is disabled, show unavailable after hooks have been called + if (!component || !component.tinderEnabled) return <ComponentUnavailable /> + + const isLoading = questionsLoading || answersLoading + const isError = questionsError || answersError + const data = questions && answersStatus + if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title="Tinder kérdések" /> + + const onSubmit = (values: Record<string, string>) => { + submit(values, answersStatus.answered) + } + + return ( + <CmschPage loginRequired={true} title="Tinder kérdések"> + <Box w="100%" mx="auto"> + <Box + position="relative" + mb={6} + display="flex" + flexDirection={{ base: 'column', sm: 'row' }} + alignItems={{ base: 'center', md: 'flex-start' }} + gap={4} + > + <Heading as="h1" variant="main-title"> + Tinder kérdések + </Heading> + <Button + as={Link} + to={`${AbsolutePaths.TINDER}/community`} + size={{ base: 'md', md: 'lg' }} + aria-label="Tinder-matches-button" + width={{ base: 'full', sm: 'auto' }} + position={{ base: 'relative', sm: 'absolute' }} + top={{ base: 'auto', sm: '50%' }} + right={{ base: 'auto', sm: 2 }} + transform={{ base: 'none', sm: 'translateY(-30%)', md: 'translateY(-50%)' }} + > + Tinder + </Button> + </Box> + <FormProvider {...formMethods}> + <form onSubmit={formMethods.handleSubmit(onSubmit)}> + {questions.map((q) => { + const fieldKey = String(q.id) + const selected = watch(fieldKey) || '' + + return ( + <FormControl key={q.id} mt={5}> + <FormLabel mb={2} fontSize={20} htmlFor={fieldKey}> + {q.question} + </FormLabel> + + <Wrap spacing={2} align="center"> + {q.options.map((opt) => ( + <WrapItem key={opt}> + <Button + type="button" + size="sm" + onClick={() => setValue(fieldKey, opt)} + variant={selected === opt ? 'solid' : 'outline'} + colorScheme={selected === opt ? brandColor : undefined} + aria-pressed={selected === opt} + > + {opt} + </Button> + </WrapItem> + ))} + </Wrap> + </FormControl> + ) + })} + + <Button mt={6} colorScheme={brandColor} isLoading={isLoading} type="submit"> + Mentés + </Button> + </form> + </FormProvider> + </Box> + </CmschPage> + ) +} + +export default TinderQuestionsPage diff --git a/frontend/src/pages/communities/tinderRouter.tsx b/frontend/src/pages/communities/tinderRouter.tsx new file mode 100644 index 000000000..435e8548e --- /dev/null +++ b/frontend/src/pages/communities/tinderRouter.tsx @@ -0,0 +1,18 @@ +import { Navigate } from 'react-router' +import { useTinderAnswers } from '../../api/hooks/community/useTinderAnswers.ts' +import { PageStatus } from '../../common-components/PageStatus.tsx' +import { AbsolutePaths } from '../../util/paths.ts' + +const TinderRouter = () => { + const { data, isLoading, isError } = useTinderAnswers() + + if (isLoading || isError || !data) return <PageStatus isLoading={isLoading} isError={isError} /> + + if (data.answered) { + return <Navigate to={`${AbsolutePaths.TINDER}/community`} /> + } else { + return <Navigate to={`${AbsolutePaths.TINDER}/question`} /> + } +} + +export default TinderRouter diff --git a/frontend/src/pages/countdown/countdown.page.tsx b/frontend/src/pages/countdown/countdown.page.tsx index 64ea62120..12ec7bb19 100644 --- a/frontend/src/pages/countdown/countdown.page.tsx +++ b/frontend/src/pages/countdown/countdown.page.tsx @@ -1,14 +1,12 @@ import { Center, Flex, Heading, VStack } from '@chakra-ui/react' -import { PropsWithChildren, useMemo } from 'react' -import { Helmet } from 'react-helmet-async' +import { type PropsWithChildren, useMemo } from 'react' import { useConfigContext } from '../../api/contexts/config/ConfigContext' +import { Title } from '../../util/TitleProvider.tsx' import Clock from './components/clock' import { parseTopMessage } from './countdown.util' const CountdownPage = ({ children }: PropsWithChildren) => { - const config = useConfigContext() - - const component = config?.components?.countdown + const component = useConfigContext()?.components?.countdown const countTo = useMemo(() => { try { if (!component) return new Date() @@ -22,7 +20,7 @@ const CountdownPage = ({ children }: PropsWithChildren) => { if (component?.enabled && component?.showOnly && (component?.keepOnAfterCountdownOver || countTo.getTime() > Date.now())) { return ( <Flex h="100%" w="100%"> - <Helmet title={component?.title} /> + <Title text={component?.title} /> <Flex position="absolute" h="100%" diff --git a/frontend/src/pages/debt/components/debt-list-item.tsx b/frontend/src/pages/debt/components/debt-list-item.tsx index 74e07347a..c3ae0ca7d 100644 --- a/frontend/src/pages/debt/components/debt-list-item.tsx +++ b/frontend/src/pages/debt/components/debt-list-item.tsx @@ -2,7 +2,7 @@ import { Box, HStack, Text, useColorModeValue } from '@chakra-ui/react' import * as FaIcons from 'react-icons/fa' import { FaCircleCheck, FaCircleXmark } from 'react-icons/fa6' import { useOpaqueBackground } from '../../../util/core-functions.util.ts' -import { DebtView } from '../../../util/views/debt.view.ts' +import type { DebtView } from '../../../util/views/debt.view.ts' interface DebtListItemProps { item: DebtView diff --git a/frontend/src/pages/debt/debt.page.tsx b/frontend/src/pages/debt/debt.page.tsx index 24ccfca5b..6fccf5779 100644 --- a/frontend/src/pages/debt/debt.page.tsx +++ b/frontend/src/pages/debt/debt.page.tsx @@ -1,5 +1,4 @@ import { Divider, Heading, Text } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { useConfigContext } from '../../api/contexts/config/ConfigContext.tsx' import { useDebtQuery } from '../../api/hooks/debt/useDebtQuery.ts' import { useProfileQuery } from '../../api/hooks/profile/useProfileQuery.ts' @@ -24,8 +23,7 @@ const DebtPage = () => { if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={title} /> return ( - <CmschPage> - <Helmet title={title} /> + <CmschPage title={title}> <Heading as="h1" variant="main-title"> {title} </Heading> diff --git a/frontend/src/pages/error/error.page.tsx b/frontend/src/pages/error/error.page.tsx index d81a36db1..97a2b2a07 100644 --- a/frontend/src/pages/error/error.page.tsx +++ b/frontend/src/pages/error/error.page.tsx @@ -1,6 +1,5 @@ import { Box, ButtonGroup, Heading } from '@chakra-ui/react' import { useEffect, useState } from 'react' -import { Helmet } from 'react-helmet-async' import { Navigate } from 'react-router' import { MessageTypes, useServiceContext } from '../../api/contexts/service/ServiceContext' import { CmschPage } from '../../common-components/layout/CmschPage' @@ -34,8 +33,7 @@ export const ErrorPage = ({ message: messageProp }: Props) => { // Display authentication page for the corresponding error type if (clonedMessageType === MessageTypes.AUTHENTICATION) return <UnauthorizedPage /> return ( - <CmschPage> - <Helmet title={l('error-page-helmet')} /> + <CmschPage title={l('error-page-helmet')}> <Heading as="h1" variant="main-title" textAlign="center"> {l('error-page-title')} </Heading> diff --git a/frontend/src/pages/error/unauthorized.page.tsx b/frontend/src/pages/error/unauthorized.page.tsx index 48503a920..044396471 100644 --- a/frontend/src/pages/error/unauthorized.page.tsx +++ b/frontend/src/pages/error/unauthorized.page.tsx @@ -1,5 +1,4 @@ import { Button, ButtonGroup, Heading, Text } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { useNavigate } from 'react-router' import { CmschPage } from '../../common-components/layout/CmschPage' import { LinkButton } from '../../common-components/LinkButton' @@ -11,8 +10,7 @@ export const UnauthorizedPage = () => { const brandColor = useBrandColor() return ( - <CmschPage> - <Helmet title={l('unauthorized-page-helmet')} /> + <CmschPage title={l('unauthorized-page-helmet')}> <Heading as="h1" variant="main-title" textAlign="center"> {l('unauthorized-page-title')} </Heading> diff --git a/frontend/src/pages/events/components/CardListItem.tsx b/frontend/src/pages/events/components/CardListItem.tsx index 89a02103e..7106f86ed 100644 --- a/frontend/src/pages/events/components/CardListItem.tsx +++ b/frontend/src/pages/events/components/CardListItem.tsx @@ -1,5 +1,5 @@ import { ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons' -import { Box, BoxProps, Heading, HStack, Spacer, useColorModeValue } from '@chakra-ui/react' +import { Box, type BoxProps, Heading, HStack, Spacer, useColorModeValue } from '@chakra-ui/react' import { PulsingDot } from '../../../common-components/PulsingDot' type CardListItemProps = { diff --git a/frontend/src/pages/events/components/CurrentEvent.tsx b/frontend/src/pages/events/components/CurrentEvent.tsx index d511f2704..84164ffe7 100644 --- a/frontend/src/pages/events/components/CurrentEvent.tsx +++ b/frontend/src/pages/events/components/CurrentEvent.tsx @@ -5,7 +5,7 @@ import { LinkButton } from '../../../common-components/LinkButton' import Markdown from '../../../common-components/Markdown' import { DETAILED_TIMESTAMP_OPTIONS, isCurrentEvent, isUpcomingEvent, stringifyTimeStamp } from '../../../util/core-functions.util' import { AbsolutePaths } from '../../../util/paths' -import { EventView } from '../../../util/views/event.view' +import type { EventView } from '../../../util/views/event.view' import EventTags from './EventTags' interface EventProps { diff --git a/frontend/src/pages/events/components/CustomTab.tsx b/frontend/src/pages/events/components/CustomTab.tsx index bf2c04c76..0a7d1c778 100644 --- a/frontend/src/pages/events/components/CustomTab.tsx +++ b/frontend/src/pages/events/components/CustomTab.tsx @@ -1,5 +1,5 @@ import { Tab } from '@chakra-ui/react' -import { PropsWithChildren } from 'react' +import type { PropsWithChildren } from 'react' import { useBrandColor } from '../../../util/core-functions.util.ts' export const CustomTab = ({ children }: PropsWithChildren) => { diff --git a/frontend/src/pages/events/components/EventFilterOption.tsx b/frontend/src/pages/events/components/EventFilterOption.tsx index 98fc99b7a..a37a492d9 100644 --- a/frontend/src/pages/events/components/EventFilterOption.tsx +++ b/frontend/src/pages/events/components/EventFilterOption.tsx @@ -1,7 +1,7 @@ import { Box, Collapse, Stack, useDisclosure } from '@chakra-ui/react' import { useEffect } from 'react' import { isCurrentEvent, isUpcomingEvent } from '../../../util/core-functions.util' -import { EventListView } from '../../../util/views/event.view' +import type { EventListView } from '../../../util/views/event.view' import { CardListItem } from './CardListItem' import EventList from './EventList' diff --git a/frontend/src/pages/events/components/EventList.tsx b/frontend/src/pages/events/components/EventList.tsx index 4669a36c9..e07e3aa5d 100644 --- a/frontend/src/pages/events/components/EventList.tsx +++ b/frontend/src/pages/events/components/EventList.tsx @@ -2,7 +2,7 @@ import { Box, Heading, VStack } from '@chakra-ui/react' import { isSameDay } from 'date-fns' import { useMemo } from 'react' import { useConfigContext } from '../../../api/contexts/config/ConfigContext' -import { EventListView } from '../../../util/views/event.view' +import type { EventListView } from '../../../util/views/event.view' import EventListItem from './EventListItem' interface EventListProps { diff --git a/frontend/src/pages/events/components/EventListItem.tsx b/frontend/src/pages/events/components/EventListItem.tsx index 8daaac61d..4553646f9 100644 --- a/frontend/src/pages/events/components/EventListItem.tsx +++ b/frontend/src/pages/events/components/EventListItem.tsx @@ -4,7 +4,7 @@ import { useConfigContext } from '../../../api/contexts/config/ConfigContext' import { EventIndicator } from '../../../common-components/EventIndicator' import { isCurrentEvent, isUpcomingEvent, stringifyTimeRange } from '../../../util/core-functions.util' import { AbsolutePaths } from '../../../util/paths' -import { EventListView } from '../../../util/views/event.view' +import type { EventListView } from '../../../util/views/event.view' import EventTags from './EventTags' interface EventListItemProps { diff --git a/frontend/src/pages/events/components/EventTags.tsx b/frontend/src/pages/events/components/EventTags.tsx index dac396cfa..648e77233 100644 --- a/frontend/src/pages/events/components/EventTags.tsx +++ b/frontend/src/pages/events/components/EventTags.tsx @@ -1,4 +1,4 @@ -import { HStack, SpaceProps, Tag } from '@chakra-ui/react' +import { HStack, type SpaceProps, Tag } from '@chakra-ui/react' import { useBrandColor } from '../../../util/core-functions.util.ts' interface EventTagsProps { diff --git a/frontend/src/pages/events/components/event-calendar/DayCalendar.tsx b/frontend/src/pages/events/components/event-calendar/DayCalendar.tsx index 6b2bf300e..c54a4debe 100644 --- a/frontend/src/pages/events/components/event-calendar/DayCalendar.tsx +++ b/frontend/src/pages/events/components/event-calendar/DayCalendar.tsx @@ -3,7 +3,7 @@ import { addDays, endOfDay, startOfDay } from 'date-fns' import { useMemo, useState } from 'react' import { FaChevronLeft, FaChevronRight } from 'react-icons/fa' import { formatHu, useBrandColor } from '../../../../util/core-functions.util' -import { EventListView } from '../../../../util/views/event.view' +import type { EventListView } from '../../../../util/views/event.view' import { CurrentDateBar } from './CurrentDateBar' import { EventBox } from './EventBox' import { HourColumn } from './HourColumn' diff --git a/frontend/src/pages/events/components/event-calendar/EventBox.tsx b/frontend/src/pages/events/components/event-calendar/EventBox.tsx index 812752cea..0be271321 100644 --- a/frontend/src/pages/events/components/event-calendar/EventBox.tsx +++ b/frontend/src/pages/events/components/event-calendar/EventBox.tsx @@ -11,17 +11,17 @@ import { Text, useColorModeValue } from '@chakra-ui/react' -import { RefObject } from 'react' +import type { RefObject } from 'react' import { useConfigContext } from '../../../../api/contexts/config/ConfigContext' import { LinkButton } from '../../../../common-components/LinkButton' import { formatHu, stringifyTimeRange, useBrandColor } from '../../../../util/core-functions.util' import { AbsolutePaths } from '../../../../util/paths' -import { EventListView } from '../../../../util/views/event.view' +import type { EventListView } from '../../../../util/views/event.view' export type EventBoxItem = EventListView & { top: number; bottom: number; width: number; left: number } interface EventBoxProps { - boxRef?: RefObject<HTMLDivElement> + boxRef?: RefObject<HTMLDivElement | null> event: EventBoxItem } diff --git a/frontend/src/pages/events/components/event-calendar/HourColumn.tsx b/frontend/src/pages/events/components/event-calendar/HourColumn.tsx index ad3639d26..97504fa8f 100644 --- a/frontend/src/pages/events/components/event-calendar/HourColumn.tsx +++ b/frontend/src/pages/events/components/event-calendar/HourColumn.tsx @@ -1,4 +1,4 @@ -import { Box, StackProps, Text } from '@chakra-ui/react' +import { Box, type StackProps, Text } from '@chakra-ui/react' import { addHours, endOfDay, format, startOfDay } from 'date-fns' import { useMemo } from 'react' import { calculatePosition } from './utils' diff --git a/frontend/src/pages/events/components/event-calendar/WeekCalendar.tsx b/frontend/src/pages/events/components/event-calendar/WeekCalendar.tsx index 5e75c18bb..cc308959f 100644 --- a/frontend/src/pages/events/components/event-calendar/WeekCalendar.tsx +++ b/frontend/src/pages/events/components/event-calendar/WeekCalendar.tsx @@ -3,9 +3,9 @@ import { addDays, addWeeks, endOfDay, startOfWeek } from 'date-fns' import { useMemo, useRef, useState } from 'react' import { FaChevronLeft, FaChevronRight } from 'react-icons/fa' import { formatHu, useBrandColor } from '../../../../util/core-functions.util' -import { EventListView } from '../../../../util/views/event.view' +import type { EventListView } from '../../../../util/views/event.view' import { CurrentDateBar } from './CurrentDateBar' -import { EventBox, EventBoxItem } from './EventBox' +import { EventBox, type EventBoxItem } from './EventBox' import { HourColumn } from './HourColumn' import { mapEventsForDay } from './utils' import { ZoomBar } from './ZoomBar' diff --git a/frontend/src/pages/events/components/event-calendar/utils.ts b/frontend/src/pages/events/components/event-calendar/utils.ts index a9642aef3..0a932b4bf 100644 --- a/frontend/src/pages/events/components/event-calendar/utils.ts +++ b/frontend/src/pages/events/components/event-calendar/utils.ts @@ -1,6 +1,6 @@ import { endOfDay, isSameDay } from 'date-fns' -import { EventListView } from '../../../../util/views/event.view' -import { EventBoxItem } from './EventBox' +import type { EventListView } from '../../../../util/views/event.view' +import type { EventBoxItem } from './EventBox' export function calculatePosition(minTimestamp: number, maxTimestamp: number, timestamp: number) { return ((timestamp - minTimestamp) / (maxTimestamp - minTimestamp)) * 100 diff --git a/frontend/src/pages/events/event.page.tsx b/frontend/src/pages/events/event.page.tsx index aab127121..3d9d26c43 100644 --- a/frontend/src/pages/events/event.page.tsx +++ b/frontend/src/pages/events/event.page.tsx @@ -1,4 +1,3 @@ -import { Helmet } from 'react-helmet-async' import { useParams } from 'react-router' import { useEventQuery } from '../../api/hooks/event/useEventQuery' @@ -13,8 +12,7 @@ const EventPage = () => { if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} /> return ( - <CmschPage position="relative"> - <Helmet title={data.title} /> + <CmschPage position="relative" title={data?.title}> <CurrentEvent event={data} /> </CmschPage> ) diff --git a/frontend/src/pages/events/eventCalendar.page.tsx b/frontend/src/pages/events/eventCalendar.page.tsx index 7ef0a16df..a21b50cf9 100644 --- a/frontend/src/pages/events/eventCalendar.page.tsx +++ b/frontend/src/pages/events/eventCalendar.page.tsx @@ -1,5 +1,4 @@ import { Box, Heading } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { FaArrowLeft } from 'react-icons/fa' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useEventListQuery } from '../../api/hooks/event/useEventListQuery' @@ -14,23 +13,22 @@ import { DayCalendar } from './components/event-calendar/DayCalendar' import { WeekCalendar } from './components/event-calendar/WeekCalendar' function EventCalendarPage() { - const component = useConfigContext()?.components?.event + const event = useConfigContext()?.components?.event const brandColor = useBrandColor() const { isLoading, isError, data } = useEventListQuery() - if (!component) return <ComponentUnavailable /> - if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={component.title} /> + if (!event) return <ComponentUnavailable /> + if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={event.title} /> return ( - <CmschPage> - <Helmet title="Naptár" /> + <CmschPage title="Naptár"> <LinkButton colorScheme={brandColor} href={AbsolutePaths.EVENTS} leftIcon={<FaArrowLeft />}> Vissza a listához </LinkButton> <Box mb={10}> <Heading mb={5}>Naptár</Heading> - {component.topMessage && <Markdown text={component.topMessage} />} + {event.topMessage && <Markdown text={event.topMessage} />} </Box> <WeekCalendar events={data} /> <DayCalendar events={data} /> diff --git a/frontend/src/pages/events/eventList.page.tsx b/frontend/src/pages/events/eventList.page.tsx index 41ac817e4..a4da23b40 100644 --- a/frontend/src/pages/events/eventList.page.tsx +++ b/frontend/src/pages/events/eventList.page.tsx @@ -14,7 +14,6 @@ import { useDisclosure } from '@chakra-ui/react' import uniq from 'lodash/uniq' -import { Helmet } from 'react-helmet-async' import { FaCalendar } from 'react-icons/fa' import { useConfigContext } from '../../api/contexts/config/ConfigContext' @@ -29,15 +28,15 @@ import Markdown from '../../common-components/Markdown' import { PageStatus } from '../../common-components/PageStatus' import { useBrandColor } from '../../util/core-functions.util.ts' import { Paths } from '../../util/paths' -import { EventListView } from '../../util/views/event.view' +import type { EventListView } from '../../util/views/event.view' import { CardListItem } from './components/CardListItem' import { EventFilterOption } from './components/EventFilterOption' import EventList from './components/EventList' -import { FILTER, mapper } from './util/filter' +import { Filter, mapper } from './util/filter' const EventListPage = () => { const { isLoading, isError, data } = useEventListQuery() - const component = useConfigContext()?.components?.event + const event = useConfigContext()?.components?.event const { isOpen, onToggle } = useDisclosure() const tabsSize = useBreakpointValue({ base: 'sm', md: 'md' }) const breakpoint = useBreakpoint() @@ -46,9 +45,9 @@ const EventListPage = () => { const brandColor = useBrandColor() const availableFilters = [] - if (component?.filterByCategory) availableFilters.push(FILTER.CATEGORY) - if (component?.filterByLocation) availableFilters.push(FILTER.PLACE) - if (component?.filterByDay) availableFilters.push(FILTER.DAY) + if (event?.filterByCategory) availableFilters.push(Filter.CATEGORY) + if (event?.filterByLocation) availableFilters.push(Filter.PLACE) + if (event?.filterByDay) availableFilters.push(Filter.DAY) // eslint-disable-next-line react-hooks/purity const pastEvents = useMemo(() => data?.filter((event) => event.timestampEnd * 1000 < Date.now()), [data]) @@ -70,16 +69,15 @@ const EventListPage = () => { setFilteredEvents(upcomingEvents) }, [upcomingEvents]) - if (!component) return <ComponentUnavailable /> - if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={component.title} /> + if (!event) return <ComponentUnavailable /> + if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={event.title} /> return ( - <CmschPage> - <Helmet title={component.title ?? 'Események'} /> + <CmschPage title={event.title ?? 'Események'}> <Box mb={5}> <Heading as="h1" variant="main-title" mb={5}> - {component.title} + {event.title} </Heading> - {component.topMessage && <Markdown text={component.topMessage} />} + {event.topMessage && <Markdown text={event.topMessage} />} </Box> <LinkButton colorScheme={brandColor} mb={5} leftIcon={<FaCalendar />} href={Paths.CALENDAR}> Megtekintés a naptárban @@ -88,15 +86,15 @@ const EventListPage = () => { {availableFilters.length > 0 && ( <TabList> <CustomTabButton>Mind</CustomTabButton> - {component.filterByCategory && <CustomTabButton>Kategória szerint</CustomTabButton>} - {component.filterByLocation && <CustomTabButton>Helyszín szerint</CustomTabButton>} - {component.filterByDay && <CustomTabButton>Időpont szerint</CustomTabButton>} + {event.filterByCategory && <CustomTabButton>Kategória szerint</CustomTabButton>} + {event.filterByLocation && <CustomTabButton>Helyszín szerint</CustomTabButton>} + {event.filterByDay && <CustomTabButton>Időpont szerint</CustomTabButton>} </TabList> )} <TabPanels> <TabPanel p={0}> - {component.searchEnabled && ( + {event.searchEnabled && ( <InputGroup mt={5}> <InputLeftElement h="100%"> <SearchIcon /> @@ -117,7 +115,7 @@ const EventListPage = () => { <TabPanel key={filter} p={0}> <Stack> <CardListItem title="Mind" open={isOpen} toggle={onToggle} /> - {filter === FILTER.DAY && <EventFilterOption name="Korábbi" events={pastEvents || []} forceOpen={isOpen} />} + {filter === Filter.DAY && <EventFilterOption name="Korábbi" events={pastEvents || []} forceOpen={isOpen} />} {uniq(upcomingEvents?.map((event) => mapper(filter, event))).map((option) => ( <EventFilterOption key={option} diff --git a/frontend/src/pages/events/util/filter.tsx b/frontend/src/pages/events/util/filter.tsx index 22be2c024..4697a3a1a 100644 --- a/frontend/src/pages/events/util/filter.tsx +++ b/frontend/src/pages/events/util/filter.tsx @@ -1,20 +1,22 @@ import { GROUP_BY_DAY_OPTIONS, stringifyTimeStamp } from '../../../util/core-functions.util' -import { EventListView } from '../../../util/views/event.view' +import type { EventListView } from '../../../util/views/event.view' -export enum FILTER { - ALL = 'all', - CATEGORY = 'category', - PLACE = 'place', - DAY = 'day' +export const Filter = { + ALL: 'all', + CATEGORY: 'category', + PLACE: 'place', + DAY: 'day' } +export type Filter = (typeof Filter)[keyof typeof Filter] -export const mapper = (f: FILTER, e: EventListView) => { +export const mapper = (f: Filter, e: EventListView) => { switch (f) { - case FILTER.ALL: + case Filter.ALL: throw 'Cannot map if filter is set to all' - case FILTER.DAY: + case Filter.DAY: return stringifyTimeStamp(e.timestampStart, GROUP_BY_DAY_OPTIONS) default: - return e[f] + console.assert(Object.keys(e).includes(f)) + return e[f as keyof EventListView].toString() } } diff --git a/frontend/src/pages/extra/extra.page.tsx b/frontend/src/pages/extra/extra.page.tsx index 355db8871..13820a415 100644 --- a/frontend/src/pages/extra/extra.page.tsx +++ b/frontend/src/pages/extra/extra.page.tsx @@ -1,5 +1,4 @@ import { Heading } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { Navigate, useParams } from 'react-router' import { useAuthContext } from '../../api/contexts/auth/useAuthContext' import { useServiceContext } from '../../api/contexts/service/ServiceContext' @@ -24,8 +23,7 @@ const ExtraPage = () => { return <Navigate replace to={AbsolutePaths.ERROR} /> } return ( - <CmschPage> - <Helmet title={data.title} /> + <CmschPage title={data.title}> <Heading as="h1" variant="main-title"> {data.title} </Heading> diff --git a/frontend/src/pages/form/components/GridField.tsx b/frontend/src/pages/form/components/GridField.tsx index 34d5116cf..8811acae0 100644 --- a/frontend/src/pages/form/components/GridField.tsx +++ b/frontend/src/pages/form/components/GridField.tsx @@ -2,7 +2,7 @@ import { Grid, GridItem, Input } from '@chakra-ui/react' import { Fragment, useEffect } from 'react' import { useFormContext } from 'react-hook-form' import { PageStatus } from '../../../common-components/PageStatus' -import { FormField, GridFieldValues } from '../../../util/views/form.view' +import type { FormField, GridFieldValues } from '../../../util/views/form.view' import { GridFieldItem } from './GridFieldItem' type Props = { diff --git a/frontend/src/pages/form/components/GridFieldItem.tsx b/frontend/src/pages/form/components/GridFieldItem.tsx index 39e60a89f..7f1fa0fcd 100644 --- a/frontend/src/pages/form/components/GridFieldItem.tsx +++ b/frontend/src/pages/form/components/GridFieldItem.tsx @@ -1,5 +1,5 @@ import { Checkbox, Radio } from '@chakra-ui/react' -import { ChangeEvent } from 'react' +import type { ChangeEvent } from 'react' import { useFormContext } from 'react-hook-form' import { useBrandColor } from '../../../util/core-functions.util.ts' diff --git a/frontend/src/pages/form/components/autoFormField.tsx b/frontend/src/pages/form/components/autoFormField.tsx index 6deb4ca0e..6a9c09191 100644 --- a/frontend/src/pages/form/components/autoFormField.tsx +++ b/frontend/src/pages/form/components/autoFormField.tsx @@ -1,11 +1,11 @@ import { Alert, AlertIcon, Checkbox, Flex, FormLabel, Input, Select, Text, Textarea, useColorModeValue } from '@chakra-ui/react' -import { ReactNode } from 'react' -import { Control, useController } from 'react-hook-form' +import type { ReactNode } from 'react' +import { type Control, useController } from 'react-hook-form' import { useStyle } from '../../../api/contexts/config/ConfigContext.tsx' import Markdown from '../../../common-components/Markdown' import { VotingField } from '../../../common-components/VotingField' import { isCheckbox, isGridField } from '../../../util/core-functions.util' -import { FormField, FormFieldVariants, VotingFieldOption } from '../../../util/views/form.view' +import { type FormField, FormFieldVariants, type VotingFieldOption } from '../../../util/views/form.view' import { GridField } from './GridField' interface AutoFormFieldProps { diff --git a/frontend/src/pages/form/components/formStatusBadge.tsx b/frontend/src/pages/form/components/formStatusBadge.tsx index 89615a9b4..cc022a7ed 100644 --- a/frontend/src/pages/form/components/formStatusBadge.tsx +++ b/frontend/src/pages/form/components/formStatusBadge.tsx @@ -1,6 +1,6 @@ import { Badge } from '@chakra-ui/react' import { useConfigContext } from '../../../api/contexts/config/ConfigContext' -import { Signup } from '../../../api/contexts/config/types' +import type { Signup } from '../../../api/contexts/config/types' import { FormStatus, FormStatusLangKeys } from '../../../util/views/form.view' interface FormStatusBadgeProps { diff --git a/frontend/src/pages/form/form.page.tsx b/frontend/src/pages/form/form.page.tsx index db03e8c4f..f648b2433 100644 --- a/frontend/src/pages/form/form.page.tsx +++ b/frontend/src/pages/form/form.page.tsx @@ -1,6 +1,5 @@ import { Box, Button, Divider, Flex, FormControl, FormLabel, Heading, useToast } from '@chakra-ui/react' import { useEffect } from 'react' -import { Helmet } from 'react-helmet-async' import { FormProvider, useForm } from 'react-hook-form' import { useParams } from 'react-router' import { useFormPage } from '../../api/hooks/form/useFormPage' @@ -64,8 +63,7 @@ const FormPage = () => { if (!isLoggedIn && status === FormStatus.NOT_FOUND) return <ComponentUnavailable /> return ( - <CmschPage> - <Helmet title={form?.name || 'Űrlap'} /> + <CmschPage title={form?.name || 'Űrlap'}> <Box w="100%" mx="auto"> <Heading as="h1" variant="main-title"> {form?.name || 'Űrlap'} diff --git a/frontend/src/pages/home/components/EmbeddedVideo.tsx b/frontend/src/pages/home/components/EmbeddedVideo.tsx index 58eeaa295..d1bcf8f3c 100644 --- a/frontend/src/pages/home/components/EmbeddedVideo.tsx +++ b/frontend/src/pages/home/components/EmbeddedVideo.tsx @@ -1,5 +1,5 @@ import { Box } from '@chakra-ui/react' -import { FC } from 'react' +import type { FC } from 'react' type EmbeddedVideoProps = { id: string | undefined diff --git a/frontend/src/pages/home/components/HomePageNewsList.tsx b/frontend/src/pages/home/components/HomePageNewsList.tsx index c0082b62a..f9336e2b8 100644 --- a/frontend/src/pages/home/components/HomePageNewsList.tsx +++ b/frontend/src/pages/home/components/HomePageNewsList.tsx @@ -1,7 +1,7 @@ import { Grid } from '@chakra-ui/react' import { useConfigContext } from '../../../api/contexts/config/ConfigContext.tsx' import { useHomeNews } from '../../../api/hooks/home/useHomeNews.tsx' -import { NewsArticleView } from '../../../util/views/news.view.ts' +import type { NewsArticleView } from '../../../util/views/news.view.ts' import { NewsListItem } from '../../news/components/NewsListItem.tsx' const sortByHighlighted = (news: NewsArticleView[]) => { diff --git a/frontend/src/pages/home/components/ImageCarousel.tsx b/frontend/src/pages/home/components/ImageCarousel.tsx index 8808ff2a0..92235702e 100644 --- a/frontend/src/pages/home/components/ImageCarousel.tsx +++ b/frontend/src/pages/home/components/ImageCarousel.tsx @@ -80,10 +80,11 @@ type DirectionButtonProps = { onClick: () => void } -enum Directions { - LEFT = 'left', - RIGHT = 'right' +const Directions = { + LEFT: 'left', + RIGHT: 'right' } +type Directions = (typeof Directions)[keyof typeof Directions] const DirectionButton = ({ direction, onClick }: DirectionButtonProps) => ( <IconButton diff --git a/frontend/src/pages/home/components/Schedule.tsx b/frontend/src/pages/home/components/Schedule.tsx index b846f6b42..319c9ec69 100644 --- a/frontend/src/pages/home/components/Schedule.tsx +++ b/frontend/src/pages/home/components/Schedule.tsx @@ -3,7 +3,7 @@ import { Link } from 'react-router' import { useConfigContext } from '../../../api/contexts/config/ConfigContext' import { useBrandColor } from '../../../util/core-functions.util.ts' import { AbsolutePaths } from '../../../util/paths' -import { EventListView } from '../../../util/views/event.view' +import type { EventListView } from '../../../util/views/event.view' type ScheduleProps = { events: EventListView[] diff --git a/frontend/src/pages/home/home.page.tsx b/frontend/src/pages/home/home.page.tsx index 40351d785..9f68bbe97 100644 --- a/frontend/src/pages/home/home.page.tsx +++ b/frontend/src/pages/home/home.page.tsx @@ -1,6 +1,5 @@ import { Box, Heading } from '@chakra-ui/react' import { useMemo } from 'react' -import { Helmet } from 'react-helmet-async' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { ComponentUnavailable } from '../../common-components/ComponentUnavailable' @@ -37,7 +36,6 @@ const HomePage = () => { return ( <CmschPage> - <Helmet /> {homeConfig?.welcomeMessage && ( <Heading variant="main-title" as="h1" size="3xl" textAlign="center" marginTop={10} lineHeight="1.2"> {homeConfig?.welcomeMessage.split('{}')[0] + ' '} diff --git a/frontend/src/pages/impressum/components/DeveloperWrapItem.tsx b/frontend/src/pages/impressum/components/DeveloperWrapItem.tsx index 20902e674..ec767f404 100644 --- a/frontend/src/pages/impressum/components/DeveloperWrapItem.tsx +++ b/frontend/src/pages/impressum/components/DeveloperWrapItem.tsx @@ -1,5 +1,5 @@ import { Flex, HStack, Image, Tag, Text } from '@chakra-ui/react' -import { Dev } from '../../../api/hooks/developers/useDevelopers' +import type { Dev } from '../../../api/hooks/developers/useDevelopers' import { API_BASE_URL } from '../../../util/configs/environment.config' import { KirDevColor } from '../../../util/configs/theme.config' diff --git a/frontend/src/pages/impressum/components/OrganizerSection.tsx b/frontend/src/pages/impressum/components/OrganizerSection.tsx index 666aef054..d59d2c655 100644 --- a/frontend/src/pages/impressum/components/OrganizerSection.tsx +++ b/frontend/src/pages/impressum/components/OrganizerSection.tsx @@ -1,5 +1,5 @@ import { Box, Heading, Wrap } from '@chakra-ui/react' -import { Organizer } from '../../../api/contexts/config/types' +import type { Organizer } from '../../../api/contexts/config/types' import Markdown from '../../../common-components/Markdown' import { OrganizerWrapItem } from './OrganizerWrapItem' diff --git a/frontend/src/pages/impressum/components/OrganizerWrapItem.tsx b/frontend/src/pages/impressum/components/OrganizerWrapItem.tsx index b1b16e2e6..664057811 100644 --- a/frontend/src/pages/impressum/components/OrganizerWrapItem.tsx +++ b/frontend/src/pages/impressum/components/OrganizerWrapItem.tsx @@ -1,5 +1,5 @@ import { Avatar, HStack, Text, useColorModeValue, VStack, WrapItem } from '@chakra-ui/react' -import { Organizer } from '../../../api/contexts/config/types' +import type { Organizer } from '../../../api/contexts/config/types' type Props = { organizer: Organizer diff --git a/frontend/src/pages/impressum/impressum.page.tsx b/frontend/src/pages/impressum/impressum.page.tsx index 0206859de..facbe9682 100644 --- a/frontend/src/pages/impressum/impressum.page.tsx +++ b/frontend/src/pages/impressum/impressum.page.tsx @@ -1,5 +1,4 @@ import { Heading, Wrap } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useDevelopers } from '../../api/hooks/developers/useDevelopers' @@ -10,16 +9,13 @@ import { DeveloperWrapItem } from './components/DeveloperWrapItem' import { OrganizerSection } from './components/OrganizerSection' const ImpressumPage = () => { - const config = useConfigContext() const developers = useDevelopers() - - const component = config?.components?.impressum + const component = useConfigContext()?.components?.impressum if (!component) return <ComponentUnavailable /> return ( - <CmschPage> - <Helmet title={component.title} /> + <CmschPage title={component?.title}> <Heading as="h1" variant="main-title"> {component.title} </Heading> diff --git a/frontend/src/pages/impressum/util/arrayFunctions.ts b/frontend/src/pages/impressum/util/arrayFunctions.ts index 73bed6581..1c3c68ae2 100644 --- a/frontend/src/pages/impressum/util/arrayFunctions.ts +++ b/frontend/src/pages/impressum/util/arrayFunctions.ts @@ -1,3 +1,3 @@ -import { Organizer } from '../../../api/contexts/config/types' +import type { Organizer } from '../../../api/contexts/config/types' export const parseOrganizerArrayJSON = (array: string | undefined): Organizer[] => JSON.parse(array || '[]') diff --git a/frontend/src/pages/leaderboard/leaderboard.page.tsx b/frontend/src/pages/leaderboard/leaderboard.page.tsx index 9a8021381..cab2d8f59 100644 --- a/frontend/src/pages/leaderboard/leaderboard.page.tsx +++ b/frontend/src/pages/leaderboard/leaderboard.page.tsx @@ -1,5 +1,4 @@ import { Box, Heading, HStack, Tab, TabList, TabPanel, TabPanels, Tabs } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { useMatch, useNavigate } from 'react-router' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useLeaderBoardQuery } from '../../api/hooks/leaderboard/useLeaderBoardQuery' @@ -39,12 +38,10 @@ const LeaderboardPage = () => { } return ( - <CmschPage disablePadding={true}> - <Helmet title={title} /> + <CmschPage disablePadding={true} title={title}> <Heading as="h1" variant="main-title" textAlign="center" m="2rem"> {title} </Heading> - {component.topMessage ? ( <Box textAlign="center"> <Markdown text={component.topMessage} /> @@ -52,12 +49,10 @@ const LeaderboardPage = () => { ) : ( <></> )} - <HStack my={5}> {data?.userScore !== undefined && <BoardStat label="Saját pont" value={data.userScore} />} {data?.groupScore !== undefined && <BoardStat label={`${component.myGroupName} pontjai`} value={data.groupScore} />} </HStack> - <Tabs isLazy isFitted colorScheme={brandColor} variant="enclosed" index={tabIndex} onChange={onTabSelected}> <TabList> <Tab>{component.groupBoardName}</Tab> diff --git a/frontend/src/pages/login/login.page.tsx b/frontend/src/pages/login/login.page.tsx index 7337467b4..9d2968fae 100644 --- a/frontend/src/pages/login/login.page.tsx +++ b/frontend/src/pages/login/login.page.tsx @@ -1,5 +1,4 @@ import { Box, Button, Text, VStack } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { FaGoogle, FaKey, FaSignInAlt } from 'react-icons/fa' import { Navigate } from 'react-router' @@ -14,8 +13,7 @@ import { l } from '../../util/language' const LoginPage = () => { const { isLoggedIn } = useAuthContext() - const config = useConfigContext() - const component = config?.components?.login + const component = useConfigContext()?.components?.login const brandColor = useBrandColor() if (!component) return <ComponentUnavailable /> @@ -23,8 +21,7 @@ const LoginPage = () => { if (isLoggedIn) return <Navigate replace to="/" /> return ( - <CmschPage> - <Helmet title={l('login-helmet')} /> + <CmschPage title={l('login-helmet')}> <VStack spacing={10} mb={10}> {component.topMessage ? ( <Box textAlign="center"> diff --git a/frontend/src/pages/map/map.page.tsx b/frontend/src/pages/map/map.page.tsx index 9fcec9319..78081a2fa 100644 --- a/frontend/src/pages/map/map.page.tsx +++ b/frontend/src/pages/map/map.page.tsx @@ -1,6 +1,5 @@ import { Box, Checkbox, Heading, Text } from '@chakra-ui/react' import { useState } from 'react' -import { Helmet } from 'react-helmet-async' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useLocationQuery } from '../../api/hooks/location/useLocationQuery' import { CmschPage } from '../../common-components/layout/CmschPage' @@ -14,8 +13,7 @@ export default function MapPage() { const component = useConfigContext()?.components?.location return ( - <CmschPage> - <Helmet>Térkép</Helmet> + <CmschPage title={component?.title || 'Térkép'}> <Heading as="h1" variant="main-title"> Térkép </Heading> diff --git a/frontend/src/pages/news/components/News.tsx b/frontend/src/pages/news/components/News.tsx index 822f98144..10e17ad1c 100644 --- a/frontend/src/pages/news/components/News.tsx +++ b/frontend/src/pages/news/components/News.tsx @@ -5,7 +5,7 @@ import { CustomBreadcrumb } from '../../../common-components/CustomBreadcrumb' import Markdown from '../../../common-components/Markdown' import { stringifyTimeStamp, useBrandColor } from '../../../util/core-functions.util' import { AbsolutePaths } from '../../../util/paths' -import { NewsArticleView } from '../../../util/views/news.view' +import type { NewsArticleView } from '../../../util/views/news.view' interface NewsProps { news: NewsArticleView diff --git a/frontend/src/pages/news/components/NewsList.tsx b/frontend/src/pages/news/components/NewsList.tsx index b66ea3f82..acaf5960d 100644 --- a/frontend/src/pages/news/components/NewsList.tsx +++ b/frontend/src/pages/news/components/NewsList.tsx @@ -4,7 +4,7 @@ import debounce from 'lodash/debounce' import { createRef, useMemo, useState } from 'react' import { useConfigContext } from '../../../api/contexts/config/ConfigContext' -import { NewsArticleView } from '../../../util/views/news.view' +import type { NewsArticleView } from '../../../util/views/news.view' import { NewsListItem } from './NewsListItem' interface NewsListProps { diff --git a/frontend/src/pages/news/components/NewsListItem.tsx b/frontend/src/pages/news/components/NewsListItem.tsx index 784124c61..559aba753 100644 --- a/frontend/src/pages/news/components/NewsListItem.tsx +++ b/frontend/src/pages/news/components/NewsListItem.tsx @@ -4,7 +4,7 @@ import { Link } from 'react-router' import Markdown from '../../../common-components/Markdown' import { stringifyTimeStamp, useBrandColor } from '../../../util/core-functions.util' import { AbsolutePaths } from '../../../util/paths' -import { NewsArticleView } from '../../../util/views/news.view' +import type { NewsArticleView } from '../../../util/views/news.view' type Props = { news: NewsArticleView diff --git a/frontend/src/pages/news/news.page.tsx b/frontend/src/pages/news/news.page.tsx index b762fd3c1..c2ea4bf2b 100644 --- a/frontend/src/pages/news/news.page.tsx +++ b/frontend/src/pages/news/news.page.tsx @@ -1,4 +1,3 @@ -import { Helmet } from 'react-helmet-async' import { useParams } from 'react-router' import { useNewsQuery } from '../../api/hooks/news/useNewsQuery' import { CmschPage } from '../../common-components/layout/CmschPage' @@ -12,8 +11,7 @@ const NewsPage = () => { if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title="Hír" /> return ( - <CmschPage> - <Helmet title={data.title} /> + <CmschPage title={data.title}> <News news={data} /> </CmschPage> ) diff --git a/frontend/src/pages/news/newsList.page.tsx b/frontend/src/pages/news/newsList.page.tsx index e84833408..08da7912f 100644 --- a/frontend/src/pages/news/newsList.page.tsx +++ b/frontend/src/pages/news/newsList.page.tsx @@ -1,5 +1,3 @@ -import { Helmet } from 'react-helmet-async' - import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useNewsListQuery } from '../../api/hooks/news/useNewsListQuery' import { ComponentUnavailable } from '../../common-components/ComponentUnavailable' @@ -17,8 +15,7 @@ const NewsListPage = () => { if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={component?.title} /> return ( - <CmschPage> - <Helmet title={component.title} /> + <CmschPage title={component?.title}> <NewsList newsList={sortNewsList(data)} /> </CmschPage> ) diff --git a/frontend/src/pages/news/util/sortNewsList.ts b/frontend/src/pages/news/util/sortNewsList.ts index fd3a2467f..cf1aa9f13 100644 --- a/frontend/src/pages/news/util/sortNewsList.ts +++ b/frontend/src/pages/news/util/sortNewsList.ts @@ -1,4 +1,4 @@ -import { NewsArticleView } from '../../../util/views/news.view' +import type { NewsArticleView } from '../../../util/views/news.view' export const sortNewsList = (newsList: NewsArticleView[]) => newsList.sort((a, b) => (a.highlighted === b.highlighted ? 0 : a.highlighted ? -1 : 1)) diff --git a/frontend/src/pages/profile/components/GroupLeaderContactList.tsx b/frontend/src/pages/profile/components/GroupLeaderContactList.tsx index d9931caed..18ede9020 100644 --- a/frontend/src/pages/profile/components/GroupLeaderContactList.tsx +++ b/frontend/src/pages/profile/components/GroupLeaderContactList.tsx @@ -1,7 +1,7 @@ import { Box, Heading, HStack, Text, useColorModeValue, VStack } from '@chakra-ui/react' import { FaFacebook, FaPhone } from 'react-icons/fa' import { LinkButton } from '../../../common-components/LinkButton' -import { ProfileView } from '../../../util/views/profile.view' +import type { ProfileView } from '../../../util/views/profile.view' export const GroupLeaderContactList = ({ profile }: { profile: ProfileView }) => { const bg = useColorModeValue('#00000005', '#FFFFFF05') diff --git a/frontend/src/pages/profile/components/Popup.tsx b/frontend/src/pages/profile/components/Popup.tsx index cfeb4cc99..096098b9e 100644 --- a/frontend/src/pages/profile/components/Popup.tsx +++ b/frontend/src/pages/profile/components/Popup.tsx @@ -1,6 +1,6 @@ import { Box, CloseButton, Flex, Heading, Text } from '@chakra-ui/react' import { forwardRef } from 'react' -import { GroupMemberLocationView } from '../../../util/views/groupMemberLocation.view' +import type { GroupMemberLocationView } from '../../../util/views/groupMemberLocation.view' import { timestampToTimePassedStr } from '../util/timestampToTimePassedStr' type PopupProps = { diff --git a/frontend/src/pages/profile/components/ProfileQR.tsx b/frontend/src/pages/profile/components/ProfileQR.tsx index b27539501..5ff505706 100644 --- a/frontend/src/pages/profile/components/ProfileQR.tsx +++ b/frontend/src/pages/profile/components/ProfileQR.tsx @@ -13,10 +13,10 @@ import { } from '@chakra-ui/react' import { FaQrcode } from 'react-icons/fa' import QRCode from 'react-qr-code' -import { Profile } from '../../../api/contexts/config/types' +import type { Profile } from '../../../api/contexts/config/types' import { WalletButton } from '../../../common-components/WalletButton' import { useBrandColor } from '../../../util/core-functions.util.ts' -import { ProfileView } from '../../../util/views/profile.view' +import type { ProfileView } from '../../../util/views/profile.view' export const ProfileQR = ({ profile, component }: { profile: ProfileView; component: Profile }) => { const { isOpen, onOpen, onClose } = useDisclosure() diff --git a/frontend/src/pages/profile/profile.aliasChange.page.tsx b/frontend/src/pages/profile/profile.aliasChange.page.tsx index 0aea25198..091b73425 100644 --- a/frontend/src/pages/profile/profile.aliasChange.page.tsx +++ b/frontend/src/pages/profile/profile.aliasChange.page.tsx @@ -1,6 +1,5 @@ import { Box, Button, ButtonGroup, FormControl, FormLabel, Heading, Input, useToast } from '@chakra-ui/react' -import { FormEvent, useState } from 'react' -import { Helmet } from 'react-helmet-async' +import { type FormEvent, useState } from 'react' import { Navigate, useNavigate } from 'react-router' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useAliasChangeMutation } from '../../api/hooks/alias/useAliasChangeMutation' @@ -64,8 +63,7 @@ export const AliasChangePage = () => { } return ( - <CmschPage> - <Helmet title="Becenév módosítása" /> + <CmschPage title="Becenév módosítása"> <Heading my={5}>Becenév módosítása</Heading> <Box display="flex" flexDirection="column" as="form" onSubmit={onSubmitAlias}> <FormControl> diff --git a/frontend/src/pages/profile/profile.groupChange.page.tsx b/frontend/src/pages/profile/profile.groupChange.page.tsx index 7b32ddc07..e814b7da4 100644 --- a/frontend/src/pages/profile/profile.groupChange.page.tsx +++ b/frontend/src/pages/profile/profile.groupChange.page.tsx @@ -1,6 +1,5 @@ import { Button, ButtonGroup, FormControl, FormLabel, Heading, Select, Text, VStack } from '@chakra-ui/react' import { useState } from 'react' -import { Helmet } from 'react-helmet-async' import { Navigate, useNavigate } from 'react-router' import { useServiceContext } from '../../api/contexts/service/ServiceContext' import { useGroupChangeMutation } from '../../api/hooks/group-change/useGroupChangeMutation' @@ -10,8 +9,8 @@ import { LinkButton } from '../../common-components/LinkButton' import { PageStatus } from '../../common-components/PageStatus.tsx' import { useBrandColor } from '../../util/core-functions.util.ts' import { AbsolutePaths } from '../../util/paths' -import { GroupChangeDTO, GroupChangeStatus } from '../../util/views/groupChange.view' -import { ProfileView } from '../../util/views/profile.view.ts' +import { type GroupChangeDTO, GroupChangeStatus } from '../../util/views/groupChange.view' +import type { ProfileView } from '../../util/views/profile.view.ts' export function ProfileGroupChangePage() { const { isLoading, isError, data: profile, refetch } = useProfileQuery() @@ -65,8 +64,7 @@ function ProfileGroupChangeBody({ profile, refetch }: { profile: ProfileView; re } return ( - <CmschPage> - <Helmet title="Tankör beállítása" /> + <CmschPage title="Tankör beállítása"> <Heading>Tankör beállítása</Heading> <Text mt={10} textAlign="center"> Állítsd be a tankörödet, hogy részt vehess a feladatokban! diff --git a/frontend/src/pages/profile/profile.page.tsx b/frontend/src/pages/profile/profile.page.tsx index 04708b343..489665d29 100644 --- a/frontend/src/pages/profile/profile.page.tsx +++ b/frontend/src/pages/profile/profile.page.tsx @@ -15,7 +15,7 @@ import { useColorModeValue, VStack } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' + import { Navigate, useNavigate } from 'react-router' import React, { useEffect } from 'react' @@ -71,8 +71,7 @@ const ProfilePage = () => { const raceStats = profile?.raceStats return ( - <CmschPage loginRequired> - <Helmet title={component.title} /> + <CmschPage loginRequired={true} title={component?.title}> {component.messageBoxContent && ( <Alert status="info" variant="left-accent" mt={5}> <AlertIcon /> diff --git a/frontend/src/pages/profile/util/percentFunctions.ts b/frontend/src/pages/profile/util/percentFunctions.ts index f755f0345..00353a8ac 100644 --- a/frontend/src/pages/profile/util/percentFunctions.ts +++ b/frontend/src/pages/profile/util/percentFunctions.ts @@ -1,4 +1,4 @@ -import { ProfileView } from '../../../util/views/profile.view' +import type { ProfileView } from '../../../util/views/profile.view' const percent = (dividend: number, divisor: number) => (divisor != 0 ? (dividend / divisor) * 100 : 0) diff --git a/frontend/src/pages/qr-fight/components/DataDisplayWrapper.tsx b/frontend/src/pages/qr-fight/components/DataDisplayWrapper.tsx index 29d6c11b2..ac81ea10e 100644 --- a/frontend/src/pages/qr-fight/components/DataDisplayWrapper.tsx +++ b/frontend/src/pages/qr-fight/components/DataDisplayWrapper.tsx @@ -3,7 +3,7 @@ import { Heading, HStack, Text, VStack } from '@chakra-ui/react' import isEmpty from 'lodash/isEmpty' import Markdown from '../../../common-components/Markdown' import { useOpaqueBackground } from '../../../util/core-functions.util' -import { LevelStatus, QrLevelDto } from '../../../util/views/qrFight.view' +import { LevelStatus, type QrLevelDto } from '../../../util/views/qrFight.view' import { LevelDataDisplay } from './LevelDataDisplay' import { LevelStatusBadge } from './LevelStatusBadge' import { TotemDataDisplay } from './TotemDataDisplay' diff --git a/frontend/src/pages/qr-fight/components/TotemDataDisplay.tsx b/frontend/src/pages/qr-fight/components/TotemDataDisplay.tsx index 20bd63946..a4f4439aa 100644 --- a/frontend/src/pages/qr-fight/components/TotemDataDisplay.tsx +++ b/frontend/src/pages/qr-fight/components/TotemDataDisplay.tsx @@ -1,5 +1,5 @@ import { Flex, Heading, VStack } from '@chakra-ui/react' -import { QrLevelDto } from '../../../util/views/qrFight.view' +import type { QrLevelDto } from '../../../util/views/qrFight.view' import { TotemField } from './TotemField' interface TotemDataDisplay { diff --git a/frontend/src/pages/qr-fight/components/TowerDataDisplay.tsx b/frontend/src/pages/qr-fight/components/TowerDataDisplay.tsx index 4ee05f8f1..67d1e4760 100644 --- a/frontend/src/pages/qr-fight/components/TowerDataDisplay.tsx +++ b/frontend/src/pages/qr-fight/components/TowerDataDisplay.tsx @@ -1,5 +1,5 @@ import { Flex, Heading, VStack } from '@chakra-ui/react' -import { QrLevelDto } from '../../../util/views/qrFight.view' +import type { QrLevelDto } from '../../../util/views/qrFight.view' import { TowerField } from './TowerField' interface TowerDataDisplay { diff --git a/frontend/src/pages/qr-fight/components/TowerField.tsx b/frontend/src/pages/qr-fight/components/TowerField.tsx index 55fc97702..7f63ae0d7 100644 --- a/frontend/src/pages/qr-fight/components/TowerField.tsx +++ b/frontend/src/pages/qr-fight/components/TowerField.tsx @@ -1,6 +1,6 @@ import { Divider, Stat, StatHelpText, StatLabel, StatNumber, VStack } from '@chakra-ui/react' import { useOpaqueBackground } from '../../../util/core-functions.util' -import { Tower } from '../../../util/views/qrFight.view' +import type { Tower } from '../../../util/views/qrFight.view' interface TowerFieldProps { tower: Tower diff --git a/frontend/src/pages/qr-fight/components/TreasureDataDisplayWrapper.tsx b/frontend/src/pages/qr-fight/components/TreasureDataDisplayWrapper.tsx index f26808c72..c53352f28 100644 --- a/frontend/src/pages/qr-fight/components/TreasureDataDisplayWrapper.tsx +++ b/frontend/src/pages/qr-fight/components/TreasureDataDisplayWrapper.tsx @@ -3,7 +3,7 @@ import { Heading, HStack, Text, VStack } from '@chakra-ui/react' import isEmpty from 'lodash/isEmpty' import Markdown from '../../../common-components/Markdown' import { useOpaqueBackground } from '../../../util/core-functions.util' -import { LevelStatus, QrTreasureHuntDto } from '../../../util/views/qrFight.view' +import { LevelStatus, type QrTreasureHuntDto } from '../../../util/views/qrFight.view' import { LevelDataDisplay } from './LevelDataDisplay' import { LevelStatusBadge } from './LevelStatusBadge' diff --git a/frontend/src/pages/qr-fight/qrLevels.page.tsx b/frontend/src/pages/qr-fight/qrLevels.page.tsx index 316f3f265..0cb45de90 100644 --- a/frontend/src/pages/qr-fight/qrLevels.page.tsx +++ b/frontend/src/pages/qr-fight/qrLevels.page.tsx @@ -1,5 +1,4 @@ import { Flex, Heading, TabList, TabPanel, TabPanels, Tabs, useBreakpoint, useBreakpointValue } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { FaQrcode } from 'react-icons/fa' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useQrLevelsQuery } from '../../api/hooks/qr/useQrLevelsQuery' @@ -26,8 +25,7 @@ export default function QrLevelsPage() { if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={component.title} /> return ( - <CmschPage> - <Helmet>{component.title}</Helmet> + <CmschPage title={component.title}> <Flex align="baseline" justifyContent="space-between" wrap="wrap"> <Heading as="h1" variant="main-title" mt={5}> {component.title} diff --git a/frontend/src/pages/race/components/RaceBoard.tsx b/frontend/src/pages/race/components/RaceBoard.tsx index 9dd1db2c9..68df8e640 100644 --- a/frontend/src/pages/race/components/RaceBoard.tsx +++ b/frontend/src/pages/race/components/RaceBoard.tsx @@ -1,14 +1,13 @@ import { Divider, Flex, Heading } from '@chakra-ui/react' import { useMemo } from 'react' -import { Helmet } from 'react-helmet-async' -import { Race } from '../../../api/contexts/config/types' +import type { Race } from '../../../api/contexts/config/types' import { BoardStat } from '../../../common-components/BoardStat' import { ComponentUnavailable } from '../../../common-components/ComponentUnavailable' import { CmschPage } from '../../../common-components/layout/CmschPage' import { LeaderBoardTable } from '../../../common-components/LeaderboardTable' import Markdown from '../../../common-components/Markdown' import { PageStatus } from '../../../common-components/PageStatus' -import { RaceView } from '../../../util/views/race.view' +import type { RaceView } from '../../../util/views/race.view' type Props = { data: RaceView | undefined @@ -24,8 +23,7 @@ const RaceBoard = ({ data, component, isError, isLoading }: Props) => { if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={component.title} /> return ( - <CmschPage> - <Helmet title={data.categoryName} /> + <CmschPage title={data.categoryName}> <Heading as="h1" variant="main-title" mb={3}> {data.categoryName} </Heading> diff --git a/frontend/src/pages/riddle/components/RiddleCategoryListItem.tsx b/frontend/src/pages/riddle/components/RiddleCategoryListItem.tsx index 4f6938c3d..99c41e284 100644 --- a/frontend/src/pages/riddle/components/RiddleCategoryListItem.tsx +++ b/frontend/src/pages/riddle/components/RiddleCategoryListItem.tsx @@ -1,6 +1,6 @@ import { Box, CircularProgress, Flex, HStack, Text } from '@chakra-ui/react' import { useOpaqueBackground } from '../../../util/core-functions.util' -import { RiddleCategory } from '../../../util/views/riddle.view' +import type { RiddleCategory } from '../../../util/views/riddle.view' interface RiddleCategoryListItemProps { category: RiddleCategory diff --git a/frontend/src/pages/riddle/components/RiddleListItem.tsx b/frontend/src/pages/riddle/components/RiddleListItem.tsx index 3daece1d7..7042f056a 100644 --- a/frontend/src/pages/riddle/components/RiddleListItem.tsx +++ b/frontend/src/pages/riddle/components/RiddleListItem.tsx @@ -1,6 +1,6 @@ import { Box, Text } from '@chakra-ui/react' import { useOpaqueBackground } from '../../../util/core-functions.util.ts' -import { Riddle } from '../../../util/views/riddle.view.ts' +import type { Riddle } from '../../../util/views/riddle.view.ts' interface RiddleListItemProps { riddle: Riddle diff --git a/frontend/src/pages/riddle/riddle.page.tsx b/frontend/src/pages/riddle/riddle.page.tsx index ddcc96ae1..b990f2568 100644 --- a/frontend/src/pages/riddle/riddle.page.tsx +++ b/frontend/src/pages/riddle/riddle.page.tsx @@ -9,13 +9,12 @@ import { Image, Input, Text, - ToastId, + type ToastId, useDisclosure, useToast, VStack } from '@chakra-ui/react' -import { FormEvent, useRef, useState } from 'react' -import { Helmet } from 'react-helmet-async' +import { type FormEvent, useRef, useState } from 'react' import { Navigate, useNavigate, useParams } from 'react-router' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useRiddleDetailsQuery } from '../../api/hooks/riddle/useRiddleDeatilsQuery' @@ -166,8 +165,7 @@ const RiddlePage = () => { ] return ( - <CmschPage loginRequired> - <Helmet title={data.title} /> + <CmschPage loginRequired={true} title={data.title}> <CustomBreadcrumb items={breadcrumbItems} /> <StopItModal isOpen={isOpen} onClose={onClose} /> <Heading my={5}> {data.title} </Heading> diff --git a/frontend/src/pages/riddle/riddleCategory.page.tsx b/frontend/src/pages/riddle/riddleCategory.page.tsx index fbf467620..b20eb301b 100644 --- a/frontend/src/pages/riddle/riddleCategory.page.tsx +++ b/frontend/src/pages/riddle/riddleCategory.page.tsx @@ -1,5 +1,4 @@ import { Button, Heading, Stack, Text, VStack } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { Link, useNavigate, useParams } from 'react-router' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useRiddleListQuery } from '../../api/hooks/riddle/useRiddleListQuery.ts' @@ -32,8 +31,7 @@ const RiddleCategoryPage = () => { } ] return ( - <CmschPage> - <Helmet title="Riddleök" /> + <CmschPage title={component?.title}> <CustomBreadcrumb items={breadcrumbItems} /> <Stack direction={['column', 'row']} justify="space-between" align={['flex-start', 'flex-end']}> <Heading as="h1" variant="main-title"> diff --git a/frontend/src/pages/riddle/riddleHistory.page.tsx b/frontend/src/pages/riddle/riddleHistory.page.tsx index f22cdac1d..6a3228170 100644 --- a/frontend/src/pages/riddle/riddleHistory.page.tsx +++ b/frontend/src/pages/riddle/riddleHistory.page.tsx @@ -1,6 +1,5 @@ import { Box, Button, Center, Heading, HStack, Image, Select, Stack, Text, useToast, VStack } from '@chakra-ui/react' import { useEffect, useState } from 'react' -import { Helmet } from 'react-helmet-async' import { FaArrowLeft, FaArrowRight } from 'react-icons/fa' import { useNavigate } from 'react-router' import { useRiddleHistoryQuery } from '../../api/hooks/riddle/useRiddleHistoryQuery' @@ -60,8 +59,7 @@ const RiddleHistoryPage = () => { } ] return ( - <CmschPage> - <Helmet title="Megoldott riddleök" /> + <CmschPage title="Megoldott riddleök"> <CustomBreadcrumb items={breadcrumbItems} /> <Stack direction={['column', 'row']} justify="space-between" align={['flex-start', 'center']}> <Heading as="h1" variant="main-title" my={5}> @@ -86,7 +84,6 @@ const RiddleHistoryPage = () => { )} </Stack> </Stack> - {!riddle || !riddleList ? ( <> <Text mt={2}>Ebben a kategóriában még nincsenek megoldott riddleök.</Text> diff --git a/frontend/src/pages/riddle/riddleList.page.tsx b/frontend/src/pages/riddle/riddleList.page.tsx index 97748d3c0..2f9bf3cae 100644 --- a/frontend/src/pages/riddle/riddleList.page.tsx +++ b/frontend/src/pages/riddle/riddleList.page.tsx @@ -1,5 +1,4 @@ import { Button, Heading, Stack, Text, useToast, VStack } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { Link, useNavigate } from 'react-router' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useRiddleListQuery } from '../../api/hooks/riddle/useRiddleListQuery' @@ -9,7 +8,7 @@ import { PageStatus } from '../../common-components/PageStatus' import { useBrandColor } from '../../util/core-functions.util.ts' import { l } from '../../util/language' import { AbsolutePaths } from '../../util/paths' -import { RiddleCategory } from '../../util/views/riddle.view.ts' +import type { RiddleCategory } from '../../util/views/riddle.view.ts' import { RiddleCategoryListItem } from './components/RiddleCategoryListItem' const RiddleCategoryList = () => { @@ -40,8 +39,7 @@ const RiddleCategoryList = () => { } return ( - <CmschPage> - <Helmet title="Riddleök" /> + <CmschPage title={component?.title}> <Stack direction={['column', 'row']} justify="space-between" align={['flex-start', 'flex-end']}> <Heading as="h1" variant="main-title"> Riddleök diff --git a/frontend/src/pages/task/components/CodeEditor.tsx b/frontend/src/pages/task/components/CodeEditor.tsx index 9cfc7fb0b..9dac5b003 100644 --- a/frontend/src/pages/task/components/CodeEditor.tsx +++ b/frontend/src/pages/task/components/CodeEditor.tsx @@ -1,5 +1,5 @@ import { Box, Flex, Select, Stack } from '@chakra-ui/react' -import { Grammar, highlight, languages } from 'prismjs' +import { type Grammar, highlight, languages } from 'prismjs' import 'prismjs/components/prism-c' import 'prismjs/components/prism-cpp' import 'prismjs/components/prism-csharp' @@ -12,7 +12,7 @@ import 'prismjs/components/prism-typescript' import 'prismjs/themes/prism-okaidia.css' import { useState } from 'react' import Editor from 'react-simple-code-editor' -import { codeLanguage } from '../../../util/views/task.view' +import { CodeLanguage } from '../../../util/views/task.view' interface CodeEditorProps { code: string @@ -21,32 +21,32 @@ interface CodeEditorProps { } const LANGUAGE_GRAMMAR_MAP = new Map<string, Grammar>([ - [codeLanguage.C, languages.c], - [codeLanguage.CPP, languages.cpp], - [codeLanguage.CSHARP, languages.csharp], - [codeLanguage.JAVA, languages.java], - [codeLanguage.JAVASCRIPT, languages.javascript], - [codeLanguage.TYPESCRIPT, languages.typescript], - [codeLanguage.SQL, languages.sql], - [codeLanguage.KOTLIN, languages.kotlin], - [codeLanguage.PYTHON, languages.python] + [CodeLanguage.C, languages.c], + [CodeLanguage.CPP, languages.cpp], + [CodeLanguage.CSHARP, languages.csharp], + [CodeLanguage.JAVA, languages.java], + [CodeLanguage.JAVASCRIPT, languages.javascript], + [CodeLanguage.TYPESCRIPT, languages.typescript], + [CodeLanguage.SQL, languages.sql], + [CodeLanguage.KOTLIN, languages.kotlin], + [CodeLanguage.PYTHON, languages.python] ]) const CodeEditor = ({ code, setCode, readonly }: CodeEditorProps) => { - const [selectedLanguage, setSelectedLanguage] = useState<string>(codeLanguage.C) + const [selectedLanguage, setSelectedLanguage] = useState<string>(CodeLanguage.C) return ( <Stack mt={5}> <Flex justify="flex-end"> <Select onChange={(e) => setSelectedLanguage(e.target.value)} w="10rem" value={selectedLanguage}> - <option value={codeLanguage.C}>C</option> - <option value={codeLanguage.CPP}>C++</option> - <option value={codeLanguage.CSHARP}>C#</option> - <option value={codeLanguage.JAVA}>JAVA</option> - <option value={codeLanguage.JAVASCRIPT}>JavaScript</option> - <option value={codeLanguage.TYPESCRIPT}>TypeScript</option> - <option value={codeLanguage.SQL}>SQL</option> - <option value={codeLanguage.KOTLIN}>Kotlin</option> - <option value={codeLanguage.PYTHON}>Python</option> + <option value={CodeLanguage.C}>C</option> + <option value={CodeLanguage.CPP}>C++</option> + <option value={CodeLanguage.CSHARP}>C#</option> + <option value={CodeLanguage.JAVA}>JAVA</option> + <option value={CodeLanguage.JAVASCRIPT}>JavaScript</option> + <option value={CodeLanguage.TYPESCRIPT}>TypeScript</option> + <option value={CodeLanguage.SQL}>SQL</option> + <option value={CodeLanguage.KOTLIN}>Kotlin</option> + <option value={CodeLanguage.PYTHON}>Python</option> </Select> </Flex> diff --git a/frontend/src/pages/task/components/CustomForm.tsx b/frontend/src/pages/task/components/CustomForm.tsx index 3472dc49f..3778e908d 100644 --- a/frontend/src/pages/task/components/CustomForm.tsx +++ b/frontend/src/pages/task/components/CustomForm.tsx @@ -1,10 +1,10 @@ import { Box, FormLabel, Input, Textarea, useToast } from '@chakra-ui/react' import { useEffect } from 'react' -import { Control, Controller, FieldArrayWithId, UseFieldArrayReplace } from 'react-hook-form' +import { type Control, Controller, type FieldArrayWithId, type UseFieldArrayReplace } from 'react-hook-form' import { useNavigate } from 'react-router' import { AbsolutePaths } from '../../../util/paths' -import { TaskFormatDescriptor } from '../../../util/views/task.view' -import { FormInput } from '../task.page' +import type { TaskFormatDescriptor } from '../../../util/views/task.view' +import type { FormInput } from '../task.page' import { InputWithAddon } from './InputWithAddon' type CustomFormProps = { diff --git a/frontend/src/pages/task/components/FilePicker.tsx b/frontend/src/pages/task/components/FilePicker.tsx index 836424cf7..311be6124 100644 --- a/frontend/src/pages/task/components/FilePicker.tsx +++ b/frontend/src/pages/task/components/FilePicker.tsx @@ -1,7 +1,7 @@ // from https://github.com/PedroDBFlores/chakra-ui-file-picker -import { Button, Input, InputGroup, InputGroupProps, InputRightElement } from '@chakra-ui/react' -import { ChangeEvent, Component, createRef, FC } from 'react' +import { Button, Input, InputGroup, type InputGroupProps, InputRightElement } from '@chakra-ui/react' +import { type ChangeEvent, Component, createRef, type FC } from 'react' interface FilePickerProps { onFileChange: (fileList: Array<File>) => void diff --git a/frontend/src/pages/task/components/InputWithAddon.tsx b/frontend/src/pages/task/components/InputWithAddon.tsx index 96cb9519d..8b0f9ae1d 100644 --- a/frontend/src/pages/task/components/InputWithAddon.tsx +++ b/frontend/src/pages/task/components/InputWithAddon.tsx @@ -1,5 +1,5 @@ import { InputGroup, InputRightAddon } from '@chakra-ui/react' -import { PropsWithChildren } from 'react' +import type { PropsWithChildren } from 'react' interface InputWithAddonProps extends PropsWithChildren { suffix: string | undefined diff --git a/frontend/src/pages/task/components/TaskCategoryListIem.tsx b/frontend/src/pages/task/components/TaskCategoryListIem.tsx index 1c531cc19..2eaeb196f 100644 --- a/frontend/src/pages/task/components/TaskCategoryListIem.tsx +++ b/frontend/src/pages/task/components/TaskCategoryListIem.tsx @@ -1,7 +1,7 @@ import { Box, CircularProgress, Flex, HStack, Text, useColorModeValue } from '@chakra-ui/react' import { Link } from 'react-router' import { AbsolutePaths } from '../../../util/paths' -import { TaskCategoryPreview } from '../../../util/views/task.view' +import type { TaskCategoryPreview } from '../../../util/views/task.view' export const TaskCategoryListItem = ({ category }: { category: TaskCategoryPreview }) => { const bg = useColorModeValue('#00000020', '#FFFFFF20') diff --git a/frontend/src/pages/task/components/TaskStatusBadge.tsx b/frontend/src/pages/task/components/TaskStatusBadge.tsx index 069bdd65e..4c808b120 100644 --- a/frontend/src/pages/task/components/TaskStatusBadge.tsx +++ b/frontend/src/pages/task/components/TaskStatusBadge.tsx @@ -1,25 +1,25 @@ import { Badge } from '@chakra-ui/react' -import { FC } from 'react' -import { taskStatus } from '../../../util/views/task.view' +import type { FC } from 'react' +import { TaskStatus } from '../../../util/views/task.view' -const STATUS_TEXT_MAP = new Map<taskStatus, string>([ - [taskStatus.ACCEPTED, 'ELFOGADVA'], - [taskStatus.NOT_SUBMITTED, 'BEADÁSRA VÁR'], - [taskStatus.REJECTED, 'ELUTASÍTVA'], - [taskStatus.SUBMITTED, 'ÉRTÉKELÉSRE VÁR'], - [taskStatus.NOT_LOGGED_IN, 'ÖN NINCS BEJELENTKEZVE'] +const STATUS_TEXT_MAP = new Map<TaskStatus, string>([ + [TaskStatus.ACCEPTED, 'ELFOGADVA'], + [TaskStatus.NOT_SUBMITTED, 'BEADÁSRA VÁR'], + [TaskStatus.REJECTED, 'ELUTASÍTVA'], + [TaskStatus.SUBMITTED, 'ÉRTÉKELÉSRE VÁR'], + [TaskStatus.NOT_LOGGED_IN, 'ÖN NINCS BEJELENTKEZVE'] ]) -const STATUS_COLOR_MAP = new Map<taskStatus, string>([ - [taskStatus.ACCEPTED, 'green'], - [taskStatus.NOT_SUBMITTED, 'gray'], - [taskStatus.REJECTED, 'red'], - [taskStatus.SUBMITTED, '#DE970B'], //dark yellow - [taskStatus.NOT_LOGGED_IN, 'gray'] +const STATUS_COLOR_MAP = new Map<TaskStatus, string>([ + [TaskStatus.ACCEPTED, 'green'], + [TaskStatus.NOT_SUBMITTED, 'gray'], + [TaskStatus.REJECTED, 'red'], + [TaskStatus.SUBMITTED, '#DE970B'], //dark yellow + [TaskStatus.NOT_LOGGED_IN, 'gray'] ]) type TaskStatusBadgeProps = { - status: taskStatus + status: TaskStatus fontSize: string } diff --git a/frontend/src/pages/task/task.page.tsx b/frontend/src/pages/task/task.page.tsx index 09dc4a70e..b0d2d2205 100644 --- a/frontend/src/pages/task/task.page.tsx +++ b/frontend/src/pages/task/task.page.tsx @@ -16,8 +16,7 @@ import { VStack } from '@chakra-ui/react' import { lazy, useEffect, useRef, useState } from 'react' -import { Helmet } from 'react-helmet-async' -import { Controller, SubmitHandler, useFieldArray, useForm, useWatch } from 'react-hook-form' +import { Controller, type SubmitHandler, useFieldArray, useForm, useWatch } from 'react-hook-form' import { Navigate, useParams } from 'react-router' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useTaskFullDetailsQuery } from '../../api/hooks/task/useTaskFullDetailsQuery' @@ -31,7 +30,7 @@ import { PageStatus } from '../../common-components/PageStatus' import { stringifyTimeStamp, useBrandColor } from '../../util/core-functions.util.ts' import { l } from '../../util/language' import { AbsolutePaths } from '../../util/paths' -import { taskFormat, TaskFormatDescriptor, taskStatus, taskType } from '../../util/views/task.view' +import { TaskFormat, type TaskFormatDescriptor, TaskStatus, TaskType } from '../../util/views/task.view' import { CustomForm } from './components/CustomForm' import { FilePicker } from './components/FilePicker' import { TaskStatusBadge } from './components/TaskStatusBadge' @@ -47,9 +46,9 @@ export interface FormInput { } & TaskFormatDescriptor)[] } -const getAcceptedFileType = (type?: taskType) => { - if (type === taskType.ONLY_ZIP) return '.zip' - else if (type === taskType.ONLY_PDF) return '.pdf' +const getAcceptedFileType = (type?: TaskType) => { + if (type === TaskType.ONLY_ZIP) return '.zip' + else if (type === TaskType.ONLY_PDF) return '.pdf' else return 'image/jpeg,image/png,image/jpg,image/gif,image/webp' } const TaskPage = () => { @@ -59,6 +58,7 @@ const TaskPage = () => { const brandColor = useBrandColor() const component = useConfigContext()?.components?.task + const toast = useToast() const { id } = useParams() const { setValue, handleSubmit, control } = useForm<FormInput>() @@ -71,7 +71,7 @@ const TaskPage = () => { const taskSubmissionMutation = useTaskSubmissionMutation() const { isLoading, isError, data, isSuccess, refetch } = useTaskFullDetailsQuery(id || 'UNKNOWN') useEffect(() => { - if (!isSuccess && data?.submission && data?.task?.format === taskFormat.CODE) { + if (!isSuccess && data?.submission && data?.task?.format === TaskFormat.CODE) { setCodeAnswer(data.submission.textAnswer) } }, [isSuccess, data]) @@ -83,20 +83,20 @@ const TaskPage = () => { if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={component.title} /> const expired = data.task?.availableTo ? data.task?.availableTo < new Date().valueOf() / 1000 : false - const textAllowed = data.task?.type === taskType.TEXT || data.task?.type === taskType.BOTH + const textAllowed = data.task?.type === TaskType.TEXT || data.task?.type === TaskType.BOTH const fileAllowed = - data.task?.type === taskType.IMAGE || - data.task?.type === taskType.BOTH || - data.task?.type === taskType.ONLY_PDF || - data.task?.type === taskType.ONLY_ZIP + data.task?.type === TaskType.IMAGE || + data.task?.type === TaskType.BOTH || + data.task?.type === TaskType.ONLY_PDF || + data.task?.type === TaskType.ONLY_ZIP const submissionAllowed = - (data?.status === taskStatus.NOT_SUBMITTED || - data?.status === taskStatus.REJECTED || - (component?.resubmissionEnabled && data.status === taskStatus.SUBMITTED)) && + (data?.status === TaskStatus.NOT_SUBMITTED || + data?.status === TaskStatus.REJECTED || + (component?.resubmissionEnabled && data.status === TaskStatus.SUBMITTED)) && !expired - const reviewed = data.status === taskStatus.ACCEPTED || data.status === taskStatus.REJECTED - const localSubmission = data?.task?.format === taskFormat.NONE + const reviewed = data.status === TaskStatus.ACCEPTED || data.status === TaskStatus.REJECTED + const localSubmission = data?.task?.format === TaskFormat.NONE const onSubmit: SubmitHandler<FormInput> = async (values) => { if ((!fileAllowed || fileAnswer) && submissionAllowed) { @@ -136,7 +136,7 @@ const TaskPage = () => { } if (textAllowed) { switch (data.task?.format) { - case taskFormat.TEXT: + case TaskFormat.TEXT: if (values.textAnswer) { formData.append('textAnswer', values.textAnswer) } else { @@ -149,7 +149,7 @@ const TaskPage = () => { return } break - case taskFormat.FORM: + case TaskFormat.FORM: if (customFormData) { formData.append( 'textAnswer', @@ -157,7 +157,7 @@ const TaskPage = () => { ) } break - case taskFormat.CODE: + case TaskFormat.CODE: if (codeAnswer) { formData.append('textAnswer', codeAnswer) } else { @@ -216,7 +216,7 @@ const TaskPage = () => { let textInput = null if (textAllowed && data.task) { switch (data.task.format) { - case taskFormat.TEXT: + case TaskFormat.TEXT: textInput = ( <Box mt={5}> <FormLabel htmlFor="textAnswer">Szöveges válasz</FormLabel> @@ -228,10 +228,10 @@ const TaskPage = () => { </Box> ) break - case taskFormat.FORM: + case TaskFormat.FORM: textInput = <CustomForm formatDescriptor={data.task.formatDescriptor} control={control} fields={fields} replace={replace} /> break - case taskFormat.CODE: + case TaskFormat.CODE: textInput = <CodeEditor code={codeAnswer} setCode={setCodeAnswer} readonly={false} /> break } @@ -240,7 +240,7 @@ const TaskPage = () => { let submittedText = null if (textAllowed && data.submission) { submittedText = - data.task?.format === taskFormat.CODE ? ( + data.task?.format === TaskFormat.CODE ? ( <CodeEditor code={data.submission?.textAnswer} setCode={() => {}} readonly={true} /> ) : ( <Text mt={2} whiteSpace="pre-wrap"> @@ -277,8 +277,7 @@ const TaskPage = () => { ] return ( - <CmschPage loginRequired> - <Helmet title={data.task?.title} /> + <CmschPage loginRequired={true} title={data.task?.title}> <CustomBreadcrumb items={breadcrumbItems} /> <Flex my={5} justify="space-between" flexWrap="wrap" alignItems="center"> <Box> @@ -304,7 +303,7 @@ const TaskPage = () => {  {data.task?.expectedResultDescription} </Text> )} - {data.status !== taskStatus.NOT_SUBMITTED && ( + {data.status !== TaskStatus.NOT_SUBMITTED && ( <> <Heading size="md" mt={8}> Beküldött megoldás @@ -341,7 +340,7 @@ const TaskPage = () => { {submissionAllowed && ( <> <Heading size="md" mt={5}> - {data.status === taskStatus.REJECTED ? 'Újra beküldés' : 'Beküldés'} + {data.status === TaskStatus.REJECTED ? 'Újra beküldés' : 'Beküldés'} </Heading> <Stack mt={5}> {localSubmission ? ( diff --git a/frontend/src/pages/task/taskCategory.page.tsx b/frontend/src/pages/task/taskCategory.page.tsx index ada8773aa..f6ab860dd 100644 --- a/frontend/src/pages/task/taskCategory.page.tsx +++ b/frontend/src/pages/task/taskCategory.page.tsx @@ -1,5 +1,4 @@ import { Badge, Box, Flex, Heading, Text, VStack } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { Link, Navigate, useParams } from 'react-router' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useTasksInCategoryQuery } from '../../api/hooks/task/useTasksInCategoryQuery' @@ -37,8 +36,7 @@ const TaskCategoryPage = () => { ] return ( - <CmschPage loginRequired> - <Helmet title={data.categoryName} /> + <CmschPage loginRequired={true} title={data.categoryName}> <CustomBreadcrumb items={breadcrumbItems} /> <Heading>{data.categoryName}</Heading> {!!data.description && ( diff --git a/frontend/src/pages/task/taskCategoryList.page.tsx b/frontend/src/pages/task/taskCategoryList.page.tsx index 3b4b58e3b..73329d908 100644 --- a/frontend/src/pages/task/taskCategoryList.page.tsx +++ b/frontend/src/pages/task/taskCategoryList.page.tsx @@ -1,12 +1,11 @@ import { Heading, Text, VStack } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useTaskCategoriesQuery } from '../../api/hooks/task/useTaskCategoriesQuery' import { ComponentUnavailable } from '../../common-components/ComponentUnavailable' import { CmschPage } from '../../common-components/layout/CmschPage' import Markdown from '../../common-components/Markdown' import { PageStatus } from '../../common-components/PageStatus' -import { taskCategoryType } from '../../util/views/task.view' +import { TaskCategoryType } from '../../util/views/task.view' import { TaskCategoryListItem } from './components/TaskCategoryListIem' const TaskCategoryListPage = () => { @@ -18,8 +17,8 @@ const TaskCategoryListPage = () => { if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={component.title} /> - const normalCategories = data.filter((c) => c.type == taskCategoryType.REGULAR) - const prCategories = data.filter((c) => c.type == taskCategoryType.PROFILE_REQUIRED) + const normalCategories = data.filter((c) => c.type == TaskCategoryType.REGULAR) + const prCategories = data.filter((c) => c.type == TaskCategoryType.PROFILE_REQUIRED) const required = prCategories.length > 0 && ( <> @@ -36,8 +35,7 @@ const TaskCategoryListPage = () => { ) return ( - <CmschPage loginRequired> - <Helmet title={component.title} /> + <CmschPage loginRequired={true} title={component?.title}> {required} <Heading as="h1" variant="main-title"> {component.regularTitle} diff --git a/frontend/src/pages/task/util/taskCategoryProgress.ts b/frontend/src/pages/task/util/taskCategoryProgress.ts index 45c2dcac1..f18f283a8 100644 --- a/frontend/src/pages/task/util/taskCategoryProgress.ts +++ b/frontend/src/pages/task/util/taskCategoryProgress.ts @@ -1,4 +1,4 @@ -import { TaskCategoryPreview } from '../../../util/views/task.view' +import type { TaskCategoryPreview } from '../../../util/views/task.view' export const progress = (category: TaskCategoryPreview) => (category.approved + category.notGraded) / category.sum diff --git a/frontend/src/pages/task/util/taskSubmissionResponseMap.ts b/frontend/src/pages/task/util/taskSubmissionResponseMap.ts index 200eb4936..c65320926 100644 --- a/frontend/src/pages/task/util/taskSubmissionResponseMap.ts +++ b/frontend/src/pages/task/util/taskSubmissionResponseMap.ts @@ -1,16 +1,16 @@ -import { taskSubmissionStatus } from '../../../util/views/task.view' +import { TaskSubmissionStatus } from '../../../util/views/task.view' -export const taskSubmissionResponseMap = new Map<taskSubmissionStatus, string>([ - [taskSubmissionStatus.OK, 'Elküldve!'], - [taskSubmissionStatus.EMPTY_ANSWER, 'Üres megoldás!'], - [taskSubmissionStatus.INVALID_IMAGE, 'Érvénytelen kép!'], - [taskSubmissionStatus.INVALID_PDF, 'Érvénytelen PDF!'], - [taskSubmissionStatus.INVALID_ZIP, 'Érvénytelen ZIP!'], - [taskSubmissionStatus.ALREADY_SUBMITTED, 'Ezt ön már beküldte!'], - [taskSubmissionStatus.ALREADY_APPROVED, 'Önnek ezt a feladatát már elfogadták!'], - [taskSubmissionStatus.NO_ASSOCIATE_GROUP, 'Nincs önnek csoportja!'], - [taskSubmissionStatus.INVALID_TASK_ID, 'Érvénytelen feladat!'], - [taskSubmissionStatus.TOO_EARLY_OR_LATE, 'Túl korán vagy túl későn adta be!'], - [taskSubmissionStatus.NO_PERMISSION, 'Nincs jogosultsága!'], - [taskSubmissionStatus.INVALID_BACKEND_CONFIG, 'Belső hiba'] +export const taskSubmissionResponseMap = new Map<TaskSubmissionStatus, string>([ + [TaskSubmissionStatus.OK, 'Elküldve!'], + [TaskSubmissionStatus.EMPTY_ANSWER, 'Üres megoldás!'], + [TaskSubmissionStatus.INVALID_IMAGE, 'Érvénytelen kép!'], + [TaskSubmissionStatus.INVALID_PDF, 'Érvénytelen PDF!'], + [TaskSubmissionStatus.INVALID_ZIP, 'Érvénytelen ZIP!'], + [TaskSubmissionStatus.ALREADY_SUBMITTED, 'Ezt ön már beküldte!'], + [TaskSubmissionStatus.ALREADY_APPROVED, 'Önnek ezt a feladatát már elfogadták!'], + [TaskSubmissionStatus.NO_ASSOCIATE_GROUP, 'Nincs önnek csoportja!'], + [TaskSubmissionStatus.INVALID_TASK_ID, 'Érvénytelen feladat!'], + [TaskSubmissionStatus.TOO_EARLY_OR_LATE, 'Túl korán vagy túl későn adta be!'], + [TaskSubmissionStatus.NO_PERMISSION, 'Nincs jogosultsága!'], + [TaskSubmissionStatus.INVALID_BACKEND_CONFIG, 'Belső hiba'] ]) diff --git a/frontend/src/pages/teams/components/MemberRow.tsx b/frontend/src/pages/teams/components/MemberRow.tsx index 3fd365ccc..5cf15a8cb 100644 --- a/frontend/src/pages/teams/components/MemberRow.tsx +++ b/frontend/src/pages/teams/components/MemberRow.tsx @@ -17,7 +17,7 @@ import { import { useRef, useState } from 'react' import { useOpaqueBackground } from '../../../util/core-functions.util' -import { TeamMemberView } from '../../../util/views/team.view' +import type { TeamMemberView } from '../../../util/views/team.view' import { AcceptButton } from './AcceptButton' import { DeleteButton } from './DeleteButton' import { LeaderButton } from './LeaderButton' diff --git a/frontend/src/pages/teams/components/TeamDetailsCore.tsx b/frontend/src/pages/teams/components/TeamDetailsCore.tsx index 9c7c1b7f9..122cbe5e3 100644 --- a/frontend/src/pages/teams/components/TeamDetailsCore.tsx +++ b/frontend/src/pages/teams/components/TeamDetailsCore.tsx @@ -14,7 +14,6 @@ import { WrapItem } from '@chakra-ui/react' import { useState } from 'react' -import { Helmet } from 'react-helmet-async' import { FaSignInAlt, FaSignOutAlt, FaUndoAlt } from 'react-icons/fa' import { useNavigate } from 'react-router' import { useConfigContext } from '../../../api/contexts/config/ConfigContext' @@ -34,7 +33,7 @@ import { PageStatus } from '../../../common-components/PageStatus' import { joinPath, useBrandColor } from '../../../util/core-functions.util' import { AbsolutePaths, Paths } from '../../../util/paths' import { RoleType, RoleTypeString } from '../../../util/views/profile.view' -import { TeamResponseMessages, TeamResponses, TeamView } from '../../../util/views/team.view' +import { TeamResponseMessages, TeamResponses, type TeamView } from '../../../util/views/team.view' import { MemberRow } from './MemberRow' import { TeamFormItem } from './TeamFormItem' import TeamLabel from './TeamLabel.tsx' @@ -100,8 +99,7 @@ export function TeamDetailsCore({ team, isLoading, error, myTeam = false, refetc if (error || isLoading || !team) return <PageStatus isLoading={isLoading} isError={!!error} title={teamComponent.title} /> const title = myTeam ? teamComponent.myTitle : undefined return ( - <CmschPage minRole={myTeam ? RoleType.ATTENDEE : undefined}> - <Helmet title={title ?? team.name} /> + <CmschPage minRole={myTeam ? RoleType.ATTENDEE : undefined} title={title ?? team.name}> {title && <Heading mb={5}>{title}</Heading>} <Box backgroundImage={team.coverUrl} backgroundPosition="center" backgroundSize="cover" borderRadius="lg" overflow="hidden"> <Box p={4} bg={bannerBlanket} display="flex" justifyContent="space-between" flexDirection={{ base: 'column', md: 'row' }}> diff --git a/frontend/src/pages/teams/components/TeamFormItem.tsx b/frontend/src/pages/teams/components/TeamFormItem.tsx index 0b170e921..97884220c 100644 --- a/frontend/src/pages/teams/components/TeamFormItem.tsx +++ b/frontend/src/pages/teams/components/TeamFormItem.tsx @@ -3,7 +3,7 @@ import { FaCheckCircle, FaExclamationCircle } from 'react-icons/fa' import { Link } from 'react-router' import { formatHu, joinPath, useOpaqueBackground } from '../../../util/core-functions.util' import { AbsolutePaths } from '../../../util/paths' -import { TeamFormView } from '../../../util/views/team.view' +import type { TeamFormView } from '../../../util/views/team.view' export function TeamFormItem({ form }: { form: TeamFormView }) { const bg = useOpaqueBackground(1) diff --git a/frontend/src/pages/teams/components/TeamLabel.tsx b/frontend/src/pages/teams/components/TeamLabel.tsx index 08da1a4f3..b4cb255ac 100644 --- a/frontend/src/pages/teams/components/TeamLabel.tsx +++ b/frontend/src/pages/teams/components/TeamLabel.tsx @@ -1,5 +1,5 @@ import { Box, Tooltip } from '@chakra-ui/react' -import { ColorInstance } from 'color' +import type { ColorInstance } from 'color' import { useAltColor, useColor } from '../../../util/color.utils.ts' const TeamLabel = ({ name, color, desc }: { name: string; color?: string; desc?: string }) => { diff --git a/frontend/src/pages/teams/components/TeamListItem.tsx b/frontend/src/pages/teams/components/TeamListItem.tsx index 0a335ec90..99a345b72 100644 --- a/frontend/src/pages/teams/components/TeamListItem.tsx +++ b/frontend/src/pages/teams/components/TeamListItem.tsx @@ -4,7 +4,7 @@ import { Link } from 'react-router' import { useOpaqueBackground } from '../../../util/core-functions.util' import { AbsolutePaths } from '../../../util/paths' -import { TeamListItemView } from '../../../util/views/team.view' +import type { TeamListItemView } from '../../../util/views/team.view' import TeamLabel from './TeamLabel.tsx' type TeamListItemProps = { diff --git a/frontend/src/pages/teams/components/TeamStat.tsx b/frontend/src/pages/teams/components/TeamStat.tsx index 3c0d86b13..75e10104f 100644 --- a/frontend/src/pages/teams/components/TeamStat.tsx +++ b/frontend/src/pages/teams/components/TeamStat.tsx @@ -1,7 +1,7 @@ -import { Box, CircularProgress, HStack, Stat, StatHelpText, StatLabel, StatNumber, StatProps } from '@chakra-ui/react' +import { Box, CircularProgress, HStack, Stat, StatHelpText, StatLabel, StatNumber, type StatProps } from '@chakra-ui/react' import { Link } from 'react-router' import { useOpaqueBackground } from '../../../util/core-functions.util' -import { TeamStatView } from '../../../util/views/team.view' +import type { TeamStatView } from '../../../util/views/team.view' interface TeamStatProps extends StatProps { stat: TeamStatView diff --git a/frontend/src/pages/teams/components/TeamTaskCategoryListItem.tsx b/frontend/src/pages/teams/components/TeamTaskCategoryListItem.tsx index 1101254c9..5149e50d3 100644 --- a/frontend/src/pages/teams/components/TeamTaskCategoryListItem.tsx +++ b/frontend/src/pages/teams/components/TeamTaskCategoryListItem.tsx @@ -2,7 +2,7 @@ import { Box, CircularProgress, Flex, HStack, Text } from '@chakra-ui/react' import { Link } from 'react-router' import { joinPath, useOpaqueBackground } from '../../../util/core-functions.util' import { AbsolutePaths } from '../../../util/paths' -import { TeamTaskCategoriesView } from '../../../util/views/team.view' +import type { TeamTaskCategoriesView } from '../../../util/views/team.view' export const TeamTaskCategoryListItem = ({ category }: { category: TeamTaskCategoriesView }) => { const bg = useOpaqueBackground(1) diff --git a/frontend/src/pages/teams/createTeam.page.tsx b/frontend/src/pages/teams/createTeam.page.tsx index e52f1a185..b5810f5d1 100644 --- a/frontend/src/pages/teams/createTeam.page.tsx +++ b/frontend/src/pages/teams/createTeam.page.tsx @@ -1,6 +1,5 @@ import { Button, FormControl, FormLabel, Heading, HStack, Input, Text, VStack } from '@chakra-ui/react' import { useState } from 'react' -import { Helmet } from 'react-helmet-async' import { useForm } from 'react-hook-form' import { Navigate, useNavigate } from 'react-router' import { useConfigContext } from '../../api/contexts/config/ConfigContext' @@ -11,12 +10,11 @@ import { CmschPage } from '../../common-components/layout/CmschPage' import Markdown from '../../common-components/Markdown' import { useBrandColor } from '../../util/core-functions.util.ts' import { AbsolutePaths } from '../../util/paths.ts' -import { CreateTeamDto, TeamResponseMessages, TeamResponses } from '../../util/views/team.view' +import { type CreateTeamDto, TeamResponseMessages, TeamResponses } from '../../util/views/team.view' export default function CreateTeamPage() { const navigate = useNavigate() const [requestError, setRequestError] = useState<string>() - const config = useConfigContext() const brandColor = useBrandColor() const tokenRefresh = useTokenRefresh(() => { navigate(AbsolutePaths.MY_TEAM) @@ -34,13 +32,12 @@ export default function CreateTeamPage() { setRequestError(TeamResponseMessages[response as TeamResponses]) } }) - const component = config?.components?.team + const component = useConfigContext()?.components?.team if (!component) return <ComponentUnavailable /> if (!component.creationEnabled) return <Navigate to="/" replace /> return ( - <CmschPage> - <Helmet title={component.createTitle} /> + <CmschPage title={component.createTitle}> <Heading>{component.createTitle}</Heading> <Markdown text={component.teamCreationTopMessage} /> <form onSubmit={handleSubmit(createTeam)}> diff --git a/frontend/src/pages/teams/editMyTeam.page.tsx b/frontend/src/pages/teams/editMyTeam.page.tsx index d6448b453..00455d432 100644 --- a/frontend/src/pages/teams/editMyTeam.page.tsx +++ b/frontend/src/pages/teams/editMyTeam.page.tsx @@ -1,6 +1,5 @@ import { Alert, AlertIcon, Box, Button, FormControl, FormLabel, Heading, Input, Text, VStack } from '@chakra-ui/react' import { useState } from 'react' -import { Helmet } from 'react-helmet-async' import { useForm } from 'react-hook-form' import { Navigate, useNavigate } from 'react-router' import { useConfigContext } from '../../api/contexts/config/ConfigContext' @@ -12,7 +11,7 @@ import Markdown from '../../common-components/Markdown' import { useBrandColor } from '../../util/core-functions.util.ts' import { AbsolutePaths } from '../../util/paths.ts' import { RoleType, RoleTypeString } from '../../util/views/profile.view' -import { TeamEditDto, TeamResponseMessages, TeamResponses } from '../../util/views/team.view' +import { type TeamEditDto, TeamResponseMessages, TeamResponses } from '../../util/views/team.view' import { FilePicker } from '../task/components/FilePicker' export default function EditMyTeamPage() { @@ -43,8 +42,7 @@ export default function EditMyTeamPage() { if (!component.teamEditEnabled) return <Navigate to="/" replace /> return ( - <CmschPage> - <Helmet title={component.teamEditTitle} /> + <CmschPage title={component.teamEditTitle}> <Heading>{component.teamEditTitle}</Heading> <Markdown text={component.teamEditTopMessage} /> <Alert status="info" my={5}> diff --git a/frontend/src/pages/teams/teamList.page.tsx b/frontend/src/pages/teams/teamList.page.tsx index a9da572b9..996b47b3a 100644 --- a/frontend/src/pages/teams/teamList.page.tsx +++ b/frontend/src/pages/teams/teamList.page.tsx @@ -1,5 +1,4 @@ import { Heading } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useTeamList } from '../../api/hooks/team/queries/useTeamList' import { ComponentUnavailable } from '../../common-components/ComponentUnavailable' @@ -8,7 +7,7 @@ import { CmschPage } from '../../common-components/layout/CmschPage' import { PageStatus } from '../../common-components/PageStatus' import { SearchBar } from '../../common-components/SearchBar' import { useSearch } from '../../util/useSearch' -import { TeamListItemView } from '../../util/views/team.view' +import type { TeamListItemView } from '../../util/views/team.view' import { TeamListItem } from './components/TeamListItem' const EmptyData: TeamListItemView[] = [] @@ -23,8 +22,7 @@ const searchFn = (item: TeamListItemView, search: string) => { } export default function TeamListPage() { - const config = useConfigContext() - const component = config?.components?.team + const component = useConfigContext()?.components?.team const { data, isLoading, isError } = useTeamList() const searchArgs = useSearch<TeamListItemView>(data ?? EmptyData, searchFn) @@ -33,8 +31,7 @@ export default function TeamListPage() { if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={component.title} /> return ( - <CmschPage> - <Helmet title={component.title} /> + <CmschPage title={component?.title}> <Heading as="h1" variant="main-title"> {component.title} </Heading> diff --git a/frontend/src/pages/token/components/QRScanResultComponent.tsx b/frontend/src/pages/token/components/QRScanResultComponent.tsx index 9624d72cd..1bfedfc8d 100644 --- a/frontend/src/pages/token/components/QRScanResultComponent.tsx +++ b/frontend/src/pages/token/components/QRScanResultComponent.tsx @@ -1,7 +1,7 @@ import { CheckCircleIcon, CloseIcon, InfoIcon, WarningIcon, WarningTwoIcon } from '@chakra-ui/icons' import { Box, Center, Heading, Image, Text } from '@chakra-ui/react' import Markdown from '../../../common-components/Markdown' -import { ScanMessages, ScanResponseView, ScanStatus } from '../../../util/views/token.view' +import { ScanMessages, type ScanResponseView, ScanStatus } from '../../../util/views/token.view' interface QrScanResultProps { isError?: boolean diff --git a/frontend/src/pages/token/components/StampComponent.tsx b/frontend/src/pages/token/components/StampComponent.tsx index 6630f23d0..22cece026 100644 --- a/frontend/src/pages/token/components/StampComponent.tsx +++ b/frontend/src/pages/token/components/StampComponent.tsx @@ -1,7 +1,7 @@ import { Box, Center, Flex, Icon, Text, useColorModeValue } from '@chakra-ui/react' -import { FC } from 'react' +import type { FC } from 'react' import { FaRocket, FaStamp } from 'react-icons/fa' -import { IconType } from 'react-icons/lib' +import type { IconType } from 'react-icons/lib' import { useConfigContext } from '../../../api/contexts/config/ConfigContext' import { useBrandColor } from '../../../util/core-functions.util.ts' diff --git a/frontend/src/pages/token/tokenList.page.tsx b/frontend/src/pages/token/tokenList.page.tsx index 700ef5b22..ae12ee158 100644 --- a/frontend/src/pages/token/tokenList.page.tsx +++ b/frontend/src/pages/token/tokenList.page.tsx @@ -1,5 +1,4 @@ import { ButtonGroup, Heading, Progress, Stack } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { FaQrcode } from 'react-icons/fa' import { useConfigContext } from '../../api/contexts/config/ConfigContext' import { useTokensQuery } from '../../api/hooks/token/useTokensQuery' @@ -15,8 +14,7 @@ import { StampComponent } from './components/StampComponent' const TokenList = () => { const { data, isLoading, isError } = useTokensQuery() - const config = useConfigContext() - const component = config?.components?.token + const component = useConfigContext()?.components?.token const brandColor = useBrandColor() const calculate_progress = (acquired: number, total: number) => (total == 0 ? 100 : (100 * acquired) / total) @@ -26,8 +24,7 @@ const TokenList = () => { if (isError || isLoading || !data) return <PageStatus isLoading={isLoading} isError={isError} title={component.title} /> return ( - <CmschPage loginRequired> - <Helmet title={component.title || 'QR kódok'} /> + <CmschPage loginRequired={true} title={component.title || 'QR kódok'}> <Heading as="h1" variant="main-title"> {component.title || 'QR kódok'} </Heading> diff --git a/frontend/src/pages/token/tokenScan.page.tsx b/frontend/src/pages/token/tokenScan.page.tsx index 609ff3142..39d4d07cd 100644 --- a/frontend/src/pages/token/tokenScan.page.tsx +++ b/frontend/src/pages/token/tokenScan.page.tsx @@ -1,5 +1,4 @@ import { Button, ButtonGroup, Fade, Heading, Spinner } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { FaArrowLeft, FaQrcode } from 'react-icons/fa' import { useNavigate } from 'react-router' @@ -34,8 +33,7 @@ const TokenScan = () => { }, [isLoggedIn, mutate]) return ( - <CmschPage loginRequired> - <Helmet title="QR beolvasás" /> + <CmschPage loginRequired={true} title="QR beolvasás"> <Heading mb={5}>QR beolvasás</Heading> {isPending && <Spinner color={spinnerColor} size="xl" thickness="0.3rem" />} {isIdle && <QrReader onScan={handleScan} />} diff --git a/frontend/src/pages/token/tokenScanResult.page.tsx b/frontend/src/pages/token/tokenScanResult.page.tsx index 401b7ff05..cdddc5147 100644 --- a/frontend/src/pages/token/tokenScanResult.page.tsx +++ b/frontend/src/pages/token/tokenScanResult.page.tsx @@ -1,24 +1,23 @@ import { ButtonGroup } from '@chakra-ui/react' -import { Helmet } from 'react-helmet-async' import { FaArrowLeft, FaQrcode } from 'react-icons/fa' import { useSearchParams } from 'react-router' import { CmschPage } from '../../common-components/layout/CmschPage' import { LinkButton } from '../../common-components/LinkButton' import { useBrandColor } from '../../util/core-functions.util.ts' import { AbsolutePaths } from '../../util/paths' -import { ScanResponseView, ScanStatus } from '../../util/views/token.view' +import { type ScanResponseView, ScanStatus } from '../../util/views/token.view' import { QRScanResultComponent } from './components/QRScanResultComponent' const TokenScanResult = () => { const [searchParams] = useSearchParams() const brandColor = useBrandColor() + const server_response: ScanResponseView = { title: searchParams.get('title') || undefined, status: (searchParams.get('status') || ScanStatus.WRONG) as ScanStatus } return ( - <CmschPage> - <Helmet title="QR eredmény" /> + <CmschPage title="QR eredmény"> <QRScanResultComponent response={server_response} /> <ButtonGroup spacing="6" alignSelf="center"> <LinkButton leftIcon={<FaArrowLeft />} href={AbsolutePaths.TOKEN}> diff --git a/frontend/src/util/LoadingView.tsx b/frontend/src/util/LoadingView.tsx index a4a7d1e3c..728118dd6 100644 --- a/frontend/src/util/LoadingView.tsx +++ b/frontend/src/util/LoadingView.tsx @@ -1,11 +1,11 @@ import { Box, Button, ButtonGroup, Center, Heading, Text, useColorModeValue, VStack } from '@chakra-ui/react' -import { FC, PropsWithChildren } from 'react' -import { Helmet } from 'react-helmet-async' +import type { FC, PropsWithChildren } from 'react' import { KirDevLogo } from '../assets/kir-dev-logo.tsx' import { Loading } from '../common-components/Loading.tsx' import { usePersistentStyleSetting } from './configs/themeStyle.config.ts' import { useBrandColor } from './core-functions.util.ts' import { l } from './language.ts' +import { Title } from './TitleProvider.tsx' export type LoadingViewProps = PropsWithChildren & { hasError: boolean @@ -24,7 +24,7 @@ export const LoadingView: FC<LoadingViewProps> = ({ errorAction, hasError, error if (hasError) { return ( <Center flexDirection="column" h="100vh" backgroundPosition="center" backgroundSize="cover"> - <Helmet title={l('error-page-helmet')} /> + <Title text={l('error-page-helmet')} /> <VStack spacing={5} p={5} borderRadius={5} bg={bg} backdropFilter={backdropFilter}> <Heading textAlign="center">{errorTitle}</Heading> <Text textAlign="center" marginTop={4} maxW={96}> diff --git a/frontend/src/util/TitleProvider.tsx b/frontend/src/util/TitleProvider.tsx new file mode 100644 index 000000000..0123eae57 --- /dev/null +++ b/frontend/src/util/TitleProvider.tsx @@ -0,0 +1,37 @@ +import { createContext, type FC, type PropsWithChildren, useContext, useEffect, useState } from 'react' + +export interface TitleContext { + addTitle: (title: string) => void + removeTitle: (title: string) => void +} +// eslint-disable-next-line react-refresh/only-export-components +export const TitleContext = createContext<TitleContext>({ addTitle: () => {}, removeTitle: () => {} }) + +export const Title = ({ text }: { text: string | undefined }) => { + const titleContext = useContext(TitleContext) + useEffect(() => { + if (!text) return + + titleContext.addTitle(text) + return () => titleContext.removeTitle(text) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [text]) + + return null +} + +export const TitleProvider: FC<PropsWithChildren & { titleTemplate: (title: string) => string }> = ({ children, titleTemplate }) => { + const [titles, setTitles] = useState<string[]>([]) + + return ( + <TitleContext.Provider + value={{ + addTitle: (title: string) => setTitles([...titles, title]), + removeTitle: (title: string) => setTitles(titles.filter((e) => e !== title)) + }} + > + <title>{titleTemplate(titles[titles.length - 1])} + {children} + + ) +} diff --git a/frontend/src/util/color.utils.ts b/frontend/src/util/color.utils.ts index 208a566af..f7d0e31a1 100644 --- a/frontend/src/util/color.utils.ts +++ b/frontend/src/util/color.utils.ts @@ -1,4 +1,4 @@ -import Color, { ColorInstance } from 'color' +import Color, { type ColorInstance } from 'color' import { useStyle } from '../api/contexts/config/ConfigContext.tsx' export function hexToRgb(hex: string): [number, number, number] { diff --git a/frontend/src/util/configs/firebase.config.ts b/frontend/src/util/configs/firebase.config.ts index 416c3b37d..3f4c50d0d 100644 --- a/frontend/src/util/configs/firebase.config.ts +++ b/frontend/src/util/configs/firebase.config.ts @@ -1,5 +1,5 @@ import { initializeApp } from '@firebase/app' -import { getMessaging, getToken, MessagePayload, Messaging, onMessage } from '@firebase/messaging' +import { getMessaging, getToken, type MessagePayload, type Messaging, onMessage } from '@firebase/messaging' import axios from 'axios' import { ApiPaths } from '../paths.ts' import { diff --git a/frontend/src/util/configs/theme.config.ts b/frontend/src/util/configs/theme.config.ts index ec072b210..2c0e01b7d 100644 --- a/frontend/src/util/configs/theme.config.ts +++ b/frontend/src/util/configs/theme.config.ts @@ -1,6 +1,6 @@ import { extendTheme } from '@chakra-ui/react' import { mode } from '@chakra-ui/theme-tools' -import { Style } from '../../api/contexts/config/types.ts' +import type { Style } from '../../api/contexts/config/types.ts' import { getColorShadesForColor } from '../core-functions.util.ts' export const KirDevColor = '#F15A29' diff --git a/frontend/src/util/configs/themeStyle.config.ts b/frontend/src/util/configs/themeStyle.config.ts index d1a489876..427b51a86 100644 --- a/frontend/src/util/configs/themeStyle.config.ts +++ b/frontend/src/util/configs/themeStyle.config.ts @@ -1,5 +1,5 @@ import { createContext, useContext } from 'react' -import { Style } from '../../api/contexts/config/types.ts' +import type { Style } from '../../api/contexts/config/types.ts' export type PersistentStyleSettingData = { persistentStyle?: Style diff --git a/frontend/src/util/errorBoundary.tsx b/frontend/src/util/errorBoundary.tsx index c05796c38..d33b1aa24 100644 --- a/frontend/src/util/errorBoundary.tsx +++ b/frontend/src/util/errorBoundary.tsx @@ -1,6 +1,5 @@ import { Heading, Text } from '@chakra-ui/react' -import React, { ErrorInfo, PropsWithChildren } from 'react' -import { Helmet } from 'react-helmet-async' +import React, { type ErrorInfo, type PropsWithChildren } from 'react' import { CmschPage } from '../common-components/layout/CmschPage' import { l } from './language' @@ -32,8 +31,7 @@ export class ErrorBoundary extends React.Component { render() { if (this.state.hasError) { return ( - - + {l('error-boundary-title')} {l('error-boundary-message')} diff --git a/frontend/src/util/paths.ts b/frontend/src/util/paths.ts index e35668a56..a3f644fa9 100644 --- a/frontend/src/util/paths.ts +++ b/frontend/src/util/paths.ts @@ -1,98 +1,107 @@ -export enum Paths { - HOME = 'home', - PROFILE = 'profile', - CHANGE_ALIAS = 'profile/change-alias', - CHANGE_GROUP = 'profile/change-group', - RIDDLE = 'riddle', - RIDDLE_HISTORY = 'riddle/history', - TASKS = 'tasks', - NEWS = 'news', - EVENTS = 'event', - CALENDAR = 'calendar', - IMPRESSUM = 'impressum', - TOKEN = 'token', - TOKEN_SCANNED = 'token-scanned', - COMMUNITY = 'community', - ORGANIZATION = 'organization', - ERROR = 'error', - EXTRA_PAGE = 'page', - FORM = 'form', - LEADER_BOARD = 'leaderboard', - RACE = 'race', - QR_FIGHT = 'qr-fight', - TEAMS = 'teams', - CREATE_TEAM = 'create-team', - EDIT_TEAM = 'edit-team', - MY_TEAM = 'my-team', - TEAM_ADMIN = 'team-admin', - ACCESS_KEY = 'access-key', - MAP = 'map', - DEBT = 'debt' -} +export const Paths = { + HOME: 'home', + PROFILE: 'profile', + CHANGE_ALIAS: 'profile/change-alias', + CHANGE_GROUP: 'profile/change-group', + RIDDLE: 'riddle', + RIDDLE_HISTORY: 'riddle/history', + TASKS: 'tasks', + NEWS: 'news', + EVENTS: 'event', + CALENDAR: 'calendar', + IMPRESSUM: 'impressum', + TOKEN: 'token', + TOKEN_SCANNED: 'token-scanned', + COMMUNITY: 'community', + ORGANIZATION: 'organization', + TINDER: 'tinder', + ERROR: 'error', + EXTRA_PAGE: 'page', + FORM: 'form', + LEADER_BOARD: 'leaderboard', + RACE: 'race', + QR_FIGHT: 'qr-fight', + TEAMS: 'teams', + CREATE_TEAM: 'create-team', + EDIT_TEAM: 'edit-team', + MY_TEAM: 'my-team', + TEAM_ADMIN: 'team-admin', + ACCESS_KEY: 'access-key', + MAP: 'map', + DEBT: 'debt' +} as const +export type Paths = (typeof Paths)[keyof typeof Paths] -export enum AbsolutePaths { - HOME = '/home', - PROFILE = '/profile', - CHANGE_ALIAS = '/profile/change-alias', - CHANGE_GROUP = '/profile/change-group', - RIDDLE = '/riddle', - RIDDLE_HISTORY = '/riddle/history', - TASKS = '/tasks', - NEWS = '/news', - EVENTS = '/event', - IMPRESSUM = '/impressum', - TOKEN = '/token', - TOKEN_SCANNED = 'token-scanned', - COMMUNITY = '/community', - ORGANIZATION = '/organization', - ERROR = '/error', - EXTRA_PAGE = '/page', - FORM = '/form', - RACE = '/race', - TEAMS = '/teams', - CREATE_TEAM = '/create-team', - EDIT_TEAM = '/edit-team', - MY_TEAM = '/my-team', - TEAM_ADMIN = '/team-admin', - QR_FIGHT = '/qr-fight', - LEADER_BOARD = '/leaderboard', - ACCESS_KEY = '/access-key', - MAP = '/map', - DEBT = '/debt' -} +export const AbsolutePaths = { + HOME: '/home', + PROFILE: '/profile', + CHANGE_ALIAS: '/profile/change-alias', + CHANGE_GROUP: '/profile/change-group', + RIDDLE: '/riddle', + RIDDLE_HISTORY: '/riddle/history', + TASKS: '/tasks', + NEWS: '/news', + EVENTS: '/event', + IMPRESSUM: '/impressum', + TOKEN: '/token', + TOKEN_SCANNED: 'token-scanned', + COMMUNITY: '/community', + ORGANIZATION: '/organization', + TINDER: '/tinder', + ERROR: '/error', + EXTRA_PAGE: '/page', + FORM: '/form', + RACE: '/race', + TEAMS: '/teams', + CREATE_TEAM: '/create-team', + EDIT_TEAM: '/edit-team', + MY_TEAM: '/my-team', + TEAM_ADMIN: '/team-admin', + QR_FIGHT: '/qr-fight', + LEADER_BOARD: '/leaderboard', + ACCESS_KEY: '/access-key', + MAP: '/map', + DEBT: '/debt' +} as const +export type AbsolutePaths = (typeof AbsolutePaths)[keyof typeof AbsolutePaths] -export enum ApiPaths { - CONFIG = '/api/app', - EVENTS = '/api/events', - FORM = '/api/form', - PAGE = '/api/page', - NEWS = '/api/news', - RACE = '/api/race', - FREESTYLE_RACE = '/api/freestyle-race', - RACE_BY_TEAM = '/api/race-by-team', - RIDDLE = '/api/riddle', - RIDDLE_HISTORY = '/api/riddle-history', - TASK = '/api/task', - TASK_SUBMIT = '/api/task/submit', - REFRESH = '/api/control/refresh', - WARNING = '/api/warning', - TASK_CATEGORY = '/api/task/category', - PROFILE = '/api/profile', - WHO_AM_I = '/api/whoami', - LEVELS = '/api/levels', - LOCATION = '/api/track-my-group', - TOKENS = '/api/tokens', - CHANGE_ALIAS = '/api/profile/change-alias', - CHANGE_GROUP = '/api/group/select', - COMMUNITY = '/api/community', - ORGANIZATION = '/api/organization', - ACCESS_KEY = '/api/access-key', - HOME_NEWS = '/api/home/news', - HOME_GALLERY = '/api/gallery/home', - ADD_PUSH_NOTIFICATION_TOKEN = '/api/pushnotification/add-token', - DELETE_PUSH_NOTIFICATION_TOKEN = '/api/pushnotification/delete-token', - MY_TEAM = '/api/team/my', - TEAM = '/api/team', - ALL_TEAMS = '/api/teams', - DEBTS = '/api/debts' -} +export const ApiPaths = { + CONFIG: '/api/app', + EVENTS: '/api/events', + FORM: '/api/form', + PAGE: '/api/page', + NEWS: '/api/news', + RACE: '/api/race', + FREESTYLE_RACE: '/api/freestyle-race', + RACE_BY_TEAM: '/api/race-by-team', + RIDDLE: '/api/riddle', + RIDDLE_HISTORY: '/api/riddle-history', + TASK: '/api/task', + TASK_SUBMIT: '/api/task/submit', + REFRESH: '/api/control/refresh', + WARNING: '/api/warning', + TASK_CATEGORY: '/api/task/category', + PROFILE: '/api/profile', + WHO_AM_I: '/api/whoami', + LEVELS: '/api/levels', + LOCATION: '/api/track-my-group', + TOKENS: '/api/tokens', + CHANGE_ALIAS: '/api/profile/change-alias', + CHANGE_GROUP: '/api/group/select', + COMMUNITY: '/api/community', + ORGANIZATION: '/api/organization', + TINDER: '/api/tinder/community', + TINDER_QUESTION: '/api/tinder/question', + TINDER_ANSWERS: '/api/tinder/question/answers', + TINDER_INTERACTION: '/api/tinder/community/interact', + ACCESS_KEY: '/api/access-key', + HOME_NEWS: '/api/home/news', + HOME_GALLERY: '/api/gallery/home', + ADD_PUSH_NOTIFICATION_TOKEN: '/api/pushnotification/add-token', + DELETE_PUSH_NOTIFICATION_TOKEN: '/api/pushnotification/delete-token', + MY_TEAM: '/api/team/my', + TEAM: '/api/team', + ALL_TEAMS: '/api/teams', + DEBTS: '/api/debts' +} as const +export type ApiPaths = (typeof ApiPaths)[keyof typeof ApiPaths] diff --git a/frontend/src/util/views/authInfo.view.ts b/frontend/src/util/views/authInfo.view.ts index ad821143d..5b6521aa7 100644 --- a/frontend/src/util/views/authInfo.view.ts +++ b/frontend/src/util/views/authInfo.view.ts @@ -1,16 +1,17 @@ -import { RoleTypeString } from './profile.view.ts' +import { RoleType } from './profile.view.ts' -export enum AuthState { - EXPIRED = 'EXPIRED', - LOGGED_IN = 'LOGGED_IN', - LOGGED_OUT = 'LOGGED_OUT' +export const AuthState = { + EXPIRED: 'EXPIRED', + LOGGED_IN: 'LOGGED_IN', + LOGGED_OUT: 'LOGGED_OUT' } +export type AuthState = (typeof AuthState)[keyof typeof AuthState] export type UserAuthInfoView = { authState: AuthState id?: number internalId?: string - role?: RoleTypeString + role?: keyof typeof RoleType permissionsAsList?: string[] userName?: string groupId?: number diff --git a/frontend/src/util/views/form.view.ts b/frontend/src/util/views/form.view.ts index d313cb558..b162c2b74 100644 --- a/frontend/src/util/views/form.view.ts +++ b/frontend/src/util/views/form.view.ts @@ -1,4 +1,4 @@ -import { Signup } from '../../api/contexts/config/types' +import type { Signup } from '../../api/contexts/config/types' export type FormData = { form?: Form @@ -40,18 +40,19 @@ export type GridFieldValues = { }[] } -export enum FormStatus { - NO_SUBMISSION = 'NO_SUBMISSION', - SUBMITTED = 'SUBMITTED', - REJECTED = 'REJECTED', - ACCEPTED = 'ACCEPTED', - TOO_EARLY = 'TOO_EARLY', - TOO_LATE = 'TOO_LATE', - NOT_ENABLED = 'NOT_ENABLED', - NOT_FOUND = 'NOT_FOUND', - FULL = 'FULL', - GROUP_NOT_PERMITTED = 'GROUP_NOT_PERMITTED' +export const FormStatus = { + NO_SUBMISSION: 'NO_SUBMISSION', + SUBMITTED: 'SUBMITTED', + REJECTED: 'REJECTED', + ACCEPTED: 'ACCEPTED', + TOO_EARLY: 'TOO_EARLY', + TOO_LATE: 'TOO_LATE', + NOT_ENABLED: 'NOT_ENABLED', + NOT_FOUND: 'NOT_FOUND', + FULL: 'FULL', + GROUP_NOT_PERMITTED: 'GROUP_NOT_PERMITTED' } +export type FormStatus = (typeof FormStatus)[keyof typeof FormStatus] export const FormStatusLangKeys: Record = { [FormStatus.NO_SUBMISSION]: 'langNoSubmission', @@ -66,35 +67,37 @@ export const FormStatusLangKeys: Record = { [FormStatus.GROUP_NOT_PERMITTED]: 'langGroupInsufficient' } -export enum FormFieldVariants { - TEXT = 'TEXT', - VOTE = 'VOTE', - LONG_TEXT = 'LONG_TEXT', - NUMBER = 'NUMBER', - EMAIL = 'EMAIL', - PHONE = 'PHONE', - CHECKBOX = 'CHECKBOX', - SELECT = 'SELECT', - MUST_AGREE = 'MUST_AGREE', - INFO_BOX = 'INFO_BOX', - WARNING_BOX = 'WARNING_BOX', - TEXT_BOX = 'TEXT_BOX', - SECTION_START = 'SECTION_START', - CHOICE_GRID = 'CHOICE_GRID', - DATE = 'DATE', - SELECTION_GRID = 'SELECTION_GRID' +export const FormFieldVariants = { + TEXT: 'TEXT', + VOTE: 'VOTE', + LONG_TEXT: 'LONG_TEXT', + NUMBER: 'NUMBER', + EMAIL: 'EMAIL', + PHONE: 'PHONE', + CHECKBOX: 'CHECKBOX', + SELECT: 'SELECT', + MUST_AGREE: 'MUST_AGREE', + INFO_BOX: 'INFO_BOX', + WARNING_BOX: 'WARNING_BOX', + TEXT_BOX: 'TEXT_BOX', + SECTION_START: 'SECTION_START', + CHOICE_GRID: 'CHOICE_GRID', + DATE: 'DATE', + SELECTION_GRID: 'SELECTION_GRID' } +export type FormFieldVariants = (typeof FormFieldVariants)[keyof typeof FormFieldVariants] -export enum FormSubmitResult { - OK = 'OK', - OK_RELOG_REQUIRED = 'OK_RELOG_REQUIRED', - ALREADY_SUBMITTED = 'ALREADY_SUBMITTED', - INVALID_VALUES = 'INVALID_VALUES', - FORM_NOT_AVAILABLE = 'FORM_NOT_AVAILABLE', - FORM_IS_FULL = 'FORM_IS_FULL', - EDIT_SUBMISSION_NOT_FOUND = 'EDIT_SUBMISSION_NOT_FOUND', - EDIT_CANNOT_BE_CHANGED = 'EDIT_CANNOT_BE_CHANGED' +export const FormSubmitResult = { + OK: 'OK', + OK_RELOG_REQUIRED: 'OK_RELOG_REQUIRED', + ALREADY_SUBMITTED: 'ALREADY_SUBMITTED', + INVALID_VALUES: 'INVALID_VALUES', + FORM_NOT_AVAILABLE: 'FORM_NOT_AVAILABLE', + FORM_IS_FULL: 'FORM_IS_FULL', + EDIT_SUBMISSION_NOT_FOUND: 'EDIT_SUBMISSION_NOT_FOUND', + EDIT_CANNOT_BE_CHANGED: 'EDIT_CANNOT_BE_CHANGED' } +export type FormSubmitResult = (typeof FormSubmitResult)[keyof typeof FormSubmitResult] export const FormSubmitMessage: Record = { OK: 'Sikeres beküldés!', diff --git a/frontend/src/util/views/groupChange.view.ts b/frontend/src/util/views/groupChange.view.ts index e12375053..4b6cf8512 100644 --- a/frontend/src/util/views/groupChange.view.ts +++ b/frontend/src/util/views/groupChange.view.ts @@ -2,10 +2,11 @@ export type GroupChangeDTO = { status: GroupChangeStatus } -export enum GroupChangeStatus { - OK = 'OK', - INVALID_GROUP = 'INVALID_GROUP', - LEAVE_DENIED = 'LEAVE_DENIED', - PERMISSION_DENIED = 'PERMISSION_DENIED', - UNAUTHORIZED = 'UNAUTHORIZED' +export const GroupChangeStatus = { + OK: 'OK', + INVALID_GROUP: 'INVALID_GROUP', + LEAVE_DENIED: 'LEAVE_DENIED', + PERMISSION_DENIED: 'PERMISSION_DENIED', + UNAUTHORIZED: 'UNAUTHORIZED' } +export type GroupChangeStatus = (typeof GroupChangeStatus)[keyof typeof GroupChangeStatus] diff --git a/frontend/src/util/views/map.view.ts b/frontend/src/util/views/map.view.ts index 63418712f..6b237c973 100644 --- a/frontend/src/util/views/map.view.ts +++ b/frontend/src/util/views/map.view.ts @@ -1,4 +1,4 @@ -import { FunctionComponent } from 'react' +import type { FunctionComponent } from 'react' import { FaBroadcastTower, FaCampground, FaCar, FaCrosshairs, FaHome, FaInfo, FaMarker, FaUser } from 'react-icons/fa' export type MapDataItemView = { @@ -16,18 +16,19 @@ export type MapDataItemView = { timestamp: number } -export enum MapMarkerShape { - CIRCLE = 'CIRCLE', - SQUARE = 'SQUARE', - INFO = 'INFO', - CAR = 'CAR', - CROSSHAIRS = 'CROSSHAIRS', - CAMP = 'CAMP', - TOWER = 'TOWER', - MARKER = 'MARKER', - HOME = 'HOME', - PERSON = 'PERSON' +export const MapMarkerShape = { + CIRCLE: 'CIRCLE', + SQUARE: 'SQUARE', + INFO: 'INFO', + CAR: 'CAR', + CROSSHAIRS: 'CROSSHAIRS', + CAMP: 'CAMP', + TOWER: 'TOWER', + MARKER: 'MARKER', + HOME: 'HOME', + PERSON: 'PERSON' } +export type MapMarkerShape = (typeof MapMarkerShape)[keyof typeof MapMarkerShape] export const MapMarkerIcons: Record = { [MapMarkerShape.CIRCLE]: () => null, diff --git a/frontend/src/util/views/profile.view.ts b/frontend/src/util/views/profile.view.ts index fc70a9cc6..b9b46953d 100644 --- a/frontend/src/util/views/profile.view.ts +++ b/frontend/src/util/views/profile.view.ts @@ -1,8 +1,8 @@ -import { DebtView } from './debt.view' -import { GroupLeaderView } from './groupLeader.view' -import { GroupMemberLocationView } from './groupMemberLocation.view' -import { TokenView } from './token.view' -import { TopListAbstractEntryView } from './toplistAbstractEntry.view' +import type { DebtView } from './debt.view' +import type { GroupLeaderView } from './groupLeader.view' +import type { GroupMemberLocationView } from './groupMemberLocation.view' +import type { TokenView } from './token.view' +import type { TopListAbstractEntryView } from './toplistAbstractEntry.view' export interface ProfileView { cmschId?: string @@ -57,39 +57,43 @@ export interface RaceStatsView { } //cannot compare roles if the enums values are strings use the RoleType[role] syntax -export enum RoleType { - GUEST = 0, // anyone without login - BASIC = 1, // has auth.sch but not member of SSSL - ATTENDEE = 10, // has auth.sch but not member of SSSL and has a group or has submitted form - PRIVILEGED = 11, // has auth.sch but not member of SSSL and is a group admin - STAFF = 100, // member of the SSSL - ADMIN = 200, // the organizers of the event - SUPERUSER = 500 // advanced user management (able to grant admin access) +export const RoleType = { + GUEST: 0, + BASIC: 1, + ATTENDEE: 10, + PRIVILEGED: 11, + STAFF: 100, + ADMIN: 200, + SUPERUSER: 500 } +export type RoleType = (typeof RoleType)[keyof typeof RoleType] +export type RoleTypeString = keyof typeof RoleType -export enum RoleTypeString { - GUEST = 'GUEST', - BASIC = 'BASIC', - ATTENDEE = 'ATTENDEE', - PRIVILEGED = 'PRIVILEGED', - STAFF = 'STAFF', - ADMIN = 'ADMIN', - SUPERUSER = 'SUPERUSER' +export const RoleTypeString: { [k: string]: RoleTypeString } = { + GUEST: 'GUEST', + BASIC: 'BASIC', + ATTENDEE: 'ATTENDEE', + PRIVILEGED: 'PRIVILEGED', + STAFF: 'STAFF', + ADMIN: 'ADMIN', + SUPERUSER: 'SUPERUSER' } -export enum GuildType { - UNKNOWN = 'Nincs', - RED = 'Piros', - BLACK = 'Fekete', - BLUE = 'Kék', - WHITE = 'Fehér', - YELLOW = 'Sárga', - PURPLE = 'Lila' +export const GuildType = { + UNKNOWN: 'Nincs', + RED: 'Piros', + BLACK: 'Fekete', + BLUE: 'Kék', + WHITE: 'Fehér', + YELLOW: 'Sárga', + PURPLE: 'Lila' } +export type GuildType = (typeof GuildType)[keyof typeof GuildType] -export enum MajorType { - UNKNOWN, - IT, - EE, - BPROF +export const MajorType = { + UNKNOWN: 'UNKNOWN', + IT: 'IT', + EE: 'EE', + BPROF: 'BPROF' } +export type MajorType = (typeof MajorType)[keyof typeof MajorType] diff --git a/frontend/src/util/views/qrFight.view.ts b/frontend/src/util/views/qrFight.view.ts index 3fd33d9c3..3caf6e207 100644 --- a/frontend/src/util/views/qrFight.view.ts +++ b/frontend/src/util/views/qrFight.view.ts @@ -39,10 +39,11 @@ export type Totem = { owner?: string } -export enum LevelStatus { - NOT_LOGGED_IN = 'NOT_LOGGED_IN', - NOT_ENABLED = 'NOT_ENABLED', - NOT_UNLOCKED = 'NOT_UNLOCKED', - OPEN = 'OPEN', - COMPLETED = 'COMPLETED' +export const LevelStatus = { + NOT_LOGGED_IN: 'NOT_LOGGED_IN', + NOT_ENABLED: 'NOT_ENABLED', + NOT_UNLOCKED: 'NOT_UNLOCKED', + OPEN: 'OPEN', + COMPLETED: 'COMPLETED' } +export type LevelStatus = (typeof LevelStatus)[keyof typeof LevelStatus] diff --git a/frontend/src/util/views/race.view.ts b/frontend/src/util/views/race.view.ts index 319d99366..8c5cacdff 100644 --- a/frontend/src/util/views/race.view.ts +++ b/frontend/src/util/views/race.view.ts @@ -1,4 +1,4 @@ -import { LeaderBoardItemView } from './leaderBoardView' +import type { LeaderBoardItemView } from './leaderBoardView' export type RaceView = { categoryName: string diff --git a/frontend/src/util/views/riddle.view.ts b/frontend/src/util/views/riddle.view.ts index b840070e4..a9d604a98 100644 --- a/frontend/src/util/views/riddle.view.ts +++ b/frontend/src/util/views/riddle.view.ts @@ -27,12 +27,13 @@ export interface RiddleCategory { nextRiddles: Riddle[] } -export enum RiddleSubmissionStatus { - CORRECT = 'CORRECT', - WRONG = 'WRONG', - CANNOT_SKIP = 'CANNOT_SKIP', - SUBMITTER_BANNED = 'SUBMITTER_BANNED' +export const RiddleSubmissionStatus = { + CORRECT: 'CORRECT', + WRONG: 'WRONG', + CANNOT_SKIP: 'CANNOT_SKIP', + SUBMITTER_BANNED: 'SUBMITTER_BANNED' } +export type RiddleSubmissionStatus = (typeof RiddleSubmissionStatus)[keyof typeof RiddleSubmissionStatus] export interface RiddleSubmissionResult { status: RiddleSubmissionStatus diff --git a/frontend/src/util/views/socialPage.view.ts b/frontend/src/util/views/socialPage.view.ts index 2a4229535..a7fab2b9f 100644 --- a/frontend/src/util/views/socialPage.view.ts +++ b/frontend/src/util/views/socialPage.view.ts @@ -1,4 +1,4 @@ -import { IconType } from 'react-icons' +import type { IconType } from 'react-icons' export type SocialPageView = { href: string diff --git a/frontend/src/util/views/task.view.ts b/frontend/src/util/views/task.view.ts index 475610367..dd32dc2c7 100644 --- a/frontend/src/util/views/task.view.ts +++ b/frontend/src/util/views/task.view.ts @@ -1,59 +1,65 @@ -import { TopListAbstractEntryView } from './toplistAbstractEntry.view' +import type { TopListAbstractEntryView } from './toplistAbstractEntry.view' -export enum taskType { - TEXT = 'TEXT', - IMAGE = 'IMAGE', - BOTH = 'BOTH', - ONLY_PDF = 'ONLY_PDF', - ONLY_ZIP = 'ONLY_ZIP' +export const TaskType = { + TEXT: 'TEXT', + IMAGE: 'IMAGE', + BOTH: 'BOTH', + ONLY_PDF: 'ONLY_PDF', + ONLY_ZIP: 'ONLY_ZIP' } +export type TaskType = (typeof TaskType)[keyof typeof TaskType] -export enum taskFormat { - TEXT = 'TEXT', - NONE = 'NONE', - CODE = 'CODE', - FORM = 'FORM' +export const TaskFormat = { + TEXT: 'TEXT', + NONE: 'NONE', + CODE: 'CODE', + FORM: 'FORM' } +export type TaskFormat = (typeof TaskFormat)[keyof typeof TaskFormat] -export enum taskStatus { - ACCEPTED = 'ACCEPTED', - NOT_LOGGED_IN = 'NOT_LOGGED_IN', - NOT_SUBMITTED = 'NOT_SUBMITTED', - REJECTED = 'REJECTED', - SUBMITTED = 'SUBMITTED' +export const TaskStatus = { + ACCEPTED: 'ACCEPTED', + NOT_LOGGED_IN: 'NOT_LOGGED_IN', + NOT_SUBMITTED: 'NOT_SUBMITTED', + REJECTED: 'REJECTED', + SUBMITTED: 'SUBMITTED' } +export type TaskStatus = (typeof TaskStatus)[keyof typeof TaskStatus] -export enum taskSubmissionStatus { - OK = 'OK', - EMPTY_ANSWER = 'EMPTY_ANSWER', - INVALID_IMAGE = 'INVALID_IMAGE', - INVALID_PDF = 'INVALID_PDF', - INVALID_ZIP = 'INVALID_ZIP', - ALREADY_SUBMITTED = 'ALREADY_SUBMITTED', - ALREADY_APPROVED = 'ALREADY_APPROVED', - NO_ASSOCIATE_GROUP = 'NO_ASSOCIATE_GROUP', - INVALID_TASK_ID = 'INVALID_TASK_ID', - TOO_EARLY_OR_LATE = 'TOO_EARLY_OR_LATE', - NO_PERMISSION = 'NO_PERMISSION', - INVALID_BACKEND_CONFIG = 'INVALID_BACKEND_CONFIG' +export const TaskSubmissionStatus = { + OK: 'OK', + EMPTY_ANSWER: 'EMPTY_ANSWER', + INVALID_IMAGE: 'INVALID_IMAGE', + INVALID_PDF: 'INVALID_PDF', + INVALID_ZIP: 'INVALID_ZIP', + ALREADY_SUBMITTED: 'ALREADY_SUBMITTED', + ALREADY_APPROVED: 'ALREADY_APPROVED', + NO_ASSOCIATE_GROUP: 'NO_ASSOCIATE_GROUP', + INVALID_TASK_ID: 'INVALID_TASK_ID', + TOO_EARLY_OR_LATE: 'TOO_EARLY_OR_LATE', + NO_PERMISSION: 'NO_PERMISSION', + INVALID_BACKEND_CONFIG: 'INVALID_BACKEND_CONFIG' } +export type TaskSubmissionStatus = (typeof TaskSubmissionStatus)[keyof typeof TaskSubmissionStatus] -export enum taskCategoryType { - REGULAR = 'REGULAR', - PROFILE_REQUIRED = 'PROFILE_REQUIRED' +export const TaskCategoryType = { + REGULAR: 'REGULAR', + PROFILE_REQUIRED: 'PROFILE_REQUIRED' } +export type TaskCategoryType = (typeof TaskCategoryType)[keyof typeof TaskCategoryType] -export enum codeLanguage { - C = 'c', - CPP = 'cpp', - CSHARP = 'csharp', - JAVA = 'java', - JAVASCRIPT = 'javascript', - TYPESCRIPT = 'typescript', - SQL = 'sql', - KOTLIN = 'kotlin', - PYTHON = 'python' +export const CodeLanguage = { + C: 'c', + CPP: 'cpp', + CSHARP: 'csharp', + JAVA: 'java', + JAVASCRIPT: 'javascript', + TYPESCRIPT: 'typescript', + SQL: 'sql', + KOTLIN: 'kotlin', + PYTHON: 'python' } +export type CodeLanguage = (typeof CodeLanguage)[keyof typeof CodeLanguage] export interface TaskFormatDescriptor { title: string @@ -70,7 +76,7 @@ export interface TaskCategoryPreview { notGraded: number rejected: number sum: number - type: taskCategoryType + type: TaskCategoryType } export interface TaskCategoryFullDetails { @@ -94,8 +100,8 @@ export interface TaskEntity { categoryName?: string description: string expectedResultDescription: string - type: taskType - format: taskFormat + type: TaskType + format: TaskFormat formatDescriptor: string availableFrom: number availableTo: number @@ -104,12 +110,12 @@ export interface TaskEntity { export interface TaskWrapper { task: TaskEntity response: string - status: taskStatus + status: TaskStatus } export interface TaskFullDetailsView { task?: TaskEntity - status: taskStatus + status: TaskStatus submission?: { id: number task?: TaskEntity diff --git a/frontend/src/util/views/team.view.ts b/frontend/src/util/views/team.view.ts index aa7dc26e5..1256c88ec 100644 --- a/frontend/src/util/views/team.view.ts +++ b/frontend/src/util/views/team.view.ts @@ -1,4 +1,4 @@ -import { TaskCategoryPreview } from './task.view' +import type { TaskCategoryPreview } from './task.view' export type TeamDashboardView = { memberCount: number @@ -22,10 +22,11 @@ export type OptionalTeamView = { team?: TeamView } -export enum TeamStatus { - PLAYING = 'PLAYING', - NOT_VISIBLE = 'NOT_VISIBLE' +export const TeamStatus = { + PLAYING: 'PLAYING', + NOT_VISIBLE: 'NOT_VISIBLE' } +export type TeamStatus = (typeof TeamStatus)[keyof typeof TeamStatus] export type TeamView = { coverUrl: string @@ -84,20 +85,21 @@ export type TeamFormView = { url: string } -export enum TeamResponses { - ALREADY_IN_GROUP = 'ALREADY_IN_GROUP', - JOINING_DISABLED = 'JOINING_DISABLED', - NOT_JOINABLE = 'NOT_JOINABLE', - ALREADY_SUBMITTED_JOIN_REQUEST = 'ALREADY_SUBMITTED_JOIN_REQUEST', - OK = 'OK', - INVALID_NAME = 'INVALID_NAME', - USED_NAME = 'USED_NAME', - CREATION_DISABLED = 'CREATION_DISABLED', - INSUFFICIENT_PERMISSIONS = 'INSUFFICIENT_PERMISSIONS', - OK_RELOG_REQUIRED = 'OK_RELOG_REQUIRED', - LEAVE_DISABLED = 'LEAVE_DISABLED', - ERROR = 'ERROR' +export const TeamResponses = { + ALREADY_IN_GROUP: 'ALREADY_IN_GROUP', + JOINING_DISABLED: 'JOINING_DISABLED', + NOT_JOINABLE: 'NOT_JOINABLE', + ALREADY_SUBMITTED_JOIN_REQUEST: 'ALREADY_SUBMITTED_JOIN_REQUEST', + OK: 'OK', + INVALID_NAME: 'INVALID_NAME', + USED_NAME: 'USED_NAME', + CREATION_DISABLED: 'CREATION_DISABLED', + INSUFFICIENT_PERMISSIONS: 'INSUFFICIENT_PERMISSIONS', + OK_RELOG_REQUIRED: 'OK_RELOG_REQUIRED', + LEAVE_DISABLED: 'LEAVE_DISABLED', + ERROR: 'ERROR' } +export type TeamResponses = (typeof TeamResponses)[keyof typeof TeamResponses] export const TeamResponseMessages: Record = { [TeamResponses.OK]: 'Sikeres művelet!', diff --git a/frontend/src/util/views/tinder.ts b/frontend/src/util/views/tinder.ts new file mode 100644 index 000000000..55bbb2683 --- /dev/null +++ b/frontend/src/util/views/tinder.ts @@ -0,0 +1,57 @@ +export interface TinderQuestion { + id: number + question: string + options: string[] +} + +export interface TinderAnswer { + questionId: number + answer: string +} + +export const TinderStatus = { + NOT_SEEN: 'NOT_SEEN', + LIKED: 'LIKED', + DISLIKED: 'DISLIKED' +} as const +export type TinderStatus = (typeof TinderStatus)[keyof typeof TinderStatus] + +export interface TinderCommunity { + id: number + name: string + matchedAnswers: number + status: TinderStatus + shortDescription: string + descriptionParagraphs: string + website: string + logo: string + established: string + email: string + interests: string[] + facebook: string + instagram: string + application: string + resortName: string + tinderAnswers: string[] +} +export const SendAnswerResponseStatus = { + OK: 'OK', + INVALID_ANSWER: 'INVALID_ANSWER', + TINDER_NOT_AVAILABLE: 'TINDER_NOT_AVAILABLE', + NO_PERMISSION: 'NO_PERMISSION', + ERROR: 'ERROR' +} as const +export type SendAnswerResponseStatus = (typeof SendAnswerResponseStatus)[keyof typeof SendAnswerResponseStatus] + +export const SendAnswerResponseMessage: Record = { + [SendAnswerResponseStatus.OK]: 'Válaszok sikeresen elmentve.', + [SendAnswerResponseStatus.INVALID_ANSWER]: 'Érvénytelen válasz(ok). Kérjük, ellenőrizze a válaszait.', + [SendAnswerResponseStatus.TINDER_NOT_AVAILABLE]: 'A Tinder jelenleg nem elérhető.', + [SendAnswerResponseStatus.NO_PERMISSION]: 'Nincs jogosultsága válaszokat küldeni.', + [SendAnswerResponseStatus.ERROR]: 'Hiba történt a válaszok mentése során. Kérjük, próbálja újra később.' +} + +export interface TinderInteractionDto { + communityId: number + liked: boolean +} diff --git a/frontend/src/util/views/token.view.ts b/frontend/src/util/views/token.view.ts index 1b2e6d25d..7fe76626c 100644 --- a/frontend/src/util/views/token.view.ts +++ b/frontend/src/util/views/token.view.ts @@ -11,26 +11,27 @@ export interface TokenView { icon: string } -export enum ScanStatus { - SCANNED = 'SCANNED', - ALREADY_SCANNED = 'ALREADY_SCANNED', - WRONG = 'WRONG', - CANNOT_COLLECT = 'CANNOT_COLLECT', - INACTIVE = 'INACTIVE', - QR_FIGHT_LEVEL_NOT_OPEN = 'QR_FIGHT_LEVEL_NOT_OPEN', - QR_FIGHT_LEVEL_LOCKED = 'QR_FIGHT_LEVEL_LOCKED', - QR_FIGHT_TOWER_LOCKED = 'QR_FIGHT_TOWER_LOCKED', - QR_FIGHT_INTERNAL_ERROR = 'QR_FIGHT_INTERNAL_ERROR', - QR_TOWER_LOGGED = 'QR_TOWER_LOGGED', - QR_TOWER_CAPTURED = 'QR_TOWER_CAPTURED', - QR_TOWER_ENSLAVED = 'QR_TOWER_ENSLAVED', - QR_TOWER_ALREADY_ENSLAVED = 'QR_TOWER_ALREADY_ENSLAVED', - QR_TOTEM_LOGGED = 'QR_TOTEM_LOGGED', - QR_TOTEM_ENSLAVED = 'QR_TOTEM_ENSLAVED', - QR_TOTEM_ALREADY_ENSLAVED = 'QR_TOTEM_ALREADY_ENSLAVED', - QR_FIGHT_TOTEM_LOCKED = 'QR_FIGHT_TOTEM_LOCKED', - QR_TOWER_DAILY_LIMIT_EXCEEDED = 'QR_TOWER_DAILY_LIMIT_EXCEEDED' +export const ScanStatus = { + SCANNED: 'SCANNED', + ALREADY_SCANNED: 'ALREADY_SCANNED', + WRONG: 'WRONG', + CANNOT_COLLECT: 'CANNOT_COLLECT', + INACTIVE: 'INACTIVE', + QR_FIGHT_LEVEL_NOT_OPEN: 'QR_FIGHT_LEVEL_NOT_OPEN', + QR_FIGHT_LEVEL_LOCKED: 'QR_FIGHT_LEVEL_LOCKED', + QR_FIGHT_TOWER_LOCKED: 'QR_FIGHT_TOWER_LOCKED', + QR_FIGHT_INTERNAL_ERROR: 'QR_FIGHT_INTERNAL_ERROR', + QR_TOWER_LOGGED: 'QR_TOWER_LOGGED', + QR_TOWER_CAPTURED: 'QR_TOWER_CAPTURED', + QR_TOWER_ENSLAVED: 'QR_TOWER_ENSLAVED', + QR_TOWER_ALREADY_ENSLAVED: 'QR_TOWER_ALREADY_ENSLAVED', + QR_TOTEM_LOGGED: 'QR_TOTEM_LOGGED', + QR_TOTEM_ENSLAVED: 'QR_TOTEM_ENSLAVED', + QR_TOTEM_ALREADY_ENSLAVED: 'QR_TOTEM_ALREADY_ENSLAVED', + QR_FIGHT_TOTEM_LOCKED: 'QR_FIGHT_TOTEM_LOCKED', + QR_TOWER_DAILY_LIMIT_EXCEEDED: 'QR_TOWER_DAILY_LIMIT_EXCEEDED' } +export type ScanStatus = (typeof ScanStatus)[keyof typeof ScanStatus] export const ScanMessages: Record = { [ScanStatus.SCANNED]: 'QR Beolvasva', diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json new file mode 100644 index 000000000..a76b1c6b2 --- /dev/null +++ b/frontend/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2023", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 43ccda828..d32ff6820 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -1,26 +1,4 @@ { - "compilerOptions": { - "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - "downlevelIteration": true, - "useDefineForClassFields": true, - "allowImportingTsExtensions": true, - "noUnusedLocals": true, - "noUnusedParameters": true - }, - "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] + "files": [], + "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }] } diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json index 97ede7ee6..8a67f62f4 100644 --- a/frontend/tsconfig.node.json +++ b/frontend/tsconfig.node.json @@ -1,11 +1,26 @@ { "compilerOptions": { - "composite": true, - "skipLibCheck": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true, - "strict": true + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true }, "include": ["vite.config.ts"] } diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 62b919fd7..af896d6f7 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,15 +1,21 @@ import legacy from '@vitejs/plugin-legacy' -import react from '@vitejs/plugin-react-swc' +import react from '@vitejs/plugin-react' import { defineConfig } from 'vite' // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react(), legacy({ modernPolyfills: true })], - build: { - rollupOptions: { - output: { - inlineDynamicImports: true + plugins: [ + react({ + babel: { + plugins: [['babel-plugin-react-compiler']] } + }), + legacy({ modernPolyfills: true }) + ], + build: { + rolldownOptions: { + optimization: { inlineConst: true, pifeForModuleWrappers: true }, + output: { inlineDynamicImports: true } } }, server: {