Skip to content

Commit

Permalink
feat(skilavottord): pagination and infinite scroll (#6195)
Browse files Browse the repository at this point in the history
* Where and before should be optional

* Relay like pagination of skilavottordAllDeregisteredVehicles

* Cleanup schema

* add infinite scroll

* Provide default type for generic

Co-authored-by: Darri Steinn Konradsson <[email protected]>
  • Loading branch information
miamiultras and darrikonn authored Jan 10, 2022
1 parent 82120a8 commit d268e5a
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 100 deletions.
94 changes: 80 additions & 14 deletions apps/skilavottord/web/screens/RecyclingFund/Overview/Overview.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FC, useContext } from 'react'
import React, { FC, useContext, useRef, useEffect } from 'react'
import gql from 'graphql-tag'
import { useQuery } from '@apollo/client'
import NextLink from 'next/link'
Expand All @@ -9,6 +9,7 @@ import {
Breadcrumbs,
GridColumn,
GridRow,
LoadingDots,
Stack,
Text,
} from '@island.is/island-ui/core'
Expand All @@ -21,16 +22,23 @@ import { Query, Role } from '@island.is/skilavottord-web/graphql/schema'
import { CarsTable, RecyclingCompanyImage } from './components'

export const SkilavottordVehiclesQuery = gql`
query skilavottordVehiclesQuery {
skilavottordAllDeregisteredVehicles {
vehicleId
vehicleType
newregDate
createdAt
recyclingRequests {
id
nameOfRequestor
query skilavottordVehiclesQuery($after: String!) {
skilavottordAllDeregisteredVehicles(first: 20, after: $after) {
pageInfo {
endCursor
hasNextPage
}
count
items {
vehicleId
vehicleType
newregDate
createdAt
recyclingRequests {
id
nameOfRequestor
createdAt
}
}
}
}
Expand All @@ -41,9 +49,54 @@ const Overview: FC = () => {
const {
t: { recyclingFundOverview: t, recyclingFundSidenav: sidenavText, routes },
} = useI18n()
const { data, loading, fetchMore } = useQuery<Query>(
SkilavottordVehiclesQuery,
{
notifyOnNetworkStatusChange: true,
variables: { after: '' },
},
)
const { pageInfo, items: vehicles } =
data?.skilavottordAllDeregisteredVehicles ?? {}

const triggerRef = useRef<HTMLDivElement>(null)

const { data } = useQuery<Query>(SkilavottordVehiclesQuery)
const vehicles = data?.skilavottordAllDeregisteredVehicles ?? []
useEffect(() => {
if (loading) return
const observer = new IntersectionObserver(
(entries) => {
const { hasNextPage, endCursor } = pageInfo
if (entries[0].isIntersecting && hasNextPage) {
fetchMore({
variables: { after: endCursor },
updateQuery: (
{ skilavottordAllDeregisteredVehicles },
{ fetchMoreResult },
) => {
const prevResults = skilavottordAllDeregisteredVehicles
const newResults =
fetchMoreResult?.skilavottordAllDeregisteredVehicles
return {
skilavottordAllDeregisteredVehicles: {
...newResults,
items: [...prevResults?.items, ...newResults?.items],
},
}
},
})
}
},
{
root: null,
rootMargin: '0px',
threshold: 1.0,
},
)
triggerRef.current && observer.observe(triggerRef.current)
return () => {
observer.disconnect()
}
}, [loading])

if (!user) {
return null
Expand Down Expand Up @@ -122,11 +175,24 @@ const Overview: FC = () => {
</Box>
<Stack space={3}>
<Text variant="h3">{t.subtitles.deregistered}</Text>
{vehicles.length > 0 ? (
<CarsTable titles={t.table} vehicles={vehicles} />
{vehicles?.length > 0 ? (
<>
<CarsTable titles={t.table} vehicles={vehicles} />

{loading && (
<Box display="flex" justifyContent="center" marginTop={4}>
<LoadingDots />
</Box>
)}
</>
) : loading ? (
<Box display="flex" justifyContent="center" marginTop={4}>
<LoadingDots />
</Box>
) : (
<Text>{t.info}</Text>
)}
<div ref={triggerRef} />
</Stack>
</Stack>
</PartnerPageLayout>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,17 @@ export class RecyclingRequestModel extends Model<RecyclingRequestModel> {
})
nameOfRequestor: string

@Field()
@Field({ nullable: true })
@CreatedAt
@Column({
field: 'created_at',
})
createdAt: Date
createdAt?: Date

@Field()
@Field({ nullable: true })
@UpdatedAt
@Column({
field: 'updated_at',
})
updatedAt: Date
updatedAt?: Date
}
38 changes: 33 additions & 5 deletions apps/skilavottord/ws/src/app/modules/vehicle/vehicle.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ export class VehicleModel extends Model<VehicleModel> {
})
vehicleColor: string

@Field()
@Field({ nullable: true })
@Column({
type: DataType.DATE,
})
newregDate: Date
newregDate?: Date

@Field()
@Column({
Expand All @@ -61,16 +61,44 @@ export class VehicleModel extends Model<VehicleModel> {
vinNumber: string

@Field()
@Field({ nullable: true })
@CreatedAt
@Column
createdAt: Date
createdAt?: Date

@Field()
@Field({ nullable: true })
@UpdatedAt
@Column
updatedAt: Date
updatedAt?: Date

@Field(() => [RecyclingRequestModel], { nullable: true })
@HasMany(() => RecyclingRequestModel)
recyclingRequests!: RecyclingRequestModel[]
}

@ObjectType()
export class PageInfo {
@Field()
hasNextPage!: boolean

@Field()
hasPreviousPage!: boolean

@Field({ nullable: true })
startCursor!: string

@Field({ nullable: true })
endCursor!: string
}

@ObjectType()
export class VehicleConnection {
@Field(() => PageInfo)
pageInfo!: PageInfo

@Field()
count!: number

@Field(() => [VehicleModel])
items: VehicleModel[]
}
35 changes: 17 additions & 18 deletions apps/skilavottord/ws/src/app/modules/vehicle/vehicle.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Inject, NotFoundException, forwardRef } from '@nestjs/common'
import { Query, Resolver, Mutation, Args } from '@nestjs/graphql'
import { Query, Resolver, Mutation, Args, Int } from '@nestjs/graphql'
import parse from 'date-fns/parse'

import type { Logger } from '@island.is/logging'
import { LOGGER_PROVIDER } from '@island.is/logging'

import { Authorize, CurrentUser, User, Role } from '../auth'

import { VehicleModel } from './vehicle.model'
import { VehicleModel, VehicleConnection } from './vehicle.model'
import { VehicleService } from './vehicle.service'
import { SamgongustofaService } from '../samgongustofa'

Expand All @@ -23,23 +23,22 @@ export class VehicleResolver {
) {}

@Authorize({ roles: [Role.developer, Role.recyclingCompany] })
@Query(() => [VehicleModel])
async skilavottordAllVehicles(): Promise<VehicleModel[]> {
const vehicles = await this.vehicleService.findAll()
this.logger.info(
'getAllVehicle response:' + JSON.stringify(vehicles, null, 2),
)
return vehicles
}

@Authorize({ roles: [Role.developer, Role.recyclingFund] })
@Query(() => [VehicleModel])
async skilavottordAllDeregisteredVehicles(): Promise<VehicleModel[]> {
const deregisteredVehicles = await this.vehicleService.findAllDeregistered()
this.logger.info(
'getAllVehicle response:' + JSON.stringify(deregisteredVehicles, null, 2),
)
return deregisteredVehicles
@Query(() => VehicleConnection)
async skilavottordAllDeregisteredVehicles(
@Args('first', { type: () => Int }) first: number,
@Args('after') after: string,
): Promise<VehicleConnection> {
const {
pageInfo,
totalCount,
data,
} = await this.vehicleService.findAllDeregistered(first, after)
return {
pageInfo,
count: totalCount,
items: data,
}
}

@Query(() => VehicleModel)
Expand Down
57 changes: 23 additions & 34 deletions apps/skilavottord/ws/src/app/modules/vehicle/vehicle.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Inject, Injectable } from '@nestjs/common'
import { InjectModel } from '@nestjs/sequelize'

import type { Logger } from '@island.is/logging'
import { LOGGER_PROVIDER } from '@island.is/logging'
import { paginate } from '@island.is/nest/pagination'

import { RecyclingRequestModel } from '../recyclingRequest'
import { RecyclingPartnerModel } from '../recyclingPartner'
Expand All @@ -12,44 +14,31 @@ export class VehicleService {
constructor(
@Inject(LOGGER_PROVIDER)
private logger: Logger,
@InjectModel(VehicleModel)
private vehicleModel: VehicleModel,
) {}

async findAll(): Promise<VehicleModel[]> {
this.logger.info('Getting all vehicles...')
try {
return await VehicleModel.findAll({
include: [
{
model: RecyclingRequestModel,
async findAllDeregistered(first: number, after: string) {
return paginate<VehicleModel>({
Model: this.vehicleModel,
limit: first,
after,
primaryKeyField: 'vehicleId',
orderOption: [['updatedAt', 'DESC']],
include: [
{
model: RecyclingRequestModel,
where: {
requestType: 'deregistered',
},
],
})
} catch (error) {
this.logger.error('error finding all vehicles:' + error)
}
}

async findAllDeregistered(): Promise<VehicleModel[]> {
this.logger.info('finding all deregistered vehicles...')
try {
return await VehicleModel.findAll({
include: [
{
model: RecyclingRequestModel,
where: {
requestType: 'deregistered',
include: [
{
model: RecyclingPartnerModel,
},
include: [
{
model: RecyclingPartnerModel,
},
],
},
],
})
} catch (error) {
this.logger.error('error finding all deregistered vehicles:' + error)
}
],
},
],
})
}

async findByVehicleId(vehicleId: string): Promise<VehicleModel> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,6 @@ export class VehicleOwnerResolver {
private logger: Logger,
) {}

@Query(() => [VehicleOwnerModel])
async skilavottordAllVehicleOwners(): Promise<VehicleOwnerModel[]> {
const res = await this.vehicleOwnerService.findAll()
this.logger.debug(
'getAllVehicleOwners responce:' + JSON.stringify(res, null, 2),
)
return res
}

@Query(() => VehicleOwnerModel)
async skilavottordVehiclesFromLocal(
@CurrentUser() user: User,
): Promise<VehicleOwnerModel> {
const res = await this.vehicleOwnerService.findByNationalId(user.nationalId)
this.logger.warn(
'getVehicleOwnersByNationaId responce:' + JSON.stringify(res, null, 2),
)
return res
}

@Authorize({
roles: [Role.developer, Role.recyclingCompany, Role.recyclingFund],
})
Expand Down
Loading

0 comments on commit d268e5a

Please sign in to comment.