diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 9a90cd1d..b813b187 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -15,6 +15,14 @@ jobs: - name: Checkout uses: actions/checkout@v1 + - name: "Automated Version Bump" + id: version-bump + uses: "phips28/gh-action-bump-version@master" + with: + tag-prefix: "v" + env: + GITHUB_TOKEN: ${{ secrets.ADMIN_GITHUB_TOKEN }} + - name: Log in to Docker Hub uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 with: diff --git a/Dockerfile b/Dockerfile index c1d49227..524f1683 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,9 +3,7 @@ FROM node:16 # Create app directory WORKDIR /usr/src/etenlab/crowd-rocks -COPY frontend /frontend/ -COPY api /api/ -COPY utils /utils/ +COPY . / ARG BUILD_MODE diff --git a/api/src/common/subscription-token.ts b/api/src/common/subscription-token.ts index eae3553d..b326ec51 100644 --- a/api/src/common/subscription-token.ts +++ b/api/src/common/subscription-token.ts @@ -9,6 +9,8 @@ export class SubscriptionToken { static pericopiesAdded = 'pericopiesAdded'; static pericopeDeleted = 'pericopeDeleted'; static pericopeVoteStatusToggled = 'pericopeVoteStatusToggled'; + static bestPericopeTrChanged = 'bestPericopeTrChanged'; + static recommendedPericopiesChanged = 'recommendedPericopiesChanged'; static questionsAdded = 'questionsAdded'; static questionsOnWordRangeAdded = 'questionsOnWordRangeAdded'; static answersAdded = 'answersAdded'; diff --git a/api/src/components/pericope-translations/pericope-tr.module.ts b/api/src/components/pericope-translations/pericope-tr.module.ts index 2f7732cd..619c2913 100644 --- a/api/src/components/pericope-translations/pericope-tr.module.ts +++ b/api/src/components/pericope-translations/pericope-tr.module.ts @@ -14,6 +14,6 @@ import { PericopiesModule } from '../pericopies/pericopies.module'; forwardRef(() => AuthenticationModule), ], providers: [PericopeTrService, PericopeTrResolver], - exports: [], + exports: [PericopeTrService], }) export class PericopeTrModule {} diff --git a/api/src/components/pericope-translations/pericope-tr.resolver.ts b/api/src/components/pericope-translations/pericope-tr.resolver.ts index bdc2f162..723e9d4d 100644 --- a/api/src/components/pericope-translations/pericope-tr.resolver.ts +++ b/api/src/components/pericope-translations/pericope-tr.resolver.ts @@ -1,4 +1,4 @@ -import { Injectable, Logger, UseGuards } from '@nestjs/common'; +import { Inject, Injectable, Logger, UseGuards } from '@nestjs/common'; import { Args, Context, @@ -7,25 +7,32 @@ import { Mutation, Query, Resolver, + Subscription, } from '@nestjs/graphql'; import { PericopeTrService } from './pericope-tr.service'; import { AddPericopeTranslationInput, + BestPericopeTrChanged, GetPericopeTranslationsInput, GetPericopiesTrInput, PericopeTranslation, PericopeTranslationsOutput, - PericopeTrVoteStatusAndBestTrListOutput, + PericopeTrVoteStatusAndBestTrOutput, PericopiesTextsWithTranslationConnection, } from './types'; import { BearerTokenAuthGuard } from '../../guards/bearer-token-auth.guard'; import { ErrorType } from '../../common/types'; -import { LanguageInput } from '../common/types'; +import { PUB_SUB } from '../../pubSub.module'; +import { PubSub } from 'graphql-subscriptions'; +import { SubscriptionToken } from '../../common/subscription-token'; @Injectable() @Resolver() export class PericopeTrResolver { - constructor(private pericopeTrService: PericopeTrService) {} + constructor( + private pericopeTrService: PericopeTrService, + @Inject(PUB_SUB) private readonly pubSub: PubSub, + ) {} @Query(() => PericopiesTextsWithTranslationConnection) async getPericopiesTr( @@ -56,40 +63,57 @@ export class PericopeTrResolver { } @UseGuards(BearerTokenAuthGuard) - @Mutation(() => PericopeTrVoteStatusAndBestTrListOutput) + @Mutation(() => PericopeTrVoteStatusAndBestTrOutput) async togglePericopeTrVoteStatus( @Args('pericope_translation_id', { type: () => ID }) pericope_translation_id: string, @Args('vote', { type: () => Boolean }) vote: boolean, @Context() req: any, - ): Promise { + ): Promise { Logger.log( `${JSON.stringify(pericope_translation_id)}`, `PericopeTrResolver#togglePericopeTrVoteStatus`, ); - const vote_status_list = await this.pericopeTrService.toggleVoteStatus( + const { pericopeId, lang } = ( + await this.pericopeTrService.getPericopeIdsAndLangsOfTranslationIds([ + pericope_translation_id, + ]) + )[0]; + + const oldBestTr = + await this.pericopeTrService.getRecomendedPericopeTranslation( + pericopeId, + lang, + ); + + const vote_status = await this.pericopeTrService.toggleVoteStatus( pericope_translation_id, vote, req.req.token as string, ); - const pIdsLangs: { pericopeId: string; lang: LanguageInput }[] = - await this.pericopeTrService.getPericopeIdsAndLangsOfTranslationIds( - vote_status_list.vote_status_list.map((v) => v.pericope_translation_id), + const best_translation = + await this.pericopeTrService.getRecomendedPericopeTranslation( + pericopeId, + lang, ); - const bestTrListPromises: Promise[] = - pIdsLangs.map((pIdLang) => { - return this.pericopeTrService.getRecomendedPericopeTranslation( - pIdLang.pericopeId, - pIdLang.lang, - ); + if ( + best_translation?.pericope_translation_id !== + oldBestTr?.pericope_translation_id + ) { + this.pubSub.publish(SubscriptionToken.bestPericopeTrChanged, { + [SubscriptionToken.bestPericopeTrChanged]: { + newPericopeTr: best_translation, + newVoteStatus: vote_status.vote_status, + } as BestPericopeTrChanged, }); + } return { - ...vote_status_list, - best_translation_list: await Promise.all(bestTrListPromises), + ...vote_status, + best_translation, }; } @@ -123,4 +147,12 @@ export class PericopeTrResolver { }; } } + + @Subscription(() => BestPericopeTrChanged, { + name: SubscriptionToken.bestPericopeTrChanged, + }) + async bestPericopeTrChanged() { + console.log('PericopeTrResolver#bestPericopeTrChanged'); + return this.pubSub.asyncIterator(SubscriptionToken.bestPericopeTrChanged); + } } diff --git a/api/src/components/pericope-translations/pericope-tr.service.ts b/api/src/components/pericope-translations/pericope-tr.service.ts index 27b34596..6ee58fbc 100644 --- a/api/src/components/pericope-translations/pericope-tr.service.ts +++ b/api/src/components/pericope-translations/pericope-tr.service.ts @@ -29,8 +29,7 @@ import { GetPericopiesTrInput, PericopeTranslation, PericopeTranslationWithVotes, - PericopeTrVoteStatus, - PericopeTrVoteStatusListOutput, + PericopeTrVoteStatusOutput, PericopiesTextsWithTranslationConnection, PericopiesTextsWithTranslationEdge, } from './types'; @@ -190,14 +189,13 @@ export class PericopeTrService { currPericopeid = word.pericope_id; currPericopeCursor++; } - // it's better to make ordered_pericopies plain zero-based array - ordered_pericopies[currPericopeCursor - 1] = { + ordered_pericopies[currPericopeCursor] = { pericopeCursor: currPericopeCursor, pericopeId: currPericopeid, words: [...(ordered_pericopies[currPericopeCursor]?.words || []), word], }; }); - return ordered_pericopies; + return ordered_pericopies.slice(1); } async getPericopeDescription( @@ -343,7 +341,7 @@ export class PericopeTrService { pericope_translation_id: string, vote: boolean, token: string, - ): Promise { + ): Promise { try { const res = await this.pg.pool.query( ...togglePericopeTrVoteStatusSql({ @@ -363,55 +361,43 @@ export class PericopeTrService { ) { return { error: creatingError, - vote_status_list: [], + vote_status: null, }; } - return this.getVoteStatusFromIds([pericope_translation_id]); + return this.getVoteStatusOfPericopeTrId(pericope_translation_id); } catch (e) { console.error(e); } return { error: ErrorType.UnknownError, - vote_status_list: [], + vote_status: null, }; } - async getVoteStatusFromIds( - pericopeTrIds: string[], - ): Promise { + async getVoteStatusOfPericopeTrId( + pericopeTrId: string, + ): Promise { try { const res = await this.pg.pool.query( - ...getPericopeTrVoteStatusFromPericopeIdsSql(pericopeTrIds), - ); - - const voteStatusMap = new Map(); - - res.rows.forEach((row) => - voteStatusMap.set(row.pericope_translation_id, row), + ...getPericopeTrVoteStatusFromPericopeIdsSql([pericopeTrId]), ); return { error: ErrorType.NoError, - vote_status_list: pericopeTrIds.map((pericope_translation_id) => { - const voteStatus = voteStatusMap.get(pericope_translation_id + ''); - - return voteStatus - ? voteStatus - : { - pericope_translation_id: pericope_translation_id + '', - upvotes: 0, - downvotes: 0, - }; - }), + vote_status: { + pericope_translation_id: res.rows[0].pericope_translation_id, + upvotes: res.rows[0].upvotes || 0, + downvotes: res.rows[0].downvotes || 0, + }, }; } catch (e) { Logger.error(e); } return { error: ErrorType.UnknownError, - vote_status_list: [], + vote_status: null, }; } diff --git a/api/src/components/pericope-translations/types.ts b/api/src/components/pericope-translations/types.ts index 179fcca2..0741e23d 100644 --- a/api/src/components/pericope-translations/types.ts +++ b/api/src/components/pericope-translations/types.ts @@ -101,12 +101,20 @@ export class PericopeTrVoteStatus { } @ObjectType() -export class PericopeTrVoteStatusListOutput extends GenericOutput { - @Field(() => [PericopeTrVoteStatus]) - vote_status_list: PericopeTrVoteStatus[]; +export class PericopeTrVoteStatusOutput extends GenericOutput { + @Field(() => PericopeTrVoteStatus) + vote_status: PericopeTrVoteStatus | null; } @ObjectType() -export class PericopeTrVoteStatusAndBestTrListOutput extends PericopeTrVoteStatusListOutput { - @Field(() => [PericopeTranslation]) - best_translation_list: Array; +export class PericopeTrVoteStatusAndBestTrOutput extends PericopeTrVoteStatusOutput { + @Field(() => PericopeTranslation) + best_translation: PericopeTranslation | null; +} + +@ObjectType() +export class BestPericopeTrChanged extends GenericOutput { + @Field(() => PericopeTranslation, { nullable: true }) + newPericopeTr: PericopeTranslation | null; + @Field(() => PericopeTrVoteStatus, { nullable: true }) + newVoteStatus: PericopeTrVoteStatus | null; } diff --git a/api/src/components/pericopies/pericopies.resolver.ts b/api/src/components/pericopies/pericopies.resolver.ts index 402f052f..8294203c 100644 --- a/api/src/components/pericopies/pericopies.resolver.ts +++ b/api/src/components/pericopies/pericopies.resolver.ts @@ -25,6 +25,7 @@ import { PericopeWithVotesListConnection, PericopeTextWithDescription, PericopeDeleteOutput, + RecomendedPericopiesChangedAtDocumentId, } from './types'; @Injectable() @@ -103,9 +104,30 @@ export class PericopiesResolver { [SubscriptionToken.pericopiesAdded]: newPericopies, }); + if (newPericopies.pericopies[0]?.pericope_id) { + const documentsData = + await this.pericopiesService.getDocumentIdsAndLangsOfPericopeIds([ + newPericopies.pericopies[0]?.pericope_id, + ]); + this.pubSub.publish(SubscriptionToken.recommendedPericopiesChanged, { + [SubscriptionToken.recommendedPericopiesChanged]: { + documentId: documentsData[0].documentId, + }, + }); + } + return newPericopies; } + @Subscription(() => RecomendedPericopiesChangedAtDocumentId, { + name: SubscriptionToken.recommendedPericopiesChanged, + }) + async subscribeToRecommendedPericopiesChanged() { + return this.pubSub.asyncIterator( + SubscriptionToken.recommendedPericopiesChanged, + ); + } + @Subscription(() => PericopiesOutput, { name: SubscriptionToken.pericopiesAdded, }) @@ -121,6 +143,11 @@ export class PericopiesResolver { ): Promise { Logger.log('deletePericopies: ', pericope_id); + const documentsData = + await this.pericopiesService.getDocumentIdsAndLangsOfPericopeIds([ + pericope_id, + ]); + const deletedPericope = await this.pericopiesService.delete( +pericope_id, getBearer(req) || '', @@ -131,6 +158,14 @@ export class PericopiesResolver { [SubscriptionToken.pericopeDeleted]: deletedPericope, }); + if (documentsData[0].documentId) { + this.pubSub.publish(SubscriptionToken.recommendedPericopiesChanged, { + [SubscriptionToken.recommendedPericopiesChanged]: { + documentId: documentsData[0].documentId, + }, + }); + } + return deletedPericope; } diff --git a/api/src/components/pericopies/pericopies.service.ts b/api/src/components/pericopies/pericopies.service.ts index c7fc8a42..737bf02a 100644 --- a/api/src/components/pericopies/pericopies.service.ts +++ b/api/src/components/pericopies/pericopies.service.ts @@ -1,4 +1,4 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { forwardRef, Inject, Injectable, Logger } from '@nestjs/common'; import { PoolClient } from 'pg'; import { calc_vote_weight, pgClientOrPool } from 'src/common/utility'; @@ -41,6 +41,7 @@ import { GetDocumentWordEntriesTotalPageSize, getDocumentWordEntriesTotalPageSize, } from '../documents/sql-string'; +import { LanguageInput } from '../common/types'; export const WORDS_JOINER = ' '; @@ -438,4 +439,37 @@ export class PericopiesService { }; } } + + async getDocumentIdsAndLangsOfPericopeIds( + pericope_ids: string[], + ): Promise> { + const res = await this.pg.pool.query<{ + document_id: string; + language_code: string; + dialect_code: string; + geo_code: string; + }>( + ` + select + d.document_id, + d.language_code, + d.dialect_code, + d.geo_code + from pericopies p + left join document_word_entries dwe on p.start_word = dwe.document_word_entry_id + left join documents d on dwe.document_id =d.document_id + where p.pericope_id = any($1) + `, + [pericope_ids], + ); + + return res.rows.map((row) => ({ + documentId: row.document_id, + lang: { + language_code: row.language_code, + dialect_code: row.dialect_code, + geo_code: row.geo_code, + }, + })); + } } diff --git a/api/src/components/pericopies/types.ts b/api/src/components/pericopies/types.ts index 8a82b008..f4250a7a 100644 --- a/api/src/components/pericopies/types.ts +++ b/api/src/components/pericopies/types.ts @@ -93,3 +93,7 @@ export class PericopeTextWithDescription extends GenericOutput { @Field(() => String) pericope_text: string; @Field(() => String) pericope_description_text: string; } +@ObjectType() +export class RecomendedPericopiesChangedAtDocumentId extends GenericOutput { + @Field(() => String) documentId: string; +} diff --git a/api/src/schema.gql b/api/src/schema.gql index c233707a..f4c1f989 100644 --- a/api/src/schema.gql +++ b/api/src/schema.gql @@ -48,6 +48,12 @@ type AvatarUpdateOutput { user: User } +type BestPericopeTrChanged { + error: ErrorType! + newPericopeTr: PericopeTranslation + newVoteStatus: PericopeTrVoteStatus +} + input BotTranslateDocumentInput { botType: BotType! documentId: String! @@ -706,7 +712,7 @@ type Mutation { threadUpsert(input: ThreadUpsertInput!): ThreadOutput! toggleFlagWithRef(name: String!, parent_id: String!, parent_table: TableNameType!): FlagsOutput! toggleMapVoteStatus(is_original: Boolean!, map_id: ID!, vote: Boolean!): MapVoteStatusOutputRow! - togglePericopeTrVoteStatus(pericope_translation_id: ID!, vote: Boolean!): PericopeTrVoteStatusAndBestTrListOutput! + togglePericopeTrVoteStatus(pericope_translation_id: ID!, vote: Boolean!): PericopeTrVoteStatusAndBestTrOutput! togglePericopeVoteStatus(pericope_id: ID!, vote: Boolean!): PericopeVoteStatusOutput! togglePhraseDefinitionVoteStatus(phrase_definition_id: ID!, vote: Boolean!): DefinitionVoteStatusOutputRow! togglePhraseToPhraseTrVoteStatus(phrase_to_phrase_translation_id: ID!, vote: Boolean!): PhraseToPhraseTranslationVoteStatusOutputRow! @@ -829,10 +835,10 @@ type PericopeTrVoteStatus { upvotes: Int! } -type PericopeTrVoteStatusAndBestTrListOutput { - best_translation_list: [PericopeTranslation!]! +type PericopeTrVoteStatusAndBestTrOutput { + best_translation: PericopeTranslation! error: ErrorType! - vote_status_list: [PericopeTrVoteStatus!]! + vote_status: PericopeTrVoteStatus! } type PericopeTranslation { @@ -1371,6 +1377,11 @@ type QuestionsOutput { questions: [Question]! } +type RecomendedPericopiesChangedAtDocumentId { + documentId: String! + error: ErrorType! +} + input RegisterInput { avatar: String! email: String! @@ -1528,12 +1539,14 @@ type Subscription { TranslationReport: TranslateAllWordsAndPhrasesByBotResult! ZipMapReport: ZipMapResult! answersAdded: AnswersOutput! + bestPericopeTrChanged: BestPericopeTrChanged! documentAdded: DocumentUploadOutput! pericopeDeleted: PericopeDeleteOutput! pericopeVoteStatusToggled: PericopeVoteStatusOutput! pericopiesAdded: PericopiesOutput! questionsAdded: QuestionsOutput! questionsOnWordRangeAdded: QuestionOnWordRangesOutput! + recommendedPericopiesChanged: RecomendedPericopiesChangedAtDocumentId! wordRangeTagVoteStatusToggled: WordRangeTagVoteStatusOutput! wordRangeTagWithVoteAdded: WordRangeTagWithVotesOutput! } diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs index 6ff974f9..2a9e49ec 100644 --- a/frontend/.eslintrc.cjs +++ b/frontend/.eslintrc.cjs @@ -11,7 +11,7 @@ module.exports = { 'plugin:prettier/recommended', ], plugins: ['react', 'react-hooks'], - ignorePatterns: ['src/generated/graphql.tsx'], + ignorePatterns: ['src/generated/graphql.tsx', 'generate-build-version.cjs'], parserOptions: { ecmaVersion: 2020, }, diff --git a/frontend/.gitignore b/frontend/.gitignore index 68eba805..071a04d7 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -32,3 +32,4 @@ dist/ /test-results/ /playwright-report/ /playwright/.cache/ +/public/meta.json diff --git a/frontend/generate-build-version.cjs b/frontend/generate-build-version.cjs new file mode 100644 index 00000000..5c634d38 --- /dev/null +++ b/frontend/generate-build-version.cjs @@ -0,0 +1,22 @@ +/* generate-build-version.js */ + +var fs = require('fs'); + +var packageJson = fs.readFileSync('../package.json', 'utf8'); + +var appVersion = JSON.parse(packageJson).version; + +var jsonData = { + version: appVersion, +}; + +var jsonContent = JSON.stringify(jsonData); + +fs.writeFile('./public/meta.json', jsonContent, 'utf8', function (err) { + if (err) { + console.log('An error occured while writing JSON Object to meta.json'); + return console.log(err); + } + + console.log('meta.json file has been saved with latest version number'); +}); diff --git a/frontend/graphql.schema.json b/frontend/graphql.schema.json index c59c36c5..79c6cca6 100644 --- a/frontend/graphql.schema.json +++ b/frontend/graphql.schema.json @@ -458,6 +458,57 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "BestPericopeTrChanged", + "description": null, + "fields": [ + { + "name": "error", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "ErrorType", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "newPericopeTr", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "PericopeTranslation", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "newVoteStatus", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "PericopeTrVoteStatus", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "SCALAR", "name": "Boolean", @@ -7405,7 +7456,7 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "PericopeTrVoteStatusAndBestTrListOutput", + "name": "PericopeTrVoteStatusAndBestTrOutput", "ofType": null } }, @@ -10253,28 +10304,20 @@ }, { "kind": "OBJECT", - "name": "PericopeTrVoteStatusAndBestTrListOutput", + "name": "PericopeTrVoteStatusAndBestTrOutput", "description": null, "fields": [ { - "name": "best_translation_list", + "name": "best_translation", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "PericopeTranslation", - "ofType": null - } - } + "kind": "OBJECT", + "name": "PericopeTranslation", + "ofType": null } }, "isDeprecated": false, @@ -10297,24 +10340,16 @@ "deprecationReason": null }, { - "name": "vote_status_list", + "name": "vote_status", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "PericopeTrVoteStatus", - "ofType": null - } - } + "kind": "OBJECT", + "name": "PericopeTrVoteStatus", + "ofType": null } }, "isDeprecated": false, @@ -18769,6 +18804,49 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "RecomendedPericopiesChangedAtDocumentId", + "description": null, + "fields": [ + { + "name": "documentId", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "error", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "ErrorType", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "INPUT_OBJECT", "name": "RegisterInput", @@ -20247,6 +20325,22 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "bestPericopeTrChanged", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "BestPericopeTrChanged", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "documentAdded", "description": null, @@ -20343,6 +20437,22 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "recommendedPericopiesChanged", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "RecomendedPericopiesChangedAtDocumentId", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "wordRangeTagVoteStatusToggled", "description": null, diff --git a/frontend/package.json b/frontend/package.json index a1cedb31..173d7059 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -5,10 +5,12 @@ "type": "module", "scripts": { "dev": "vite", - "build:test": "tsc && vite build --mode test", - "build:local": "tsc && vite build --mode local-dev", - "build:staging": "tsc && vite build --mode staging", - "build:prod": "tsc && vite build", + "generate-build-version": "node ./generate-build-version.cjs", + "prebuild": "npm run generate-build-version", + "build:test": "npm run generate-build-version && tsc && vite build --mode test", + "build:local": "npm run generate-build-version && tsc && vite build --mode local-dev", + "build:staging": "npm run generate-build-version && tsc && vite build --mode staging", + "build:prod": "npm run generate-build-version && tsc && vite build", "format": "prettier --write \"src/**/*.{ts,tsx,md,mdx,js,jsx}\"", "preview": "vite preview", "test.e2e": "cypress run", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 283e50ad..1a3502fc 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,3 +1,4 @@ +import { useEffect } from 'react'; import { Route } from 'react-router-dom'; import { IonApp, IonRouterOutlet, setupIonicReact } from '@ionic/react'; import { IonReactRouter } from '@ionic/react-router'; @@ -49,6 +50,8 @@ import { createUploadLink } from 'apollo-upload-client'; import { typePolicies } from './cacheTypePolicies'; import { createClient } from 'graphql-ws'; +import { useCacheBuster } from './hooks/useCacheBuster'; + console.info('Runninig in environment: ' + import.meta.env.MODE); const server_url = `${import.meta.env.VITE_APP_SERVER_URL}/graphql`; @@ -112,23 +115,35 @@ export const apollo_client = new ApolloClient({ (window as any).cacheApollo = apollo_client; const App: React.FC = () => { - return ( - - - - - - - - - - - - - - - - ); + const { loading, isLatestVersion, refreshCacheAndReload, latestVersion } = + useCacheBuster(); + + useEffect(() => { + if (!loading && !isLatestVersion) refreshCacheAndReload(latestVersion); + }, [loading, isLatestVersion, refreshCacheAndReload, latestVersion]); + + if (loading || !isLatestVersion) { + return null; + } else { + return ( + + + + + + + + + + + + + + + + ); + } }; export default App; +// test 1 diff --git a/frontend/src/components/pericope-translations/PericopeTranslationPage/PericopeTranslationsList.tsx b/frontend/src/components/pericope-translations/PericopeTranslationPage/PericopeTranslationsList.tsx index d31de16d..0e00d0c4 100644 --- a/frontend/src/components/pericope-translations/PericopeTranslationPage/PericopeTranslationsList.tsx +++ b/frontend/src/components/pericope-translations/PericopeTranslationPage/PericopeTranslationsList.tsx @@ -9,6 +9,7 @@ import { TextCard } from '../../common/TextCard'; import { useCallback, useEffect } from 'react'; import { useIonToast } from '@ionic/react'; import { useTogglePericopeTrVoteStatusMutation } from '../../../hooks/useTogglePericopeTrVoteStatusMutation'; +import { useBestPericopeTrChangedSubscription } from '../../../hooks/useSubscribeToRecomendedPericopies'; export type PericopeTranslationListProps = { translations: PericopeTranslationWithVotes[]; @@ -22,6 +23,8 @@ export function PericopeTranslationList({ const [toggleTrVoteStatus, { data: voteData, loading: voteLoading }] = useTogglePericopeTrVoteStatusMutation(); + useBestPericopeTrChangedSubscription(); + useEffect(() => { if (voteLoading) return; if ( diff --git a/frontend/src/components/pericope-translations/PericopiesTrListPage/PericopiesTrList.tsx b/frontend/src/components/pericope-translations/PericopiesTrListPage/PericopiesTrList.tsx index 5612c3f9..035b80de 100644 --- a/frontend/src/components/pericope-translations/PericopiesTrListPage/PericopiesTrList.tsx +++ b/frontend/src/components/pericope-translations/PericopiesTrListPage/PericopiesTrList.tsx @@ -9,11 +9,12 @@ import { } from '@ionic/react'; import { useTr } from '../../../hooks/useTr'; import { FilterKind } from '../../super-tool/SuperDocumentViewerPage/ToolBox'; -import { useGetPericopiesTrLazyQuery } from '../../../generated/graphql'; +import { useGetPericopiesTrQuery } from '../../../generated/graphql'; import { useAppContext } from '../../../hooks/useAppContext'; -import { useCallback, useEffect } from 'react'; +import { useCallback } from 'react'; import { langInfo2langInput } from '../../../../../utils'; import { PAGE_SIZE } from '../../../const/commonConst'; +import { useSubscribeToRecomendedPericopiesChangedSubscription } from '../../../hooks/useSubscribeToRecomendedPericopiesChanged'; export type PericopiesTrListProps = { documentId: string; @@ -28,56 +29,35 @@ export function PericopiesTrList({ }: PericopiesTrListProps) { const { tr } = useTr(); const [present] = useIonToast(); - const [getPericopiesTr, { data: pericopies, fetchMore, loading }] = - useGetPericopiesTrLazyQuery(); const { states: { global: { - langauges: { sourceLang, targetLang }, + langauges: { + documentPage: { source: sourceLang, target: targetLang }, + }, }, }, } = useAppContext(); - useEffect(() => { - if (!targetLang) { - present({ - message: tr('Target language is not defined'), - duration: 1500, - position: 'top', - color: 'danger', - }); - return; - } - if (!loading) { - getPericopiesTr({ - variables: { - documentId, - targetLang: langInfo2langInput(targetLang), - filter: stringFilter, - onlyNotTranslatedTo: - filterKind === FilterKind.NotTranslated && targetLang - ? langInfo2langInput(targetLang) - : null, - onlyTranslatedTo: - filterKind === FilterKind.Translated && targetLang - ? langInfo2langInput(targetLang) - : null, - first: PAGE_SIZE, - }, - }); - } - }, [ - getPericopiesTr, - targetLang, - loading, - sourceLang, - present, - tr, - documentId, - stringFilter, - filterKind, - ]); + const { data: pericopies, fetchMore } = useGetPericopiesTrQuery({ + variables: { + documentId, + targetLang: langInfo2langInput(targetLang || { lang: { tag: '' } }), + filter: stringFilter, + onlyNotTranslatedTo: + filterKind === FilterKind.NotTranslated && targetLang + ? langInfo2langInput(targetLang) + : null, + onlyTranslatedTo: + filterKind === FilterKind.Translated && targetLang + ? langInfo2langInput(targetLang) + : null, + first: PAGE_SIZE, + }, + }); + + useSubscribeToRecomendedPericopiesChangedSubscription(); const handleInfinite = useCallback( async (ev: IonInfiniteScrollCustomEvent) => { @@ -128,10 +108,7 @@ export function PericopiesTrList({ return ( <> -
- {loading && } -
- {pericopies && + {pericopies ? ( pericopies.getPericopiesTr.edges.map( (pericopeTr) => pericopeTr.node && ( @@ -150,7 +127,10 @@ export function PericopiesTrList({ }} /> ), - )} + ) + ) : ( +
{}
+ )}
diff --git a/frontend/src/components/pericope-translations/gql.graphql b/frontend/src/components/pericope-translations/gql.graphql index 2862141a..7d4062a6 100644 --- a/frontend/src/components/pericope-translations/gql.graphql +++ b/frontend/src/components/pericope-translations/gql.graphql @@ -134,11 +134,28 @@ mutation TogglePericopeTrVoteStatus( vote: $vote ) { error - vote_status_list { + vote_status { ...PericopeTrVoteStatusFragment } - best_translation_list { + best_translation { ...PericopeTranslationFragment } } -} \ No newline at end of file +} + +subscription SubscribeToRecomendedPericopiesChanged { + recommendedPericopiesChanged { + documentId + } +} + +subscription BestPericopeTrChanged { + bestPericopeTrChanged { + newPericopeTr { + ...PericopeTranslationFragment + } + newVoteStatus { + ...PericopeTrVoteStatusFragment + } + } +} diff --git a/frontend/src/components/super-tool/SuperDocumentViewer/SuperDocumentViewer.tsx b/frontend/src/components/super-tool/SuperDocumentViewer/SuperDocumentViewer.tsx index 60b8c18c..b062a2cf 100644 --- a/frontend/src/components/super-tool/SuperDocumentViewer/SuperDocumentViewer.tsx +++ b/frontend/src/components/super-tool/SuperDocumentViewer/SuperDocumentViewer.tsx @@ -43,4 +43,5 @@ export function SuperDocumentViewer({ /> ); } + return null; } diff --git a/frontend/src/components/super-tool/SuperDocumentViewerPage/SuperDocumentViewerPage.tsx b/frontend/src/components/super-tool/SuperDocumentViewerPage/SuperDocumentViewerPage.tsx index 01ae09ea..2b9532dd 100644 --- a/frontend/src/components/super-tool/SuperDocumentViewerPage/SuperDocumentViewerPage.tsx +++ b/frontend/src/components/super-tool/SuperDocumentViewerPage/SuperDocumentViewerPage.tsx @@ -23,6 +23,8 @@ import { NavArrowDown } from '../../common/icons/NavArrowDown'; import { NavArrowUp } from '../../common/icons/NavArrowUp'; import { SuperDocumentViewer } from '../SuperDocumentViewer/SuperDocumentViewer'; import { SuperPericopiesTranslator } from '../SuperPericopiesTranslator'; +import { useSubscribeToRecomendedPericopiesChangedSubscription } from '../../../hooks/useSubscribeToRecomendedPericopiesChanged'; +import { useBestPericopeTrChangedSubscription } from '../../../hooks/useSubscribeToRecomendedPericopies'; export function SuperDocumentViewerPage() { const { tr } = useTr(); @@ -55,7 +57,6 @@ export function SuperDocumentViewerPage() { document_id, }, }); - useIonViewDidEnter(() => { setPageStatus('shown'); }); @@ -64,6 +65,9 @@ export function SuperDocumentViewerPage() { setPageStatus('hidden'); }); + useSubscribeToRecomendedPericopiesChangedSubscription(); + useBestPericopeTrChangedSubscription(); + const handleToggleMode = useCallback(() => { setMode((mode) => { if (mode === 'view') { diff --git a/frontend/src/generated/graphql.tsx b/frontend/src/generated/graphql.tsx index a1e97735..708a459a 100644 --- a/frontend/src/generated/graphql.tsx +++ b/frontend/src/generated/graphql.tsx @@ -71,6 +71,13 @@ export type AvatarUpdateOutput = { user?: Maybe; }; +export type BestPericopeTrChanged = { + __typename?: 'BestPericopeTrChanged'; + error: ErrorType; + newPericopeTr?: Maybe; + newVoteStatus?: Maybe; +}; + export type BotTranslateDocumentInput = { botType: BotType; documentId: Scalars['String']['input']; @@ -778,7 +785,7 @@ export type Mutation = { threadUpsert: ThreadOutput; toggleFlagWithRef: FlagsOutput; toggleMapVoteStatus: MapVoteStatusOutputRow; - togglePericopeTrVoteStatus: PericopeTrVoteStatusAndBestTrListOutput; + togglePericopeTrVoteStatus: PericopeTrVoteStatusAndBestTrOutput; togglePericopeVoteStatus: PericopeVoteStatusOutput; togglePhraseDefinitionVoteStatus: DefinitionVoteStatusOutputRow; togglePhraseToPhraseTrVoteStatus: PhraseToPhraseTranslationVoteStatusOutputRow; @@ -1399,11 +1406,11 @@ export type PericopeTrVoteStatus = { upvotes: Scalars['Int']['output']; }; -export type PericopeTrVoteStatusAndBestTrListOutput = { - __typename?: 'PericopeTrVoteStatusAndBestTrListOutput'; - best_translation_list: Array; +export type PericopeTrVoteStatusAndBestTrOutput = { + __typename?: 'PericopeTrVoteStatusAndBestTrOutput'; + best_translation: PericopeTranslation; error: ErrorType; - vote_status_list: Array; + vote_status: PericopeTrVoteStatus; }; export type PericopeTranslation = { @@ -2496,6 +2503,12 @@ export type QuestionsOutput = { questions: Array>; }; +export type RecomendedPericopiesChangedAtDocumentId = { + __typename?: 'RecomendedPericopiesChangedAtDocumentId'; + documentId: Scalars['String']['output']; + error: ErrorType; +}; + export type RegisterInput = { avatar: Scalars['String']['input']; email: Scalars['String']['input']; @@ -2672,12 +2685,14 @@ export type Subscription = { TranslationReport: TranslateAllWordsAndPhrasesByBotResult; ZipMapReport: ZipMapResult; answersAdded: AnswersOutput; + bestPericopeTrChanged: BestPericopeTrChanged; documentAdded: DocumentUploadOutput; pericopeDeleted: PericopeDeleteOutput; pericopeVoteStatusToggled: PericopeVoteStatusOutput; pericopiesAdded: PericopiesOutput; questionsAdded: QuestionsOutput; questionsOnWordRangeAdded: QuestionOnWordRangesOutput; + recommendedPericopiesChanged: RecomendedPericopiesChangedAtDocumentId; wordRangeTagVoteStatusToggled: WordRangeTagVoteStatusOutput; wordRangeTagWithVoteAdded: WordRangeTagWithVotesOutput; }; @@ -3963,7 +3978,17 @@ export type TogglePericopeTrVoteStatusMutationVariables = Exact<{ }>; -export type TogglePericopeTrVoteStatusMutation = { __typename?: 'Mutation', togglePericopeTrVoteStatus: { __typename?: 'PericopeTrVoteStatusAndBestTrListOutput', error: ErrorType, vote_status_list: Array<{ __typename?: 'PericopeTrVoteStatus', pericope_translation_id: string, upvotes: number, downvotes: number }>, best_translation_list: Array<{ __typename?: 'PericopeTranslation', pericope_translation_id: string, pericope_id: string, translation: string, translation_description?: string | null, created_at: string, created_by_user: { __typename?: 'User', user_id: string, avatar: string, avatar_url?: string | null, is_bot: boolean }, language: { __typename?: 'LanguageOutput', language_code: string, dialect_code?: string | null, geo_code?: string | null } }> } }; +export type TogglePericopeTrVoteStatusMutation = { __typename?: 'Mutation', togglePericopeTrVoteStatus: { __typename?: 'PericopeTrVoteStatusAndBestTrOutput', error: ErrorType, vote_status: { __typename?: 'PericopeTrVoteStatus', pericope_translation_id: string, upvotes: number, downvotes: number }, best_translation: { __typename?: 'PericopeTranslation', pericope_translation_id: string, pericope_id: string, translation: string, translation_description?: string | null, created_at: string, created_by_user: { __typename?: 'User', user_id: string, avatar: string, avatar_url?: string | null, is_bot: boolean }, language: { __typename?: 'LanguageOutput', language_code: string, dialect_code?: string | null, geo_code?: string | null } } } }; + +export type SubscribeToRecomendedPericopiesChangedSubscriptionVariables = Exact<{ [key: string]: never; }>; + + +export type SubscribeToRecomendedPericopiesChangedSubscription = { __typename?: 'Subscription', recommendedPericopiesChanged: { __typename?: 'RecomendedPericopiesChangedAtDocumentId', documentId: string } }; + +export type BestPericopeTrChangedSubscriptionVariables = Exact<{ [key: string]: never; }>; + + +export type BestPericopeTrChangedSubscription = { __typename?: 'Subscription', bestPericopeTrChanged: { __typename?: 'BestPericopeTrChanged', newPericopeTr?: { __typename?: 'PericopeTranslation', pericope_translation_id: string, pericope_id: string, translation: string, translation_description?: string | null, created_at: string, created_by_user: { __typename?: 'User', user_id: string, avatar: string, avatar_url?: string | null, is_bot: boolean }, language: { __typename?: 'LanguageOutput', language_code: string, dialect_code?: string | null, geo_code?: string | null } } | null, newVoteStatus?: { __typename?: 'PericopeTrVoteStatus', pericope_translation_id: string, upvotes: number, downvotes: number } | null } }; export type PericopeFragmentFragment = { __typename?: 'Pericope', pericope_id: string, start_word: string }; @@ -8487,10 +8512,10 @@ export const TogglePericopeTrVoteStatusDocument = gql` vote: $vote ) { error - vote_status_list { + vote_status { ...PericopeTrVoteStatusFragment } - best_translation_list { + best_translation { ...PericopeTranslationFragment } } @@ -8524,6 +8549,70 @@ export function useTogglePericopeTrVoteStatusMutation(baseOptions?: Apollo.Mutat export type TogglePericopeTrVoteStatusMutationHookResult = ReturnType; export type TogglePericopeTrVoteStatusMutationResult = Apollo.MutationResult; export type TogglePericopeTrVoteStatusMutationOptions = Apollo.BaseMutationOptions; +export const SubscribeToRecomendedPericopiesChangedDocument = gql` + subscription SubscribeToRecomendedPericopiesChanged { + recommendedPericopiesChanged { + documentId + } +} + `; + +/** + * __useSubscribeToRecomendedPericopiesChangedSubscription__ + * + * To run a query within a React component, call `useSubscribeToRecomendedPericopiesChangedSubscription` and pass it any options that fit your needs. + * When your component renders, `useSubscribeToRecomendedPericopiesChangedSubscription` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useSubscribeToRecomendedPericopiesChangedSubscription({ + * variables: { + * }, + * }); + */ +export function useSubscribeToRecomendedPericopiesChangedSubscription(baseOptions?: Apollo.SubscriptionHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useSubscription(SubscribeToRecomendedPericopiesChangedDocument, options); + } +export type SubscribeToRecomendedPericopiesChangedSubscriptionHookResult = ReturnType; +export type SubscribeToRecomendedPericopiesChangedSubscriptionResult = Apollo.SubscriptionResult; +export const BestPericopeTrChangedDocument = gql` + subscription BestPericopeTrChanged { + bestPericopeTrChanged { + newPericopeTr { + ...PericopeTranslationFragment + } + newVoteStatus { + ...PericopeTrVoteStatusFragment + } + } +} + ${PericopeTranslationFragmentFragmentDoc} +${PericopeTrVoteStatusFragmentFragmentDoc}`; + +/** + * __useBestPericopeTrChangedSubscription__ + * + * To run a query within a React component, call `useBestPericopeTrChangedSubscription` and pass it any options that fit your needs. + * When your component renders, `useBestPericopeTrChangedSubscription` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useBestPericopeTrChangedSubscription({ + * variables: { + * }, + * }); + */ +export function useBestPericopeTrChangedSubscription(baseOptions?: Apollo.SubscriptionHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useSubscription(BestPericopeTrChangedDocument, options); + } +export type BestPericopeTrChangedSubscriptionHookResult = ReturnType; +export type BestPericopeTrChangedSubscriptionResult = Apollo.SubscriptionResult; export const GetPericopiesByDocumentIdDocument = gql` query GetPericopiesByDocumentId($document_id: ID!, $first: Int, $after: ID) { getPericopiesByDocumentId( @@ -11970,6 +12059,8 @@ export const namedOperations = { SubscribeToDataGenProgress: 'SubscribeToDataGenProgress', SubscribeToDocumentAdded: 'SubscribeToDocumentAdded', SubscribeToZipMap: 'SubscribeToZipMap', + SubscribeToRecomendedPericopiesChanged: 'SubscribeToRecomendedPericopiesChanged', + BestPericopeTrChanged: 'BestPericopeTrChanged', SubscribeToPericopiesAdded: 'SubscribeToPericopiesAdded', SubscribeToPericopieDeleted: 'SubscribeToPericopieDeleted', SubscribeToPericopeVoteStatusToggled: 'SubscribeToPericopeVoteStatusToggled', diff --git a/frontend/src/hooks/useCacheBuster.ts b/frontend/src/hooks/useCacheBuster.ts new file mode 100644 index 00000000..b843b3f7 --- /dev/null +++ b/frontend/src/hooks/useCacheBuster.ts @@ -0,0 +1,103 @@ +import { useEffect, useState, useCallback } from 'react'; + +import packageJson from '../../../package.json'; +const appVersion = packageJson.version; + +const semverGreaterThan = (versionA: string, versionB: string) => { + const versionsA = versionA.split(/\./g); + + const versionsB = versionB.split(/\./g); + while (versionsA.length || versionsB.length) { + const a = Number(versionsA.shift()); + + const b = Number(versionsB.shift()); + // eslint-disable-next-line no-continue + if (a === b) continue; + // eslint-disable-next-line no-restricted-globals + return a > b || isNaN(b); + } + return false; +}; + +export const useCacheBuster = () => { + const [state, setState] = useState<{ + loading: boolean; + isLatestVersion: boolean; + latestVersion: string; + }>({ + loading: true, + isLatestVersion: false, + latestVersion: '', + }); + + const refreshCacheAndReload = useCallback(async (version: string) => { + try { + if (caches) { + // Service worker cache should be cleared with caches.delete() + caches.keys().then(function (names) { + for (const name of names) caches.delete(name); + }); + } + localStorage.clear(); + localStorage.setItem('APP_VERSION', version); + + window.location.reload(); + } catch (err) { + console.error(err); + } + }, []); + + useEffect(() => { + fetch('/meta.json') + .then((response) => response.json()) + .then((meta) => { + const latestVersion = meta.version; + const currentVersion = appVersion; + const localStorageAppVersion = localStorage.getItem('APP_VERSION'); + + const shouldForceRefresh = semverGreaterThan( + latestVersion, + currentVersion, + ); + + let invalidPersistedData = false; + if ( + !localStorageAppVersion || + semverGreaterThan(latestVersion, localStorageAppVersion as string) + ) { + invalidPersistedData = true; + } + if (shouldForceRefresh || invalidPersistedData) { + if (shouldForceRefresh) + console.info( + 'info:::: ', + `We have a new version - ${latestVersion}. Should force refresh`, + ); + if (invalidPersistedData) + console.info( + 'info:::: ', + `You have invalid persisted data - ${latestVersion}. Should force refresh`, + ); + console.error( + `We have a new version - ${latestVersion}. Should force refresh`, + ); + setState({ loading: false, isLatestVersion: false, latestVersion }); + } else { + console.info( + 'info:::: ', + `You already have the latest version - ${latestVersion}. No cache refresh needed.`, + ); + console.error( + `You already have the latest version - ${latestVersion}. No cache refresh needed.`, + ); + setState({ loading: false, isLatestVersion: true, latestVersion }); + } + }); + }, []); + return { + loading: state.loading, + isLatestVersion: state.isLatestVersion, + latestVersion: state.latestVersion, + refreshCacheAndReload, + }; +}; diff --git a/frontend/src/hooks/useSubscribeToRecomendedPericopies.ts b/frontend/src/hooks/useSubscribeToRecomendedPericopies.ts new file mode 100644 index 00000000..84e156e7 --- /dev/null +++ b/frontend/src/hooks/useSubscribeToRecomendedPericopies.ts @@ -0,0 +1,21 @@ +import { updateCacheWithTogglePericopeTrVoteStatus } from '../cacheUpdators/togglePericopeTrVoteStatus'; +import { useBestPericopeTrChangedSubscription as useGenBestPericopeTrChangedSubscription } from '../generated/graphql'; + +export function useBestPericopeTrChangedSubscription() { + return useGenBestPericopeTrChangedSubscription({ + onData: ({ data, client }) => { + if ( + !data.data?.bestPericopeTrChanged.newPericopeTr || + !data.data.bestPericopeTrChanged.newVoteStatus + ) + return; + updateCacheWithTogglePericopeTrVoteStatus( + client.cache, + data.data.bestPericopeTrChanged.newVoteStatus, + data.data.bestPericopeTrChanged.newPericopeTr, + ); + client.cache; + console.log(data); + }, + }); +} diff --git a/frontend/src/hooks/useSubscribeToRecomendedPericopiesChanged.ts b/frontend/src/hooks/useSubscribeToRecomendedPericopiesChanged.ts new file mode 100644 index 00000000..e35d4ee5 --- /dev/null +++ b/frontend/src/hooks/useSubscribeToRecomendedPericopiesChanged.ts @@ -0,0 +1,15 @@ +import { + GetPericopiesTrDocument, + useSubscribeToRecomendedPericopiesChangedSubscription as useGenSubscribeToRecomendedPericopiesChangedSubscription, +} from '../generated/graphql'; + +export function useSubscribeToRecomendedPericopiesChangedSubscription() { + return useGenSubscribeToRecomendedPericopiesChangedSubscription({ + onData: ({ data, client }) => { + client.refetchQueries({ + include: [GetPericopiesTrDocument], + }); + console.log(data); + }, + }); +} diff --git a/frontend/src/hooks/useTogglePericopeTrVoteStatusMutation.ts b/frontend/src/hooks/useTogglePericopeTrVoteStatusMutation.ts index bd58a62e..e0e5d065 100644 --- a/frontend/src/hooks/useTogglePericopeTrVoteStatusMutation.ts +++ b/frontend/src/hooks/useTogglePericopeTrVoteStatusMutation.ts @@ -21,15 +21,12 @@ export function useTogglePericopeTrVoteStatusMutation() { if ( !errors && data && - data.togglePericopeTrVoteStatus.vote_status_list[0] && + data.togglePericopeTrVoteStatus.vote_status && data.togglePericopeTrVoteStatus.error === ErrorType.NoError ) { - // note: index [0] is because we are toggling single vote related to one definite pericope_translaion_id - // so we're expecting only single row. - const newVoteStatus = - data.togglePericopeTrVoteStatus.vote_status_list[0]; + const newVoteStatus = data.togglePericopeTrVoteStatus.vote_status; const newBestTranslation = - data.togglePericopeTrVoteStatus.best_translation_list[0]; + data.togglePericopeTrVoteStatus.best_translation; updateCacheWithTogglePericopeTrVoteStatus( cache, @@ -49,21 +46,3 @@ export function useTogglePericopeTrVoteStatusMutation() { }, }); } - -// export function useSubscribeToPericopeVoteStatusToggledSubscription() { -// return useGeneratedSubscribeToPericopeVoteStatusToggledSubscription({ -// onData({ client, data: result }) { -// const { data, error } = result; -// if ( -// !error && -// data && -// data.pericopeVoteStatusToggled.vote_status && -// data.pericopeVoteStatusToggled.error === ErrorType.NoError -// ) { -// const newVoteStatus = data.pericopeVoteStatusToggled.vote_status; - -// updateCacheWithTogglePericopeVoteStatus(client.cache, newVoteStatus); -// } -// }, -// }); -// } diff --git a/package-lock.json b/package-lock.json index eefb11cf..d55d25cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,8 @@ "": { "devDependencies": { "@playwright/test": "^1.40.0" - } + }, + "version": "0.1.0" }, "node_modules/@playwright/test": { "version": "1.40.0", @@ -67,5 +68,6 @@ "node": ">=16" } } - } + }, + "version": "0.1.0" } diff --git a/package.json b/package.json index 0a2a8832..8eceb916 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,5 @@ { + "version": "0.1.0", "devDependencies": { "@playwright/test": "^1.40.0" }