Skip to content

Commit

Permalink
fix: changed onChange event listening to one time and avoided stale s…
Browse files Browse the repository at this point in the history
…tate

feat: implemented replication filter and validation doc for couchdb
  • Loading branch information
akhilmhdh committed Sep 15, 2021
1 parent 35da460 commit 81c2efe
Show file tree
Hide file tree
Showing 24 changed files with 433 additions and 372 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Idea Hub is a place to share ideas and innovations, with feedbacks from other us
`git clone https://github.com/1-Platform/idea-hub.git && cd idea-hub`
2. Install Dependencies
`npm install`
3. Copy `.env.example` to `.env.local` and fill necessary fields

## Start SPA

Expand All @@ -32,11 +33,11 @@ run `npm run lint:fix`

## Load remote couchdb with design documents and default tag

run `npm run generate:couchdb-documents`: To save both design documents and default tags to couchdb
run `npm run migrate:all`: To save both design documents and default tags to couchdb

run `nom run generate:design-doc`: To save design documents to couchdb
run `npm run migrate:design-doc`: To save design documents to couchdb

run `nom run generate:default-tags`: To save default tags to couchdb
run `npm run migrate:default-tags`: To save default tags to couchdb

## 🤝 Contributors

Expand Down
362 changes: 171 additions & 191 deletions package-lock.json

Large diffs are not rendered by default.

18 changes: 10 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,13 @@
"@testing-library/user-event": "^13.1.9",
"@types/jest": "^26.0.23",
"@types/node": "^15.12.2",
"@types/pouchdb-browser": "^6.1.3",
"@types/react": "^17.0.11",
"@types/react-dom": "^17.0.7",
"dotenv": "^10.0.0",
"history": "^5.0.0",
"nanoid": "^3.1.23",
"node-sass": "^6.0.1",
"pouchdb": "^7.2.2",
"pouchdb-adapter-http": "^7.2.2",
"pouchdb-browser": "^7.2.2",
"pouchdb-debug": "^7.2.1",
"pouchdb-find": "^7.2.2",
"react": "^17.0.2",
Expand All @@ -45,9 +44,9 @@
"lint": "eslint --ext .ts,.tsx src/",
"lint:fix": "eslint --ext .ts,.tsx src/ --fix",
"prepare": "husky install",
"generate:design-doc": "ts-node -P scripts/tsconfig.json scripts/generate-couchdb-design-documents.ts",
"generate:default-tags": "ts-node -P scripts/tsconfig.json scripts/generate-couchdb-default-tags.ts",
"generate:couchdb-documents": "npm run generate:design-doc && npm run generate:default-tags"
"migrate:design-doc": "ts-node -P scripts/tsconfig.json scripts/migrate-couchdb-design-documents.ts",
"migrate:default-tags": "ts-node -P scripts/tsconfig.json scripts/migrate-couchdb-default-tags.ts",
"migrate:all": "npm run migrate:design-doc && npm run migrate:default-tags"
},
"lint-staged": {
"*.{ts,tsx}": "eslint --cache --fix"
Expand All @@ -71,7 +70,8 @@
]
},
"devDependencies": {
"@types/pouchdb": "^6.4.0",
"@types/dotenv-safe": "^8.1.2",
"@types/pouchdb-node": "^6.1.4",
"@types/react-test-renderer": "^17.0.1",
"@typescript-eslint/eslint-plugin": "^4.26.1",
"@typescript-eslint/parser": "^4.26.1",
Expand All @@ -82,8 +82,10 @@
"eslint-plugin-react-hooks": "^4.2.0",
"husky": "^6.0.0",
"lint-staged": "^11.0.0",
"pouchdb-node": "^7.2.2",
"prettier": "^2.3.1",
"react-test-renderer": "^17.0.2",
"ts-node": "^10.2.1"
"ts-node": "^10.2.1",
"dotenv-safe": "^8.2.0"
}
}
File renamed without changes.
File renamed without changes.
8 changes: 3 additions & 5 deletions scripts/remote-pouch-db-instance.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import PouchDB from 'pouchdb';
import PouchDB from 'pouchdb-node';
import PouchDBFind from 'pouchdb-find';
import pouchdbHTTPAdapter from 'pouchdb-adapter-http';
import dotenv from 'dotenv';
dotenv.config();
import dotenv from 'dotenv-safe';
dotenv.config({ path: '.env.local' });

import { POUCHDB_DB_URL } from '../src/pouchDB/config';

PouchDB.plugin(PouchDBFind);
PouchDB.plugin(pouchdbHTTPAdapter);

export const db = new PouchDB(POUCHDB_DB_URL, {
skip_setup: true,
Expand Down
5 changes: 5 additions & 0 deletions src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ a {
--pf-c-backdrop--ZIndex: 9999;
}

.pf-c-select__menu {
overflow: auto;
max-height: 200px;
}

.rounded {
border-radius: 8px;
}
Expand Down
40 changes: 23 additions & 17 deletions src/containers/CommentsContainer/CommentsContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { ReactNode, useRef, useCallback, useEffect, useState } from 'react';

import {
Avatar,
Button,
Bullseye,
Dropdown,
DropdownItem,
Expand All @@ -19,12 +18,13 @@ import {
EmptyState,
EmptyStateIcon,
EmptyStateBody,
DropdownToggle,
} from '@patternfly/react-core';
import { SortAmountDownIcon, CubesIcon } from '@patternfly/react-icons';
import { Controller, useForm } from 'react-hook-form';

import { CommentField } from 'components';
import { useInfiniteScroll, useToggle } from 'hooks';
import { useInfiniteScroll, useStateRef, useToggle } from 'hooks';
import { usePouchDB } from 'context';
import { CommentDoc, DesignDoc, GetList, IdeaDoc } from 'pouchDB/types';
import { onCommentChange } from './commentsContainer.helper';
Expand All @@ -45,7 +45,7 @@ export const CommentsContainer = ({ ideaDetails }: Props): JSX.Element => {
const { isOpen, handleToggle } = useToggle(false);
const [sortOrder, setSortOrder] = useState<0 | 1>(0);
const { control, handleSubmit, reset } = useForm<FormData>();
const [commentDoc, setCommentDoc] = useState<GetList<CommentDoc>>({
const [commentDoc, setCommentDoc, commentDocRef] = useStateRef<GetList<CommentDoc>>({
hasNextPage: false,
docs: [],
});
Expand Down Expand Up @@ -75,13 +75,7 @@ export const CommentsContainer = ({ ideaDetails }: Props): JSX.Element => {
ideaId,
},
})
.on('change', async function ({ doc }) {
// change.id contains the doc id, change.doc contains the doc
if (doc && doc?.type === 'comment') {
const newCommentList = await onCommentChange(doc, commentDoc.docs, comment);
setCommentDoc((comments) => ({ ...comments, docs: newCommentList }));
}
})
.on('change', handleCommentFeedChange)
.on('error', function (err) {
console.error(err);
window.OpNotification.warning({
Expand All @@ -90,7 +84,19 @@ export const CommentsContainer = ({ ideaDetails }: Props): JSX.Element => {
});
});
return () => dbChanges.cancel();
}, [comment, commentDoc.docs, ideaId, db]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ideaId]);

const handleCommentFeedChange = useCallback(
async ({ doc }: PouchDB.Core.ChangesResponseChange<IdeaDoc | CommentDoc>) => {
if (doc && doc?.type === 'comment') {
const newCommentList = await onCommentChange(doc, commentDocRef.current.docs, comment);
setCommentDoc((comments) => ({ ...comments, docs: newCommentList }));
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[commentDoc.docs]
);

useEffect(() => {
window.OpAuthHelper.onLogin(() => handleFetchComments(sortOrder));
Expand Down Expand Up @@ -121,6 +127,7 @@ export const CommentsContainer = ({ ideaDetails }: Props): JSX.Element => {
});
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[comment, ideaId]
);

Expand Down Expand Up @@ -204,15 +211,14 @@ export const CommentsContainer = ({ ideaDetails }: Props): JSX.Element => {
<Bullseye>
<Dropdown
toggle={
<Button
variant="link"
<DropdownToggle
className="pf-u-p-0 pf-u-color-400"
onClick={handleToggle}
icon={<SortAmountDownIcon />}
iconPosition="right"
onToggle={handleToggle}
toggleIndicator={SortAmountDownIcon}
isPlain
>
Sort by
</Button>
</DropdownToggle>
}
isOpen={isOpen}
onSelect={handleToggle}
Expand Down
25 changes: 21 additions & 4 deletions src/context/PouchDB/PouchDBContext.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { createContext, ReactNode, useContext, useEffect, useMemo, useRef } from 'react';

import PouchDB from 'pouchdb';
import PouchDB from 'pouchdb-browser';
import PouchDBFind from 'pouchdb-find';
import pouchdbDebug from 'pouchdb-debug';
import pouchdbHTTPAdapter from 'pouchdb-adapter-http';

import { pouchDBIndexCreator, POUCHDB_DB_NAME } from 'pouchDB/config';
import { pouchDBIndexCreator, POUCHDB_DB_NAME, POUCHDB_DB_URL } from 'pouchDB/config';
import { IdeaModel } from 'pouchDB/api/idea';
import { TagModel } from 'pouchDB/api/tag';
import { PouchDBConsumer } from './types';
import { VoteModel } from 'pouchDB/api/vote';
import { pouchDBDesignDocCreator } from 'pouchDB/design';
import { CommentModel } from 'pouchDB/api/comments';
import { DesignDoc } from 'pouchDB/types';

PouchDB.plugin(PouchDBFind);
PouchDB.plugin(pouchdbDebug);
PouchDB.plugin(pouchdbHTTPAdapter);
PouchDB.debug.enable('pouchdb:find');
const PouchDBContext = createContext<PouchDBConsumer | null>(null);

Expand All @@ -23,16 +26,30 @@ interface Props {
}

export const PouchDBProvider = ({ children }: Props): JSX.Element => {
const db = useRef(new PouchDB(POUCHDB_DB_NAME));
const db = useRef(new PouchDB(POUCHDB_DB_NAME, { auto_compaction: true }));
const remoteDb = useRef(
new PouchDB(POUCHDB_DB_URL, {
skip_setup: true,
auto_compaction: true,
fetch: function (url, opts) {
if (opts) {
(opts?.headers as any).set('Authorization', `Bearer ${window?.OpAuthHelper?.jwtToken}`);
opts.credentials = 'omit';
}
return PouchDB.fetch(url, opts);
},
} as PouchDB.Configuration.RemoteDatabaseConfiguration)
);
const idea = useRef(new IdeaModel(db.current));
const tag = useRef(new TagModel(db.current));
const vote = useRef(new VoteModel(db.current));
const comment = useRef(new CommentModel(db.current));
// to sync with couch database onMount
useEffect(() => {
db.current.sync(process.env.COUCH_DB || '', {
db.current.sync(remoteDb.current, {
retry: true,
live: true,
filter: DesignDoc.ReplicationFilter,
});
pouchDBIndexCreator(db.current);
pouchDBDesignDocCreator(db.current);
Expand Down
1 change: 1 addition & 0 deletions src/hooks/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export { useInfiniteScroll } from './useInfiniteScroll';
export { useFormSelect } from './useFormSelect';
export { useQuery } from './useQuery';
export { useDebounce } from './useDebounce';
export { useStateRef } from './useStateRef';
4 changes: 2 additions & 2 deletions src/hooks/useFormSelect/useFormSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ export const useFormSelect = <T extends FieldValues>(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const selections = useMemo(() => data.fields.map((field: any) => field.name), [data.fields]);

const onToggle = useCallback((): void => {
setSelectIsOpen((state) => !state);
const onToggle = useCallback((isExpanded?: boolean): void => {
setSelectIsOpen(typeof isExpanded === 'boolean' ? isExpanded : (state) => !state);
}, []);

/**
Expand Down
1 change: 1 addition & 0 deletions src/hooks/useStateRef/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { useStateRef } from './useStateRef';
15 changes: 15 additions & 0 deletions src/hooks/useStateRef/useStateRef.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useEffect, useRef, useState } from 'react';

export const useStateRef = <T extends unknown>(
initialValue: T
): [T, React.Dispatch<React.SetStateAction<T>>, React.MutableRefObject<T>] => {
const [value, setValue] = useState<T>(initialValue);

const ref = useRef<T>(value);

useEffect(() => {
ref.current = value;
}, [value]);

return [value, setValue, ref];
};
Loading

0 comments on commit 81c2efe

Please sign in to comment.