import { schema } from 'nexus' import * as ProjectController from '../../controllers/project' import { logger } from '../../utils/logger' import * as Auth from '../../utils/auth' import * as Slack from '../../utils/slack' import { syncCondoManger } from '../../queues' export const ProjectPendingActionsInput = schema.objectType({ name: 'ProjectPendingActionsInput', definition(t) { t.string('id') t.string('name') t.int('total') t.int('news') t.int('calendar') t.int('chat') t.int('amenities') t.int('marketPlace') t.int('packages') t.int('residents') t.int('tasks') t.int('files') t.int('contacts') t.int('filters') t.int('condoManager') t.int('total') }, }) export const ManagingCompanyPendingActionsInput = schema.objectType({ name: 'ManagingCompanyPendingActionsInput', definition(t) { t.list.field('projects', { type: ProjectPendingActionsInput }) }, }) export const Project = schema.objectType({ name: 'Project', definition(t) { t.model.id() t.model.tools() t.model.createdAt() t.model.updatedAt() t.model.key() t.model.isDeleted() t.model.active() t.model.name() t.model.colorHex() t.model.additionalInfo() t.model.hasSecurityAgent() t.model.hasGuessRegistration() t.model.hasFobAccess() t.model.hasRestaurant() t.model.hasGym() t.model.hasShowerInGym() t.model.hasLockerChangingRoom() t.model.hasGuessRoom() t.model.hasPartyRoom() t.model.allowDog() t.model.needDogInArmInCommonArea() t.model.hasAccessForDog() t.model.accessForDogInfo() t.model.hasParkingForWorker() t.model.parkingForWorkerInfo() t.model.hasParkingForGuess() t.model.parkingForGuessInfo() t.model.hasValet() t.model.hasCarWash() t.model.carWashInfo() t.model.hasResidentLockers() t.model.hasResidentParkings() t.model.residentCanEditUnits() t.model.residentCanEditLockers() t.model.residentCanEditParkings() t.model.residentCanEditAccessKeys() t.model.residentCanEditRemotes() t.model.remotePrice() t.model.accessKeyPrice() t.model.isInConstruction() t.model.condoManagerId() t.model.needAdApproval() t.model.coOwnershipDeclarationId() t.model.numberOfProperties() t.model.hasSyncedWithCondoManager() t.model.hubspotCompanyId() t.model.isLaunched() t.model.paySafeMerchantAccountId() t.model.paySafeRefundPin() t.model.condoFeeEFTBillDay() t.model.lastDataSyncDate() t.model.lastCondoManagerDataPushDate() t.model.privateColor() t.model.residentCanCreateUnits() t.model.residentCanCreateLockers() t.model.residentCanCreateParkings() t.model.residentCanCreateAccessKeys() t.model.residentCanCreateRemotes() t.model.isCondoProject() t.model.isRentalProject() t.model.squareLogoId() t.model.nameInitials() t.model.newTenantsNeedApproval() t.model.newFamilyMembersNeedApproval() t.model.newOwnersNeedApproval() t.model.stripeAccountId() t.model.stripeAccountAccessToken() t.model.automaticallyInviteResidentCreatedFromThirdParty() t.model.launchDate() t.model.residentCanCreateTask() t.model.residentCanEditEmail() t.model.residentCanEditPhoneNumber() t.model.residentCanEditFirstName() t.model.residentCanEditLastName() t.model.newAdNeedApproval() t.model.coOwnershipDeclaration() t.model.logo() t.model.squareLogo() t.model.accessKeys() t.model.ads() t.model.amenities() t.model.amenityBookingOptions() t.model.condoManagerComptes() t.model.contactsLinked() t.model.events() t.model.folders() t.model.lockers() t.model.managerStoreOrders() t.model.meetings() t.model.notes() t.model.notifications() t.model.offenses() t.model.packages() t.model.parkings() t.model.posts() t.model.servicesAvailable() t.model.remotes() t.model.reservations() t.model.rules2() t.model.segments() t.model.serviceProjects() t.model.serviceRequests() t.model.syncStatuses() t.model.tasks() t.model.unitRooms() t.model.currentUsers() t.model.activeUsersForProject() t.model.appInviteEmailHeaderImage() t.model.boardMembers() t.model.building() t.model.buildings() // t.model.contactPersons() // We're not using contactPersons anymore t.model.contacts() t.model.managerStoreItems() t.model.managingCompany() t.model.managingCompanyRoles() t.model.thirdPartyServiceSettings() t.model.thirdPartyServices() t.model.previousProjectsOfUser() t.model.managers() t.model.rules() t.model.sharedAmenities() t.model.tenantUsersForProject() t.model.users() }, }) export const ProjectQueries = schema.extendType({ type: 'Query', definition(t) { t.crud.project() t.crud.projects({ filtering: true, ordering: true }) t.field('managingCompanyPendingActions', { type: ManagingCompanyPendingActionsInput, args: { managingCompanyId: schema.idArg(), }, resolve: async (_, { managingCompanyId }, ctx: NexusContext) => { const [managingCompanyWithProjects, currentUserId] = await Promise.all([ ctx.prisma.managingCompany.findOne({ where: { id: managingCompanyId }, include: { projects: {}, }, }), Auth.getUserId(ctx), ]) const projectsWithData = await Promise.all( managingCompanyWithProjects.projects.map(async (project) => ProjectController.getPendingActionsForProject({ managingCompanyId: managingCompanyWithProjects.id, projectId: project.id, currentUserId, otherProjectIdsOfManagingCompany: managingCompanyWithProjects.projects.map( ({ id }) => id ), }) ) ) const projectsWithDataAndTotal = projectsWithData.map((project) => ({ ...project, total: project.tasks + project.news + project.calendar + project.chat + project.amenities + project.marketPlace + project.packages + project.residents + project.files + project.contacts + project.filters + project.condoManager, })) return { projects: projectsWithDataAndTotal, } }, }) }, }) export const ProjectMutation = schema.extendType({ type: 'Mutation', definition: (t) => { t.crud.deleteOneProject({ alias: 'deleteProject' }) t.crud.updateOneProject({ alias: 'updateProject' }) t.crud.createOneProject({ alias: 'createProject' }) t.field('syncProjectWithCondoManager', { type: 'Boolean', args: { projectId: schema.stringArg({ required: true }), }, resolve: async (parent, { projectId }, ctx) => { await syncCondoManger({ projectId }) return true }, }) t.field('createProject', { type: 'Project', args: { data: schema.arg({ type: 'ProjectCreateInput' }), }, resolve: async (parent, { data }, ctx: NexusContext) => { const userId = Auth.getUserId(ctx) const currentUser = await ctx.prisma.user.findOne({ where: { id: userId }, select: { managingCompany: { select: { id: true, }, }, }, }) const createdProject = await ProjectController.createProject({ data, managingCompanyId: currentUser.managingCompany.id, }) return ctx.prisma.project.findOne({ where: { id: createdProject.id } }) }, }) t.field('updateProject', { type: 'Project', args: { data: schema.arg({ type: 'ProjectUpdateInput' }), where: schema.arg({ type: 'ProjectWhereUniqueInput' }), }, resolve: async (parent, { data, where }, ctx: NexusContext) => { const updatedProject = await ctx.prisma.project.update({ where, data }) // Notifiy Charles whenever someone upload a logo if (data?.logo?.create?.url) { await ctx.prisma.project .findOne({ where: { id: updatedProject.id, }, select: { name: true, logo: { select: { url: true, }, }, managingCompany: { select: { shortName: true, longName: true, }, }, }, }) .catch(logger.error) } // Add thirdParty settings if project add condo manager id if (data.condoManagerId) { await ctx.prisma.project .findOne({ where: { id: updatedProject.id } }) .thirdPartyServiceSettings() .then((thirdPartyServicesSettings) => { if (thirdPartyServicesSettings.length === 0) { return ctx.prisma.project.update({ where: { id: updatedProject.id }, data: { thirdPartyServiceSettings: { create: [ { importEnabled: true, exportEnabled: true, importStatus: '', exportStatus: '', mappedService: { connect: { id: 'ck3f1v25yxpp70789unc2fvc4', // Condo manager mapped service }, }, }, ], }, }, }) } }) .catch(logger.error) } // If we update the project's address, let's update all the properties also. We should never change the building's address... but in case we've made a mistake. if (data.building && data.building.update && data.building.update.address) { await ctx.prisma.project .findOne({ where }) .building() .properties({ select: { address: { select: { id: true, apartmentNumber: true } } } }) .then((properties) => properties.map((property) => ctx.prisma.address .update({ where: { id: property.address.id }, data: { ...data.building.update.address.update, apartmentNumber: property.address.apartmentNumber, }, }) // .then(logger.info) .catch(logger.error) ) ) .catch(logger.error) } return updatedProject }, }) }, })