From 1dbbbb210ccb1bf8e5887c63a39ac128466928cc Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Fri, 15 Apr 2022 17:47:17 +0300 Subject: [PATCH 01/90] feat: built storycard --- package-lock.json | 216 +++++++++--------- src/Components/VotesCount/VotesCount.tsx | 11 + .../Posts/Components/PostCard/Header.tsx | 23 ++ .../Posts/Components/PostCard/PostCard.tsx | 19 ++ .../Components/PostCard/StoryCard.stories.tsx | 22 ++ .../Posts/Components/PostCard/StoryCard.tsx | 28 +++ .../Posts/Components/PostCard/index.tsx | 2 + src/features/Posts/index.tsx | 2 + src/features/Posts/types/index.ts | 36 +++ .../Components/Avatar/Avatar.stories.tsx | 21 ++ .../Profiles/Components/Avatar/Avatar.tsx | 15 ++ src/mocks/data.ts | 30 ++- src/utils/interfaces/misc.interfaces.ts | 5 +- tailwind.config.js | 1 + 14 files changed, 317 insertions(+), 114 deletions(-) create mode 100644 src/Components/VotesCount/VotesCount.tsx create mode 100644 src/features/Posts/Components/PostCard/Header.tsx create mode 100644 src/features/Posts/Components/PostCard/PostCard.tsx create mode 100644 src/features/Posts/Components/PostCard/StoryCard.stories.tsx create mode 100644 src/features/Posts/Components/PostCard/StoryCard.tsx create mode 100644 src/features/Posts/Components/PostCard/index.tsx create mode 100644 src/features/Posts/index.tsx create mode 100644 src/features/Posts/types/index.ts create mode 100644 src/features/Profiles/Components/Avatar/Avatar.stories.tsx create mode 100644 src/features/Profiles/Components/Avatar/Avatar.tsx diff --git a/package-lock.json b/package-lock.json index 78eb807..78075ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21025,9 +21025,9 @@ } }, "node_modules/is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", "dependencies": { "has": "^1.0.3" }, @@ -23970,9 +23970,9 @@ } }, "node_modules/lilconfig": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", - "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", + "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", "dev": true, "engines": { "node": ">=10" @@ -25681,9 +25681,9 @@ } }, "node_modules/nanoid": { - "version": "3.1.30", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", - "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.2.tgz", + "integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -52048,27 +52048,33 @@ } }, "node_modules/purgecss/node_modules/postcss": { - "version": "8.4.4", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.4.tgz", - "integrity": "sha512-joU6fBsN6EIer28Lj6GDFoC/5yOZzLCfn0zHAn/MYXI7aPt4m4hK5KC5ovEZXy+lnCjmYIbQWngvju2ddyEr8Q==", + "version": "8.4.12", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz", + "integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], "dependencies": { - "nanoid": "^3.1.30", + "nanoid": "^3.3.1", "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" + "source-map-js": "^1.0.2" }, "engines": { "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" } }, "node_modules/purgecss/node_modules/source-map-js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", - "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -56865,6 +56871,18 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/svg-parser": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", @@ -57144,13 +57162,16 @@ } }, "node_modules/tailwindcss/node_modules/color": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/color/-/color-4.1.0.tgz", - "integrity": "sha512-o2rkkxyLGgYoeUy1OodXpbPAQNmlNBrirQ8ODO8QutzDiDMNdezSOZLNnusQ6pUpCQJUsaJIo9DZJKqa2HgH7A==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", "dev": true, "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" } }, "node_modules/tailwindcss/node_modules/color-convert": { @@ -57172,9 +57193,9 @@ "dev": true }, "node_modules/tailwindcss/node_modules/fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", + "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", @@ -57206,38 +57227,13 @@ "node": ">=8" } }, - "node_modules/tailwindcss/node_modules/import-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", - "integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==", - "dev": true, - "dependencies": { - "import-from": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tailwindcss/node_modules/import-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", - "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/tailwindcss/node_modules/postcss-load-config": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.0.tgz", - "integrity": "sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", "dev": true, "dependencies": { - "import-cwd": "^3.0.0", - "lilconfig": "^2.0.3", + "lilconfig": "^2.0.5", "yaml": "^1.10.2" }, "engines": { @@ -57248,22 +57244,30 @@ "url": "https://opencollective.com/postcss/" }, "peerDependencies": { + "postcss": ">=8.0.9", "ts-node": ">=9.0.0" }, "peerDependenciesMeta": { + "postcss": { + "optional": true + }, "ts-node": { "optional": true } } }, "node_modules/tailwindcss/node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -77058,9 +77062,9 @@ } }, "is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", "requires": { "has": "^1.0.3" } @@ -79238,9 +79242,9 @@ } }, "lilconfig": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", - "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", + "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", "dev": true }, "lines-and-columns": { @@ -80595,9 +80599,9 @@ } }, "nanoid": { - "version": "3.1.30", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", - "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==" + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.2.tgz", + "integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==" }, "nanomatch": { "version": "1.2.13", @@ -100914,20 +100918,20 @@ "dev": true }, "postcss": { - "version": "8.4.4", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.4.tgz", - "integrity": "sha512-joU6fBsN6EIer28Lj6GDFoC/5yOZzLCfn0zHAn/MYXI7aPt4m4hK5KC5ovEZXy+lnCjmYIbQWngvju2ddyEr8Q==", + "version": "8.4.12", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz", + "integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==", "dev": true, "requires": { - "nanoid": "^3.1.30", + "nanoid": "^3.3.1", "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" + "source-map-js": "^1.0.2" } }, "source-map-js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", - "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true } } @@ -104687,6 +104691,12 @@ } } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, "svg-parser": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", @@ -104908,9 +104918,9 @@ } }, "color": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/color/-/color-4.1.0.tgz", - "integrity": "sha512-o2rkkxyLGgYoeUy1OodXpbPAQNmlNBrirQ8ODO8QutzDiDMNdezSOZLNnusQ6pUpCQJUsaJIo9DZJKqa2HgH7A==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", "dev": true, "requires": { "color-convert": "^2.0.1", @@ -104933,9 +104943,9 @@ "dev": true }, "fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", + "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", "dev": true, "requires": { "graceful-fs": "^4.2.0", @@ -104958,43 +104968,25 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "import-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", - "integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==", - "dev": true, - "requires": { - "import-from": "^3.0.0" - } - }, - "import-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", - "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - } - }, "postcss-load-config": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.0.tgz", - "integrity": "sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", "dev": true, "requires": { - "import-cwd": "^3.0.0", - "lilconfig": "^2.0.3", + "lilconfig": "^2.0.5", "yaml": "^1.10.2" } }, "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "supports-color": { diff --git a/src/Components/VotesCount/VotesCount.tsx b/src/Components/VotesCount/VotesCount.tsx new file mode 100644 index 0000000..f020fcd --- /dev/null +++ b/src/Components/VotesCount/VotesCount.tsx @@ -0,0 +1,11 @@ +import React from 'react' +import { MdLocalFireDepartment } from 'react-icons/md' + +export default function VotesCount({ count = 0 }: { count: number }) { + return ( + + + {count} + + ) +} diff --git a/src/features/Posts/Components/PostCard/Header.tsx b/src/features/Posts/Components/PostCard/Header.tsx new file mode 100644 index 0000000..f149061 --- /dev/null +++ b/src/features/Posts/Components/PostCard/Header.tsx @@ -0,0 +1,23 @@ +import React from 'react' +import Avatar from 'src/features/Profiles/Components/Avatar/Avatar'; + +interface Props { + name: string; + avatar: string; + date: string +} + +export default function Header(props: Props) { + return ( +
+ +
+

{props.name}

+

{props.date}

+
+

+ 3h ago +

+
+ ) +} diff --git a/src/features/Posts/Components/PostCard/PostCard.tsx b/src/features/Posts/Components/PostCard/PostCard.tsx new file mode 100644 index 0000000..aa91beb --- /dev/null +++ b/src/features/Posts/Components/PostCard/PostCard.tsx @@ -0,0 +1,19 @@ + +type Props = + | { + type: 'story' + } + | { + type: 'question' + } + | { + type: 'bounty' + } + +export default function PostCard(props: Props) { + if ('question' in props) { + } + return ( +
StoryCard
+ ) +} diff --git a/src/features/Posts/Components/PostCard/StoryCard.stories.tsx b/src/features/Posts/Components/PostCard/StoryCard.stories.tsx new file mode 100644 index 0000000..545ca97 --- /dev/null +++ b/src/features/Posts/Components/PostCard/StoryCard.stories.tsx @@ -0,0 +1,22 @@ +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { MOCK_DATA } from 'src/mocks/data'; + +import StoryCard from './StoryCard'; + +export default { + title: 'Posts/Components/StoryCard', + component: StoryCard, + argTypes: { + backgroundColor: { control: 'color' }, + }, +} as ComponentMeta; + + +const Template: ComponentStory = (args) =>
+ +export const Default = Template.bind({}); +Default.args = { + story: MOCK_DATA['posts'].stories[0] +} + + diff --git a/src/features/Posts/Components/PostCard/StoryCard.tsx b/src/features/Posts/Components/PostCard/StoryCard.tsx new file mode 100644 index 0000000..bac6b64 --- /dev/null +++ b/src/features/Posts/Components/PostCard/StoryCard.tsx @@ -0,0 +1,28 @@ +import VotesCount from "src/Components/VotesCount/VotesCount" +import { Story } from "src/features/Posts/types" +import Header from "./Header" +import { BiComment } from 'react-icons/bi' + +interface Props { + story: Story +} +export default function StoryCard({ story }: Props) { + return ( +
+ +
+
+

{story.title}

+

{story.excerpt}

+ +
+
+ +
+ {story.comments_count} Comments +
+
+
+
+ ) +} diff --git a/src/features/Posts/Components/PostCard/index.tsx b/src/features/Posts/Components/PostCard/index.tsx new file mode 100644 index 0000000..bcdab81 --- /dev/null +++ b/src/features/Posts/Components/PostCard/index.tsx @@ -0,0 +1,2 @@ + +export { } \ No newline at end of file diff --git a/src/features/Posts/index.tsx b/src/features/Posts/index.tsx new file mode 100644 index 0000000..bcdab81 --- /dev/null +++ b/src/features/Posts/index.tsx @@ -0,0 +1,2 @@ + +export { } \ No newline at end of file diff --git a/src/features/Posts/types/index.ts b/src/features/Posts/types/index.ts new file mode 100644 index 0000000..e18c8b8 --- /dev/null +++ b/src/features/Posts/types/index.ts @@ -0,0 +1,36 @@ +import { Tag } from "src/utils/interfaces" + +export type PostBase = { + id: number + title: string + date: string + author: { + id: number + name: string + image: string + } + excerpt: string + tags: Tag[] + votes_count: number +} + +export type Story = PostBase & { + type: 'story' + cover_image: string; + comments_count: number +} + +export type Bounty = PostBase & { + type: 'bounty' + cover_image: string; + reward_amount: number + deadline: string + applicants_count: number +} + +export type Question = PostBase & { + type: 'question' + answers_count: number +} + +export type Post = Story | Question | Bounty diff --git a/src/features/Profiles/Components/Avatar/Avatar.stories.tsx b/src/features/Profiles/Components/Avatar/Avatar.stories.tsx new file mode 100644 index 0000000..e8e9e0c --- /dev/null +++ b/src/features/Profiles/Components/Avatar/Avatar.stories.tsx @@ -0,0 +1,21 @@ +import { ComponentStory, ComponentMeta } from '@storybook/react'; + +import Avatar from './Avatar'; + +export default { + title: 'Profile/Components/Avatar', + component: Avatar, + argTypes: { + backgroundColor: { control: 'color' }, + }, +} as ComponentMeta; + + +const Template: ComponentStory = (args) => + +export const Default = Template.bind({}); +Default.args = { + src: 'https://i.pravatar.cc/300' +} + + diff --git a/src/features/Profiles/Components/Avatar/Avatar.tsx b/src/features/Profiles/Components/Avatar/Avatar.tsx new file mode 100644 index 0000000..f7530fb --- /dev/null +++ b/src/features/Profiles/Components/Avatar/Avatar.tsx @@ -0,0 +1,15 @@ + +interface Props { + src: string; + alt?: string; + width?: number; +} + +export default function Avatar({ src, alt, width = 40 }: Props) { + return ( + {alt + ) +} diff --git a/src/mocks/data.ts b/src/mocks/data.ts index 4dd4376..f32b49b 100644 --- a/src/mocks/data.ts +++ b/src/mocks/data.ts @@ -1,4 +1,5 @@ import ASSETS from "src/assets"; +import { Story } from "src/features/Posts/types"; import { Project, ProjectCategory } from "src/utils/interfaces"; let categories = [ @@ -557,6 +558,32 @@ let projects = [ } ] + +let posts = { + stories: [ + { + id: 1, + title: 'Digital Editor, Mars Review of Books', + cover_image: "https://picsum.photos/id/10/1660/1200", + comments_count: 31, + date: 'April 13', + votes_count: 120, + excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...', + type: "story", + tags: [ + { id: 1, title: "lnurl" }, + { id: 2, title: "webln" }, + { id: 3, title: "guide" }, + ], + author: { + id: 12, + name: "John Doe", + image: "https://i.pravatar.cc/300?img=3" + } + } + ] as Story[], +} + // Process Data // ------------ @@ -570,5 +597,6 @@ categories = categories.map(c => ({ ...c, apps_count: projects.reduce((acc, p) = export const MOCK_DATA = { projects: projects as Project[], - categories: categories as ProjectCategory[] + categories: categories as ProjectCategory[], + posts: posts } \ No newline at end of file diff --git a/src/utils/interfaces/misc.interfaces.ts b/src/utils/interfaces/misc.interfaces.ts index 0740f3e..d810cbb 100644 --- a/src/utils/interfaces/misc.interfaces.ts +++ b/src/utils/interfaces/misc.interfaces.ts @@ -1,4 +1,7 @@ - +export type Tag = { + id: number + title: string +} export type Image = string; \ No newline at end of file diff --git a/tailwind.config.js b/tailwind.config.js index 54d0aa9..593fd99 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,6 +1,7 @@ module.exports = { mode: "jit", purge: [ + "./src/features/**/*.{html,js,ts,tsx,jsx}", "./src/pages/**/*.{html,js,ts,tsx,jsx}", "./src/Components/**/*.{html,js,ts,tsx,jsx}", "./src/layouts/**/*.{html,js,ts,tsx,jsx}", From 9b7afbffcd48340626818e279cccdf00ff0d8f14 Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Sat, 16 Apr 2022 15:52:35 +0300 Subject: [PATCH 02/90] feat: built rest of post cards variations --- package-lock.json | 17 +- package.json | 1 + src/Components/Badge/Badge.tsx | 2 +- src/Components/Button/Button.tsx | 4 +- .../PostCard/BountyCard.stories.tsx | 22 + .../Posts/Components/PostCard/BountyCard.tsx | 47 ++ .../Posts/Components/PostCard/Header.tsx | 4 +- .../PostCard/QuestionCard.stories.tsx | 22 + .../Components/PostCard/QuestionCard.tsx | 62 ++ src/features/Posts/types/index.ts | 24 +- src/mocks/data.ts | 601 +----------------- src/mocks/data/posts.ts | 92 +++ src/mocks/data/projects.ts | 570 +++++++++++++++++ src/mocks/data/utils.ts | 25 + 14 files changed, 878 insertions(+), 615 deletions(-) create mode 100644 src/features/Posts/Components/PostCard/BountyCard.stories.tsx create mode 100644 src/features/Posts/Components/PostCard/BountyCard.tsx create mode 100644 src/features/Posts/Components/PostCard/QuestionCard.stories.tsx create mode 100644 src/features/Posts/Components/PostCard/QuestionCard.tsx create mode 100644 src/mocks/data/posts.ts create mode 100644 src/mocks/data/projects.ts create mode 100644 src/mocks/data/utils.ts diff --git a/package-lock.json b/package-lock.json index 78075ed..c8cb542 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "apollo-server": "^3.5.0", "apollo-server-lambda": "^3.5.0", "axios": "^0.24.0", + "dayjs": "^1.11.1", "env-cmd": "^10.1.0", "framer-motion": "^5.3.0", "graphql": "^16.0.1", @@ -15452,11 +15453,9 @@ "dev": true }, "node_modules/dayjs": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.0.tgz", - "integrity": "sha512-JLC809s6Y948/FuCZPm5IX8rRhQwOiyMb2TfVVQEixG7P8Lm/gt5S7yoQZmC8x1UehI9Pb7sksEt4xx14m+7Ug==", - "dev": true, - "peer": true + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.1.tgz", + "integrity": "sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA==" }, "node_modules/debounce": { "version": "1.2.1", @@ -72756,11 +72755,9 @@ "dev": true }, "dayjs": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.0.tgz", - "integrity": "sha512-JLC809s6Y948/FuCZPm5IX8rRhQwOiyMb2TfVVQEixG7P8Lm/gt5S7yoQZmC8x1UehI9Pb7sksEt4xx14m+7Ug==", - "dev": true, - "peer": true + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.1.tgz", + "integrity": "sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA==" }, "debounce": { "version": "1.2.1", diff --git a/package.json b/package.json index fbfd519..4f9f345 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "apollo-server": "^3.5.0", "apollo-server-lambda": "^3.5.0", "axios": "^0.24.0", + "dayjs": "^1.11.1", "env-cmd": "^10.1.0", "framer-motion": "^5.3.0", "graphql": "^16.0.1", diff --git a/src/Components/Badge/Badge.tsx b/src/Components/Badge/Badge.tsx index 9366519..3102562 100644 --- a/src/Components/Badge/Badge.tsx +++ b/src/Components/Badge/Badge.tsx @@ -66,7 +66,7 @@ export default function Badge( return ( wrapLink( - {children} + {children} {onRemove && } , href) diff --git a/src/Components/Button/Button.tsx b/src/Components/Button/Button.tsx index 31f737c..1c58cc8 100644 --- a/src/Components/Button/Button.tsx +++ b/src/Components/Button/Button.tsx @@ -4,7 +4,7 @@ import { UnionToObjectKeys } from 'src/utils/types/utils'; // import Loading from '../Loading/Loading'; interface Props { - color?: 'primary' | 'red' | 'white' | 'gray' | 'none', + color?: 'primary' | 'red' | 'white' | 'gray' | "black" | 'none', variant?: 'fill' | 'outline' size?: 'sm' | 'md' | 'lg' children: ReactNode; @@ -23,6 +23,7 @@ const btnStylesFill: UnionToObjectKeys = { primary: "bg-primary-500 border-0 hover:bg-primary-400 active:bg-primary-600 text-white", gray: 'bg-gray-100 hover:bg-gray-200 text-gray-900 active:bg-gray-300', white: 'text-gray-900 bg-gray-25 hover:bg-gray-50', + black: 'text-white bg-black hover:bg-gray-900', red: "bg-red-600 border-0 hover:bg-red-500 active:bg-red-700 text-white", } @@ -31,6 +32,7 @@ const btnStylesOutline: UnionToObjectKeys = { primary: "text-primary-600", gray: 'text-gray-700', white: 'text-gray-900', + black: 'text-black', red: "text-red-500", } diff --git a/src/features/Posts/Components/PostCard/BountyCard.stories.tsx b/src/features/Posts/Components/PostCard/BountyCard.stories.tsx new file mode 100644 index 0000000..446fb14 --- /dev/null +++ b/src/features/Posts/Components/PostCard/BountyCard.stories.tsx @@ -0,0 +1,22 @@ +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { MOCK_DATA } from 'src/mocks/data'; + +import BountyCard from './BountyCard'; + +export default { + title: 'Posts/Components/BountyCard', + component: BountyCard, + argTypes: { + backgroundColor: { control: 'color' }, + }, +} as ComponentMeta; + + +const Template: ComponentStory = (args) =>
+ +export const Default = Template.bind({}); +Default.args = { + bounty: MOCK_DATA['posts'].bounties[0] +} + + diff --git a/src/features/Posts/Components/PostCard/BountyCard.tsx b/src/features/Posts/Components/PostCard/BountyCard.tsx new file mode 100644 index 0000000..7ad7162 --- /dev/null +++ b/src/features/Posts/Components/PostCard/BountyCard.tsx @@ -0,0 +1,47 @@ +import VotesCount from "src/Components/VotesCount/VotesCount" +import { Bounty } from "src/features/Posts/types" +import Header from "./Header" +import { FiUsers } from "react-icons/fi" +import Badge from "src/Components/Badge/Badge" +import Button from "src/Components/Button/Button" + +interface Props { + bounty: Bounty +} +export default function BountyCard({ bounty }: Props) { + return ( +
+ +
+
+
+
+

{bounty.title}

+
+ Bounty + {bounty.reward_amount} sats +
+
+ +
+

{bounty.excerpt}

+ +
+ {bounty.tags.map(tag => + {tag.title} + )} +
+ +
+
+ +
+ {bounty.applicants_count} Applicants +
+
+
+
+ ) +} diff --git a/src/features/Posts/Components/PostCard/Header.tsx b/src/features/Posts/Components/PostCard/Header.tsx index f149061..5c6c7e7 100644 --- a/src/features/Posts/Components/PostCard/Header.tsx +++ b/src/features/Posts/Components/PostCard/Header.tsx @@ -1,5 +1,6 @@ import React from 'react' import Avatar from 'src/features/Profiles/Components/Avatar/Avatar'; +import dayjs from 'dayjs' interface Props { name: string; @@ -8,12 +9,13 @@ interface Props { } export default function Header(props: Props) { + return (

{props.name}

-

{props.date}

+

{dayjs(props.date).format('MMMM DD')}

3h ago diff --git a/src/features/Posts/Components/PostCard/QuestionCard.stories.tsx b/src/features/Posts/Components/PostCard/QuestionCard.stories.tsx new file mode 100644 index 0000000..356898d --- /dev/null +++ b/src/features/Posts/Components/PostCard/QuestionCard.stories.tsx @@ -0,0 +1,22 @@ +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { MOCK_DATA } from 'src/mocks/data'; + +import QuestionCard from './QuestionCard'; + +export default { + title: 'Posts/Components/QuestionCard', + component: QuestionCard, + argTypes: { + backgroundColor: { control: 'color' }, + }, +} as ComponentMeta; + + +const Template: ComponentStory = (args) =>

+ +export const Default = Template.bind({}); +Default.args = { + question: MOCK_DATA['posts'].questions[0] +} + + diff --git a/src/features/Posts/Components/PostCard/QuestionCard.tsx b/src/features/Posts/Components/PostCard/QuestionCard.tsx new file mode 100644 index 0000000..0359d01 --- /dev/null +++ b/src/features/Posts/Components/PostCard/QuestionCard.tsx @@ -0,0 +1,62 @@ +import VotesCount from "src/Components/VotesCount/VotesCount" +import { Question } from "src/features/Posts/types" +import Header from "./Header" +import { FiUsers } from "react-icons/fi" +import Badge from "src/Components/Badge/Badge" +import Avatar from "src/features/Profiles/Components/Avatar/Avatar" +import dayjs from "dayjs" +import { Link } from "react-router-dom" + +interface Props { + question: Question +} +export default function QuestionCard({ question }: Props) { + return ( +
+ {/* */} +
+
+
+

{question.title}

+
+

{question.excerpt}

+ +
+ + Help + + {question.tags.map(tag => + {tag.title} + )} +
+ +
+
+ +
+ {question.answers_count} Answers +
+
+ +
+ {question.comments.map(comment =>
+
+ +
+

{comment.author.name}

+

{dayjs(comment.date).format('MMMM DD')}

+
+
+

{comment.body}

+
)} + +
+ + See all {question.answers_count} comments + +
+
+
+
+ ) +} diff --git a/src/features/Posts/types/index.ts b/src/features/Posts/types/index.ts index e18c8b8..868b6f4 100644 --- a/src/features/Posts/types/index.ts +++ b/src/features/Posts/types/index.ts @@ -1,14 +1,20 @@ import { Tag } from "src/utils/interfaces" +export type User = { + id: number + name: string + image: string +} + +export type Author = User & { + join_date: string +} + export type PostBase = { id: number title: string date: string - author: { - id: number - name: string - image: string - } + author: Author excerpt: string tags: Tag[] votes_count: number @@ -31,6 +37,14 @@ export type Bounty = PostBase & { export type Question = PostBase & { type: 'question' answers_count: number + comments: PostComment[] +} + +export type PostComment = { + id: number; + author: Author + date: string + body: string } export type Post = Story | Question | Bounty diff --git a/src/mocks/data.ts b/src/mocks/data.ts index f32b49b..98dab99 100644 --- a/src/mocks/data.ts +++ b/src/mocks/data.ts @@ -1,602 +1,9 @@ -import ASSETS from "src/assets"; -import { Story } from "src/features/Posts/types"; import { Project, ProjectCategory } from "src/utils/interfaces"; - -let categories = [ - { - "title": "Shock the Web ⚡️", - "id": 11, - "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", - "icon": "⚡", - "votes_sum": 0 - }, - { - "title": "Finance", - "id": 1, - "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", - "icon": "💸", - "votes_sum": 452 - }, - { - "title": "Gaming", - "id": 4, - "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", - "icon": "🎮", - "votes_sum": 15 - }, - { - "title": "Media & News", - "id": 7, - "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", - "icon": "🚨", - "votes_sum": 250 - }, - { - "title": "Shopping", - "id": 8, - "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", - "icon": "🛒", - "votes_sum": 35 - }, - { - "title": "Misc / Other", - "id": 9, - "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", - "icon": "🎁", - "votes_sum": 345 - }, - { - "title": "Art & Collectibles", - "id": 3, - "cover_image": "https://s3-alpha-sig.figma.com/img/6edc/d1e4/8683ae2aa5c60526b5eaaf40a201a08a?Expires=1649030400&Signature=TAO9e3rlHC1TD3AKWOcxZr0t9YZW~q5AOj5deqXDFPqHvtbsTbaJXjKDo5LLp~H6V0OvbAmP6G2ab~9qrQitnJYogcpXO-mTLlpnUmKU1aA-Ipp5jQIfUvCMLQEGm4dJmgqoDINae3AJCj7dUIqnQaT79oHsUTy1jIPaVPcHj0dnm1Gj2WO06E-bX-wcJ~7yIuqZ6VXXbYPehfTpoEybmMPFuWP0b7wO-LklHT~CQ3k9Zeg4Gd1xM63p7kGLyVJng1Zwz5XuZ9Yasv~eQpz5W~L5TUx8afw1TgdiA4RigdSq6tM9wskbpPnyN~AODDUkkrrbDUtppfOTKAWmAlEXBQ__&Key-Pair-Id=APKAINTVSUGEWH5XD5UA", - "icon": "🎨", - "votes_sum": 11 - }, - { - "title": "Social", - "id": 2, - "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", - "icon": "🎭", - "votes_sum": 0 - }, - { - "title": "Analytics", - "id": 6, - "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", - "icon": "💹", - "votes_sum": 0 - }, - { - "title": "Wallet", - "id": 5, - "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", - "icon": "💳", - "votes_sum": 0 - }, - { - "title": "Exchange", - "id": 10, - "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", - "icon": "🔁", - "votes_sum": 0 - } -] - -let projects = [ - { - "id": 16, - "title": "Alby", - "description": "Alby is wallet for your browser to send and receive bitcoin over the Lightning Network and login to websites. It let's you connect your own Lightning wallet. ", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/alby_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/alby_thumbnail.png", - "screenshots": [], - "website": "https://getalby.com/", - "lightning_address": "hello@getalby.com", - "votes_count": 335, - "category": { - "id": 9, - "title": "Misc / Other" - } - }, - { - "id": 22, - "title": "Geyser Fund", - "description": "On Geyser fund you can explore live crowdfunding projects, fund them on Bitcoin’s Lightning Network, and keep track of the projects.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/geyser-fund_cover.png", - "thumbnail_image": "https://user-images.githubusercontent.com/36778205/157433567-4b1e41db-23d4-4a80-b48f-ee248ee87f1e.jpg", - "screenshots": [], - "website": "https://geyser.fund/", - "lightning_address": "divineorgan67@walletofsatoshi.com", - "votes_count": 232, - "category": { - "id": 1, - "title": "Finance" - } - }, - { - "id": 1, - "title": "Kollider", - "description": "The first real-time settled derivative exchange", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/kollider_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/kollider_thumbnail.png", - "screenshots": [ - "https://t18307877.p.clickup-attachments.com/t18307877/87f5f10f-f462-4ec7-a0e7-65ac43f39d97/Screenshot%202022-03-01%20at%2023.34.23.png?view=open", - "https://t18307877.p.clickup-attachments.com/t18307877/7a17965b-30d3-473a-85ee-f7a1698f44e4/Screenshot%202022-03-01%20at%2023.35.06.png?view=open", - "https://t18307877.p.clickup-attachments.com/t18307877/8f75cdbb-de05-49c5-8f3c-4fcb260a49bf/Screenshot%202022-03-01%20at%2023.36.19.png?view=open" - ], - "website": "https://kollider.xyz/", - "lightning_address": "johns@getalby.com", - "votes_count": 220, - "category": { - "id": 1, - "title": "Finance" - } - }, - { - "id": 20, - "title": "Lightning.Video", - "description": "Lightning.Video allows to paywall videos and receive payments for comments, subscriptions and tips.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-video_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-video_thumbnail.png", - "screenshots": [], - "website": "https://lightning.video/", - "lightning_address": "moritz@getalby.com", - "votes_count": 205, - "category": { - "id": 7, - "title": "Media & News" - } - }, - { - "id": 7, - "title": "Wavlake", - "description": "Wavlake directly connects artists and listeners on an open-source payment platform powered by Bitcoin & Lightning.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/wavlake_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/wavlake_thumbnail.png", - "screenshots": [], - "website": "https://www.wavlake.com/", - "lightning_address": "moritz@getalby.com", - "votes_count": 45, - "category": { - "id": 7, - "title": "Media & News" - } - }, - { - "id": 12, - "title": "Bitrefill", - "description": "Bitrefill lets you buy vouchers, refill your phone, pay your bills and purchase incoming capacity for your Lightning node.", - "cover_image": "http://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/bitrefill_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/bitrefill_thumbnail.png", - "screenshots": [], - "website": "https://www.bitrefill.com/buy", - "lightning_address": "moritz@getalby.com", - "votes_count": 25, - "category": { - "id": 8, - "title": "Shopping" - } - }, - { - "id": 3, - "title": "Sparkshot", - "description": " Sparkshot is an art hosting platform that requires users to reveal the art by purchasing pixels in groups of one or more. Each purchase reveals those pixels and more of the underlying art.\r\n\r\nOnce all pixels have been purchased the art is fully revealled and we unlock the ability for the art to be downloaded and made free to go and live a life of its own. The art's page will remain on Sparkshot with the comments and metadata provided by the patrons. ", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/sparkshot_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/sparkshot_thumbnail.png", - "screenshots": [], - "website": "https://sparkshot.io/", - "lightning_address": "johns@getalby.com", - "votes_count": 11, - "category": { - "id": 3, - "title": "Art & Collectibles" - } - }, - { - "id": 10, - "title": "Lightning Roulette", - "description": "Lightning Roulette is a website to win bitcoin by playing Roulette.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-roulette_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-roulette_thumbnail.png", - "screenshots": [], - "website": "https://lightning-roulette.com/", - "lightning_address": "moritz@getalby.com", - "votes_count": 10, - "category": { - "id": 4, - "title": "Gaming" - } - }, - { - "id": 15, - "title": "lnshort.it", - "description": "lnshort.it is a service to redirect URLs and generate QR codes using the Lightning Network for payments and logins.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lnshort-it_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lnshort-it_thumbnail.png", - "screenshots": [], - "website": "https://lnshort.it/", - "lightning_address": "moritz@getalby.com", - "votes_count": 10, - "category": { - "id": 9, - "title": "Misc / Other" - } - }, - { - "id": 17, - "title": "Lightning Gifts", - "description": "On Lightning Gifts you can create fee-less Bitcoin gift vouchers to share with friends, family, and your haters.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-gifts_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-gifts_thumbnail.png", - "screenshots": [], - "website": "https://lightning.gifts/", - "lightning_address": "moritz@getalby.com", - "votes_count": 10, - "category": { - "id": 8, - "title": "Shopping" - } - }, - { - "id": 5, - "title": "LN Blackjack", - "description": "LN Blackjack lets you play Blackjack and win bitcoin over the Lightning Network.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lnblackjack_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lnblackjack_thumbnail.png", - "screenshots": [], - "website": "https://www.lnblackjack.com/", - "lightning_address": "moritz@getalby.com", - "votes_count": 5, - "category": { - "id": 4, - "title": "Gaming" - } - }, - { - "id": 23, - "title": "Bolt Boosters", - "description": "I wanted to create a way to monetize any video instantly and for free. A creator is able to create a unique link tied to their LN address to share with friends & followers. The user is able to stream sats instantly and for free after signing in with their @getalby LN address. \r\n\r\nThe market potential for this type of app is endless!", - "cover_image": "https://dl.airtable.com/.attachmentThumbnails/27474095d5fea78afdf385c30ed3f761/6b6d831a", - "thumbnail_image": "https://dl.airtable.com/.attachmentThumbnails/27474095d5fea78afdf385c30ed3f761/6b6d831a", - "screenshots": [ - "https://dl.airtable.com/.attachmentThumbnails/dadd6fe367f993137972415dd3ba5b6d/46dde8e2", - "https://dl.airtable.com/.attachmentThumbnails/ad0410f4c8bf05073a8484d4eb7146ed/d0946f0a", - "https://dl.airtable.com/.attachmentThumbnails/815c6a76bd1aa7b07d2b92d47cbc4a78/b352fc1b" - ], - "website": "https://satsbuster.herokuapp.com/", - "lightning_address": "subirachs@getalby.com", - "votes_count": 0, - "category": { - "id": 11, - "title": "Shock the Web ⚡️" - } - }, - { - "id": 24, - "title": "Sat Streamer", - "description": "Interact with the audience of your livestream through Lightning donations.\r\n- Lightning Address compatible\r\n- Text-to-speech: comedy ensured by reading out the messages or questions from you audience.\r\n- Crowdsource gifs from your audience \r\n\r\nIf you want to test out the live application, please use the regtest server, do not make an account on the mainnet experimental lndhub instance.\r\n\r\nLive Youtube example: https://www.youtube.com/watch?v=zAY8od3Z_LA&t=6015s", - "cover_image": "", - "thumbnail_image": "https://dl.airtable.com/.attachmentThumbnails/fb4467e1e0a0a4baeaaed2a58cf9e2cd/e100876e", - "screenshots": [ - "https://dl.airtable.com/.attachmentThumbnails/bbb72c8861bc8152bb1400b0ca0e4c5a/742bd6f6" - ], - "website": "https://satstreamer.vercel.app", - "lightning_address": "kiwiidb@getalby.com", - "votes_count": 0, - "category": { - "id": 11, - "title": "Shock the Web ⚡️" - } - }, - { - "id": 25, - "title": "The Lightning tip gallery", - "description": "The Lightning tip gallery\r\nsend a stranger a tip. get your tip request listed here\r\n\r\nhttps://github.com/Zrce/tipwall-backend\r\nhttps://github.com/Zrce/tipwall-frontend", - "cover_image": "https://dl.airtable.com/.attachmentThumbnails/2529b036b046446c1502ee110598b5da/bbecacbc", - "thumbnail_image": "https://dl.airtable.com/.attachmentThumbnails/dbc9138739627cbe0598063c0d235f18/d7b0c9c2", - "screenshots": [ - "https://dl.airtable.com/.attachmentThumbnails/51d39bf8493a38cff3de85de6e6a47e0/9a1f5b74", - "https://dl.airtable.com/.attachmentThumbnails/eb55a5a85d21d6c2ddcfe0895baf413b/2e5971a3" - ], - "website": "https://github.com/Zrce/tipwall-frontend", - "lightning_address": "tobitcoin@getalby.com", - "votes_count": 0, - "category": { - "id": 11, - "title": "Shock the Web ⚡️" - } - }, - { - "id": 26, - "title": "Arion", - "description": "A fast, easy, bitcoin powered parking app that's on the user's side. Users can get on their way quicker, cities enforce parking easier, and local businesses benefit.", - "cover_image": "https://dl.airtable.com/.attachmentThumbnails/4a63e4bf9523de039fcca7bbb5d39b38/b799bb27", - "thumbnail_image": "https://dl.airtable.com/.attachmentThumbnails/4a63e4bf9523de039fcca7bbb5d39b38/b799bb27", - "screenshots": [ - "https://dl.airtable.com/.attachmentThumbnails/640706bbf4fe82f554e47313dcffdb03/fd421db7", - "https://dl.airtable.com/.attachmentThumbnails/ee696150c36ab7625582b768c4ee023f/7eba66f5", - "https://dl.airtable.com/.attachmentThumbnails/36d5e53432f94e8ba50649b5fc875b0f/7da5dc98", - "https://dl.airtable.com/.attachmentThumbnails/c56a91e4b77d51bd8ab283296e73bc7c/83c550f2", - "https://dl.airtable.com/.attachmentThumbnails/72b3e88b2bb67586f4616fbdc76574f7/ab159627", - "https://dl.airtable.com/.attachmentThumbnails/d2a02c77483cbe2679b3e35b78a216df/ca05ec1c", - "https://dl.airtable.com/.attachmentThumbnails/077493b1d9397bca8a3daa993e880529/6187ca63", - "https://dl.airtable.com/.attachmentThumbnails/ea1f5386080334b95965b09d33cdc03f/d47eda7f", - "https://dl.airtable.com/.attachmentThumbnails/9f22802092bb26522ea1c7ae889b82f4/ae0de49b" - ], - "website": "https://arionparking.tech/", - "lightning_address": "atlantabitdevs@getalby.com", - "votes_count": 0, - "category": { - "id": 11, - "title": "Shock the Web ⚡️" - } - }, - { - "id": 27, - "title": "⚡ Payment Widgets", - "description": "Payment widgets make integrating ⚡ payments into your website a breeze. \r\n\r\n1. Go to https://webln.twentyuno.net/widget\r\n2. Fill in the form\r\n3. Generate embed code\r\n4. Embed the code into your website and start receiving payments today\r\n\r\nThis is how that would look on your website:\r\nhttps://codepen.io/reneaaron/full/VwybrvO \r\n\r\nThe widget supports WebLN but also provides fallback options (QR, Invoice) where WebLN is not available.", - "cover_image": "", - "thumbnail_image": "https://dl.airtable.com/.attachmentThumbnails/34984c4a4e366373c3410887fab001ba/f1121463", - "screenshots": [ - "https://dl.airtable.com/.attachmentThumbnails/73b6da7fb9802bf8aa4bdd212e4b1cbe/ebc0a61a" - ], - "website": "https://webln.twentyuno.net/widget", - "lightning_address": "reneaaron@getalby.com", - "votes_count": 0, - "category": { - "id": 11, - "title": "Shock the Web ⚡️" - } - }, - { - "id": 28, - "title": "LNShop", - "description": "LNShop aims to provide a one-click, lightweight, e-commerce solution for the lightning network.\r\n\r\nWe built it from the ground up to be easy to setup as a static website that can allow free hosting and little to no maintenance.\r\n\r\nI supports easy setup where the client only needs to Create a spreadsheet of their inventory and provide a lighting address and have their shop up and running in as little as 15 minutes.\r\n\r\nhttps://www.figma.com/proto/6BWuYddHvFySbdikxll9tj/Ln-shop-Presentation?node-id=1010%3A2200&scaling=min-zoom&page-id=801%3A6671&starting-point-node-id=1009%3A1337\r\n\r\nhttps://www.loom.com/share/8b608dc58a6d489ab8f541641060111b", - "cover_image": "", - "thumbnail_image": "https://dl.airtable.com/.attachmentThumbnails/b98eae93eaca66e2e006eab594a4c8d8/3f981698", - "screenshots": [ - "https://dl.airtable.com/.attachmentThumbnails/a681f9f056ac0bc29ab39730d2db9bda/2279dcb8", - "https://dl.airtable.com/.attachmentThumbnails/bcbe86a0096e384a54900c0e04f89448/d6341045", - "https://dl.airtable.com/.attachmentThumbnails/e90632192df8d5b6d9dea9dc8cd80c51/e59c749a", - "https://dl.airtable.com/.attachmentThumbnails/bfffa80f1a76cfdfaaa29b5e44346f2b/57eccaf6", - "https://dl.airtable.com/.attachmentThumbnails/0e0881d4f0d3459cbbf270c760ca3e94/088f4023", - "https://dl.airtable.com/.attachmentThumbnails/f6ab4891cbe033fea641e34f2f05853f/1fb9d921" - ], - "website": "https://lnshop.github.io/lnshop/", - "lightning_address": "alivesession77@walletofsatoshi.com", - "votes_count": 0, - "category": { - "id": 11, - "title": "Shock the Web ⚡️" - } - }, - { - "id": 2, - "title": "LN Markets", - "description": "LN Markets is a new type of Bitcoin derivatives trading platform, one that can only be accessed via the Lightning Network, a payment protocol running on top of Bitcoin.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lnmarkets_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lnmarkets_thumbnail.png", - "screenshots": [], - "website": "https://lnmarkets.com/", - "lightning_address": "johns@getalby.com", - "votes_count": 0, - "category": { - "id": 1, - "title": "Finance" - } - }, - { - "id": 29, - "title": "Geyser Grants", - "description": "Geyser Grants makes it easy for anyone to contribute to a cause without having to look into every crowdfunding campaign. The Geyser Fund Board will search within and beyond Geyserfund campaigns to distribute them to the most relevant and impactful projects.\r\n\r\nhttps://www.loom.com/share/6442574f45344345abf0b5ae303b35a3", - "cover_image": "", - "thumbnail_image": "https://dl.airtable.com/.attachmentThumbnails/f62e158661995a11b6119e8ff4cc4ac2/fe0219e9", - "screenshots": [ - "https://dl.airtable.com/.attachmentThumbnails/3e2d4e49d8aa7d6fb62c5a278b7bff68/249829a6", - "https://dl.airtable.com/.attachmentThumbnails/7540606967a04f51637731c0c6eb29c0/1abf8a61", - "https://dl.airtable.com/.attachmentThumbnails/f7cfff3ea2d125ebfa3ce9a1ac49df00/d7253e98", - "https://dl.airtable.com/.attachmentThumbnails/39492c2dabe7ebc78d62617cfd41103d/ae42cc14", - "https://dl.airtable.com/.attachmentThumbnails/7e86771958c7c5949bdbaa54545b341c/a7dd3e02" - ], - "website": "https://geyser.fund", - "lightning_address": "divineorgan67@walletofsatoshi.com", - "votes_count": 0, - "category": { - "id": 11, - "title": "Shock the Web ⚡️" - } - }, - { - "id": 8, - "title": "LOFT", - "description": "LOFT allows you to trade investment products with bitcoin and uses the Lightning Network for a seamless user experience.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/loft-trade_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/loft-trade_thumbnail.png", - "screenshots": [], - "website": "https://loft.trade/", - "lightning_address": "moritz@getalby.com", - "votes_count": 0, - "category": { - "id": 1, - "title": "Finance" - } - }, - { - "id": 14, - "title": "Sats 4 Likes", - "description": "Sats 4 Likes allows you to provide rewards for various tasks such as Twitter likes and followers or app reviews.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/sats-4-likes-cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/sats-4-likes_thumbnail.png", - "screenshots": [], - "website": "https://kriptode.com/satsforlikes/index.html", - "lightning_address": "moritz@getalby.com", - "votes_count": 0, - "category": { - "id": 9, - "title": "Misc / Other" - } - }, - { - "id": 18, - "title": "Scarce City", - "description": "Scarce City is an auction marketplace for art. Bidders collateralize their bids with minimal fee lightning payments.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/scarce-city_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/scarce-city_thumbnail.png", - "screenshots": [], - "website": "https://scarce.city/", - "lightning_address": "moritz@getalby.com", - "votes_count": 0, - "category": { - "id": 3, - "title": "Art & Collectibles" - } - }, - { - "id": 11, - "title": "Stacker News", - "description": "Stacker News is a crowd-sourced news aggregator with a Reddit-style voting mechanism using bitcoin.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/stacker-news_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/stacker-news_thumbnail.png", - "screenshots": [], - "website": "https://stacker.news/", - "lightning_address": "moritz@getalby.com", - "votes_count": 0, - "category": { - "id": 7, - "title": "Media & News" - } - }, - { - "id": 21, - "title": "Starbackr", - "description": "Starbackr's plattform allows to post, follow, like, comment and support your favorite creators", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/starbackr_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/starbackr_thumbail.png", - "screenshots": [], - "website": "https://www.starbackr.com/", - "lightning_address": "moritz@geralby.com", - "votes_count": 0, - "category": { - "id": 7, - "title": "Media & News" - } - }, - { - "id": 4, - "title": "Amboss Space", - "description": "Amboss Space is a Lightning Network Explorer leveraging the Lightning Network for secure and seamless logins.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/amboss-space_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/amboss-space_thumbnail.png", - "screenshots": [], - "website": "https://amboss.space/", - "lightning_address": "moritz@getalby.com", - "votes_count": 0, - "category": { - "id": 6, - "title": "Analytics" - } - }, - { - "id": 19, - "title": "Y'alls ", - "description": "Visitors on Y'alls can read and write articles with Lightning Network micropayments.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/yalls_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/yalls_thumbnail.png", - "screenshots": [], - "website": "https://yalls.org/", - "lightning_address": "moritz@getalby.com", - "votes_count": 0, - "category": { - "id": 2, - "title": "Social" - } - }, - { - "id": 13, - "title": "Lightning Network Stores", - "description": "Lightning Network Stores provides a collection of stores and websites accepting Bitcoin payments over the Lightning Network.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-network-stores_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-network-stores_thumbnail.png", - "screenshots": [], - "website": "https://lightningnetworkstores.com/", - "lightning_address": "moritz@getalby.com", - "votes_count": 0, - "category": { - "id": 8, - "title": "Shopping" - } - }, - { - "id": 9, - "title": "Lightning Poker", - "description": "Lightning Poker is platform to play poker games with bitcoin over the Lightning Network.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-poker_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-poker_thumbnail.png", - "screenshots": [], - "website": "https://lightning-poker.com/", - "lightning_address": "moritz@getalby.com", - "votes_count": 0, - "category": { - "id": 4, - "title": "Gaming" - } - }, - { - "id": 6, - "title": "LNGames", - "description": "LNGames is platform with several provably fair simple games integrating payments over the Lightning Network.", - "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lngames_cover.png", - "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lngames_thumbnail.png", - "screenshots": [], - "website": "https://lngames.net/", - "lightning_address": "moritz@getalby.com", - "votes_count": 0, - "category": { - "id": 4, - "title": "Gaming" - } - } -] - - -let posts = { - stories: [ - { - id: 1, - title: 'Digital Editor, Mars Review of Books', - cover_image: "https://picsum.photos/id/10/1660/1200", - comments_count: 31, - date: 'April 13', - votes_count: 120, - excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...', - type: "story", - tags: [ - { id: 1, title: "lnurl" }, - { id: 2, title: "webln" }, - { id: 3, title: "guide" }, - ], - author: { - id: 12, - name: "John Doe", - image: "https://i.pravatar.cc/300?img=3" - } - } - ] as Story[], -} - -// Process Data -// ------------ - - -// 1- Add Typenames -categories = categories.map(c => ({ ...c, __typename: "Category" })) -projects = projects.map(p => ({ ...p, __typename: "Project" })) - -// 2- Computed Fields -categories = categories.map(c => ({ ...c, apps_count: projects.reduce((acc, p) => acc + (p.category.id === c.id ? 1 : 0), 0) })) +import { posts } from "./data/posts"; +import { categories, projects } from "./data/projects"; export const MOCK_DATA = { - projects: projects as Project[], - categories: categories as ProjectCategory[], + projects: projects, + categories: categories, posts: posts } \ No newline at end of file diff --git a/src/mocks/data/posts.ts b/src/mocks/data/posts.ts new file mode 100644 index 0000000..7d22ecf --- /dev/null +++ b/src/mocks/data/posts.ts @@ -0,0 +1,92 @@ + +import { Bounty, Question, Story } from "src/features/Posts/types"; +import { getAvatarImage, getCoverImage } from "./utils"; + +const getAuthor = () => ({ + id: 12, + name: "John Doe", + image: getAvatarImage() +}) + +const date = 'Mon Mar 14 2022 20:33:17 GMT+0200 (Eastern European Standard Time)' + +let posts = { + stories: [ + { + id: 1, + title: 'Digital Editor, Mars Review of Books', + cover_image: getCoverImage(), + comments_count: 31, + date, + votes_count: 120, + excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...', + type: "story", + tags: [ + { id: 1, title: "lnurl" }, + { id: 2, title: "webln" }, + { id: 3, title: "guide" }, + ], + author: getAuthor() + } + ] as Story[], + bounties: [ + { + type: "bounty", + id: 1, + title: 'Digital Editor, Mars Review of Books', + cover_image: getCoverImage(), + applicants_count: 31, + date, + votes_count: 120, + excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...', + tags: [ + { id: 1, title: "lnurl" }, + { id: 2, title: "webln" }, + { id: 3, title: "guide" }, + ], + author: getAuthor(), + deadline: "25 May", + reward_amount: 200_000, + } + ] as Bounty[], + questions: [ + { + type: "question", + id: 1, + title: 'Digital Editor, Mars Review of Books', + answers_count: 31, + date, + votes_count: 70, + excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...', + tags: [ + { id: 1, title: "lnurl" }, + { id: 2, title: "webln" }, + ], + author: getAuthor(), + comments: [ + { + id: 1, + author: getAuthor(), + date, + body: 'Naw, I’m 42 and know people who started in their 50’s, you got this!' + }, + { + id: 2, + author: getAuthor(), + date, + body: 'Naw, I’m 42 and know people who started in their 50’s, you got this!' + }, + ] + } + ] as Question[] +} + + +posts.bounties = posts.bounties.map(b => ({ ...b, __typename: "Bounty" })) +posts.questions = posts.questions.map(b => ({ ...b, __typename: "Question" })) +posts.stories = posts.stories.map(b => ({ ...b, __typename: "Story" })) + + +export { + posts, +} \ No newline at end of file diff --git a/src/mocks/data/projects.ts b/src/mocks/data/projects.ts new file mode 100644 index 0000000..9b928fa --- /dev/null +++ b/src/mocks/data/projects.ts @@ -0,0 +1,570 @@ +import { Project, ProjectCategory } from "src/utils/interfaces"; + + +let categories = [ + { + "title": "Shock the Web ⚡️", + "id": 11, + "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", + "icon": "⚡", + "votes_sum": 0 + }, + { + "title": "Finance", + "id": 1, + "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", + "icon": "💸", + "votes_sum": 452 + }, + { + "title": "Gaming", + "id": 4, + "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", + "icon": "🎮", + "votes_sum": 15 + }, + { + "title": "Media & News", + "id": 7, + "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", + "icon": "🚨", + "votes_sum": 250 + }, + { + "title": "Shopping", + "id": 8, + "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", + "icon": "🛒", + "votes_sum": 35 + }, + { + "title": "Misc / Other", + "id": 9, + "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", + "icon": "🎁", + "votes_sum": 345 + }, + { + "title": "Art & Collectibles", + "id": 3, + "cover_image": "https://s3-alpha-sig.figma.com/img/6edc/d1e4/8683ae2aa5c60526b5eaaf40a201a08a?Expires=1649030400&Signature=TAO9e3rlHC1TD3AKWOcxZr0t9YZW~q5AOj5deqXDFPqHvtbsTbaJXjKDo5LLp~H6V0OvbAmP6G2ab~9qrQitnJYogcpXO-mTLlpnUmKU1aA-Ipp5jQIfUvCMLQEGm4dJmgqoDINae3AJCj7dUIqnQaT79oHsUTy1jIPaVPcHj0dnm1Gj2WO06E-bX-wcJ~7yIuqZ6VXXbYPehfTpoEybmMPFuWP0b7wO-LklHT~CQ3k9Zeg4Gd1xM63p7kGLyVJng1Zwz5XuZ9Yasv~eQpz5W~L5TUx8afw1TgdiA4RigdSq6tM9wskbpPnyN~AODDUkkrrbDUtppfOTKAWmAlEXBQ__&Key-Pair-Id=APKAINTVSUGEWH5XD5UA", + "icon": "🎨", + "votes_sum": 11 + }, + { + "title": "Social", + "id": 2, + "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", + "icon": "🎭", + "votes_sum": 0 + }, + { + "title": "Analytics", + "id": 6, + "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", + "icon": "💹", + "votes_sum": 0 + }, + { + "title": "Wallet", + "id": 5, + "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", + "icon": "💳", + "votes_sum": 0 + }, + { + "title": "Exchange", + "id": 10, + "cover_image": "https://via.placeholder.com/1920x850.png?text=Category+Cover+Image", + "icon": "🔁", + "votes_sum": 0 + } +] + +let projects = [ + { + "id": 16, + "title": "Alby", + "description": "Alby is wallet for your browser to send and receive bitcoin over the Lightning Network and login to websites. It let's you connect your own Lightning wallet. ", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/alby_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/alby_thumbnail.png", + "screenshots": [], + "website": "https://getalby.com/", + "lightning_address": "hello@getalby.com", + "votes_count": 335, + "category": { + "id": 9, + "title": "Misc / Other" + } + }, + { + "id": 22, + "title": "Geyser Fund", + "description": "On Geyser fund you can explore live crowdfunding projects, fund them on Bitcoin’s Lightning Network, and keep track of the projects.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/geyser-fund_cover.png", + "thumbnail_image": "https://user-images.githubusercontent.com/36778205/157433567-4b1e41db-23d4-4a80-b48f-ee248ee87f1e.jpg", + "screenshots": [], + "website": "https://geyser.fund/", + "lightning_address": "divineorgan67@walletofsatoshi.com", + "votes_count": 232, + "category": { + "id": 1, + "title": "Finance" + } + }, + { + "id": 1, + "title": "Kollider", + "description": "The first real-time settled derivative exchange", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/kollider_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/kollider_thumbnail.png", + "screenshots": [ + "https://t18307877.p.clickup-attachments.com/t18307877/87f5f10f-f462-4ec7-a0e7-65ac43f39d97/Screenshot%202022-03-01%20at%2023.34.23.png?view=open", + "https://t18307877.p.clickup-attachments.com/t18307877/7a17965b-30d3-473a-85ee-f7a1698f44e4/Screenshot%202022-03-01%20at%2023.35.06.png?view=open", + "https://t18307877.p.clickup-attachments.com/t18307877/8f75cdbb-de05-49c5-8f3c-4fcb260a49bf/Screenshot%202022-03-01%20at%2023.36.19.png?view=open" + ], + "website": "https://kollider.xyz/", + "lightning_address": "johns@getalby.com", + "votes_count": 220, + "category": { + "id": 1, + "title": "Finance" + } + }, + { + "id": 20, + "title": "Lightning.Video", + "description": "Lightning.Video allows to paywall videos and receive payments for comments, subscriptions and tips.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-video_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-video_thumbnail.png", + "screenshots": [], + "website": "https://lightning.video/", + "lightning_address": "moritz@getalby.com", + "votes_count": 205, + "category": { + "id": 7, + "title": "Media & News" + } + }, + { + "id": 7, + "title": "Wavlake", + "description": "Wavlake directly connects artists and listeners on an open-source payment platform powered by Bitcoin & Lightning.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/wavlake_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/wavlake_thumbnail.png", + "screenshots": [], + "website": "https://www.wavlake.com/", + "lightning_address": "moritz@getalby.com", + "votes_count": 45, + "category": { + "id": 7, + "title": "Media & News" + } + }, + { + "id": 12, + "title": "Bitrefill", + "description": "Bitrefill lets you buy vouchers, refill your phone, pay your bills and purchase incoming capacity for your Lightning node.", + "cover_image": "http://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/bitrefill_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/bitrefill_thumbnail.png", + "screenshots": [], + "website": "https://www.bitrefill.com/buy", + "lightning_address": "moritz@getalby.com", + "votes_count": 25, + "category": { + "id": 8, + "title": "Shopping" + } + }, + { + "id": 3, + "title": "Sparkshot", + "description": " Sparkshot is an art hosting platform that requires users to reveal the art by purchasing pixels in groups of one or more. Each purchase reveals those pixels and more of the underlying art.\r\n\r\nOnce all pixels have been purchased the art is fully revealled and we unlock the ability for the art to be downloaded and made free to go and live a life of its own. The art's page will remain on Sparkshot with the comments and metadata provided by the patrons. ", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/sparkshot_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/sparkshot_thumbnail.png", + "screenshots": [], + "website": "https://sparkshot.io/", + "lightning_address": "johns@getalby.com", + "votes_count": 11, + "category": { + "id": 3, + "title": "Art & Collectibles" + } + }, + { + "id": 10, + "title": "Lightning Roulette", + "description": "Lightning Roulette is a website to win bitcoin by playing Roulette.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-roulette_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-roulette_thumbnail.png", + "screenshots": [], + "website": "https://lightning-roulette.com/", + "lightning_address": "moritz@getalby.com", + "votes_count": 10, + "category": { + "id": 4, + "title": "Gaming" + } + }, + { + "id": 15, + "title": "lnshort.it", + "description": "lnshort.it is a service to redirect URLs and generate QR codes using the Lightning Network for payments and logins.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lnshort-it_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lnshort-it_thumbnail.png", + "screenshots": [], + "website": "https://lnshort.it/", + "lightning_address": "moritz@getalby.com", + "votes_count": 10, + "category": { + "id": 9, + "title": "Misc / Other" + } + }, + { + "id": 17, + "title": "Lightning Gifts", + "description": "On Lightning Gifts you can create fee-less Bitcoin gift vouchers to share with friends, family, and your haters.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-gifts_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-gifts_thumbnail.png", + "screenshots": [], + "website": "https://lightning.gifts/", + "lightning_address": "moritz@getalby.com", + "votes_count": 10, + "category": { + "id": 8, + "title": "Shopping" + } + }, + { + "id": 5, + "title": "LN Blackjack", + "description": "LN Blackjack lets you play Blackjack and win bitcoin over the Lightning Network.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lnblackjack_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lnblackjack_thumbnail.png", + "screenshots": [], + "website": "https://www.lnblackjack.com/", + "lightning_address": "moritz@getalby.com", + "votes_count": 5, + "category": { + "id": 4, + "title": "Gaming" + } + }, + { + "id": 23, + "title": "Bolt Boosters", + "description": "I wanted to create a way to monetize any video instantly and for free. A creator is able to create a unique link tied to their LN address to share with friends & followers. The user is able to stream sats instantly and for free after signing in with their @getalby LN address. \r\n\r\nThe market potential for this type of app is endless!", + "cover_image": "https://dl.airtable.com/.attachmentThumbnails/27474095d5fea78afdf385c30ed3f761/6b6d831a", + "thumbnail_image": "https://dl.airtable.com/.attachmentThumbnails/27474095d5fea78afdf385c30ed3f761/6b6d831a", + "screenshots": [ + "https://dl.airtable.com/.attachmentThumbnails/dadd6fe367f993137972415dd3ba5b6d/46dde8e2", + "https://dl.airtable.com/.attachmentThumbnails/ad0410f4c8bf05073a8484d4eb7146ed/d0946f0a", + "https://dl.airtable.com/.attachmentThumbnails/815c6a76bd1aa7b07d2b92d47cbc4a78/b352fc1b" + ], + "website": "https://satsbuster.herokuapp.com/", + "lightning_address": "subirachs@getalby.com", + "votes_count": 0, + "category": { + "id": 11, + "title": "Shock the Web ⚡️" + } + }, + { + "id": 24, + "title": "Sat Streamer", + "description": "Interact with the audience of your livestream through Lightning donations.\r\n- Lightning Address compatible\r\n- Text-to-speech: comedy ensured by reading out the messages or questions from you audience.\r\n- Crowdsource gifs from your audience \r\n\r\nIf you want to test out the live application, please use the regtest server, do not make an account on the mainnet experimental lndhub instance.\r\n\r\nLive Youtube example: https://www.youtube.com/watch?v=zAY8od3Z_LA&t=6015s", + "cover_image": "", + "thumbnail_image": "https://dl.airtable.com/.attachmentThumbnails/fb4467e1e0a0a4baeaaed2a58cf9e2cd/e100876e", + "screenshots": [ + "https://dl.airtable.com/.attachmentThumbnails/bbb72c8861bc8152bb1400b0ca0e4c5a/742bd6f6" + ], + "website": "https://satstreamer.vercel.app", + "lightning_address": "kiwiidb@getalby.com", + "votes_count": 0, + "category": { + "id": 11, + "title": "Shock the Web ⚡️" + } + }, + { + "id": 25, + "title": "The Lightning tip gallery", + "description": "The Lightning tip gallery\r\nsend a stranger a tip. get your tip request listed here\r\n\r\nhttps://github.com/Zrce/tipwall-backend\r\nhttps://github.com/Zrce/tipwall-frontend", + "cover_image": "https://dl.airtable.com/.attachmentThumbnails/2529b036b046446c1502ee110598b5da/bbecacbc", + "thumbnail_image": "https://dl.airtable.com/.attachmentThumbnails/dbc9138739627cbe0598063c0d235f18/d7b0c9c2", + "screenshots": [ + "https://dl.airtable.com/.attachmentThumbnails/51d39bf8493a38cff3de85de6e6a47e0/9a1f5b74", + "https://dl.airtable.com/.attachmentThumbnails/eb55a5a85d21d6c2ddcfe0895baf413b/2e5971a3" + ], + "website": "https://github.com/Zrce/tipwall-frontend", + "lightning_address": "tobitcoin@getalby.com", + "votes_count": 0, + "category": { + "id": 11, + "title": "Shock the Web ⚡️" + } + }, + { + "id": 26, + "title": "Arion", + "description": "A fast, easy, bitcoin powered parking app that's on the user's side. Users can get on their way quicker, cities enforce parking easier, and local businesses benefit.", + "cover_image": "https://dl.airtable.com/.attachmentThumbnails/4a63e4bf9523de039fcca7bbb5d39b38/b799bb27", + "thumbnail_image": "https://dl.airtable.com/.attachmentThumbnails/4a63e4bf9523de039fcca7bbb5d39b38/b799bb27", + "screenshots": [ + "https://dl.airtable.com/.attachmentThumbnails/640706bbf4fe82f554e47313dcffdb03/fd421db7", + "https://dl.airtable.com/.attachmentThumbnails/ee696150c36ab7625582b768c4ee023f/7eba66f5", + "https://dl.airtable.com/.attachmentThumbnails/36d5e53432f94e8ba50649b5fc875b0f/7da5dc98", + "https://dl.airtable.com/.attachmentThumbnails/c56a91e4b77d51bd8ab283296e73bc7c/83c550f2", + "https://dl.airtable.com/.attachmentThumbnails/72b3e88b2bb67586f4616fbdc76574f7/ab159627", + "https://dl.airtable.com/.attachmentThumbnails/d2a02c77483cbe2679b3e35b78a216df/ca05ec1c", + "https://dl.airtable.com/.attachmentThumbnails/077493b1d9397bca8a3daa993e880529/6187ca63", + "https://dl.airtable.com/.attachmentThumbnails/ea1f5386080334b95965b09d33cdc03f/d47eda7f", + "https://dl.airtable.com/.attachmentThumbnails/9f22802092bb26522ea1c7ae889b82f4/ae0de49b" + ], + "website": "https://arionparking.tech/", + "lightning_address": "atlantabitdevs@getalby.com", + "votes_count": 0, + "category": { + "id": 11, + "title": "Shock the Web ⚡️" + } + }, + { + "id": 27, + "title": "⚡ Payment Widgets", + "description": "Payment widgets make integrating ⚡ payments into your website a breeze. \r\n\r\n1. Go to https://webln.twentyuno.net/widget\r\n2. Fill in the form\r\n3. Generate embed code\r\n4. Embed the code into your website and start receiving payments today\r\n\r\nThis is how that would look on your website:\r\nhttps://codepen.io/reneaaron/full/VwybrvO \r\n\r\nThe widget supports WebLN but also provides fallback options (QR, Invoice) where WebLN is not available.", + "cover_image": "", + "thumbnail_image": "https://dl.airtable.com/.attachmentThumbnails/34984c4a4e366373c3410887fab001ba/f1121463", + "screenshots": [ + "https://dl.airtable.com/.attachmentThumbnails/73b6da7fb9802bf8aa4bdd212e4b1cbe/ebc0a61a" + ], + "website": "https://webln.twentyuno.net/widget", + "lightning_address": "reneaaron@getalby.com", + "votes_count": 0, + "category": { + "id": 11, + "title": "Shock the Web ⚡️" + } + }, + { + "id": 28, + "title": "LNShop", + "description": "LNShop aims to provide a one-click, lightweight, e-commerce solution for the lightning network.\r\n\r\nWe built it from the ground up to be easy to setup as a static website that can allow free hosting and little to no maintenance.\r\n\r\nI supports easy setup where the client only needs to Create a spreadsheet of their inventory and provide a lighting address and have their shop up and running in as little as 15 minutes.\r\n\r\nhttps://www.figma.com/proto/6BWuYddHvFySbdikxll9tj/Ln-shop-Presentation?node-id=1010%3A2200&scaling=min-zoom&page-id=801%3A6671&starting-point-node-id=1009%3A1337\r\n\r\nhttps://www.loom.com/share/8b608dc58a6d489ab8f541641060111b", + "cover_image": "", + "thumbnail_image": "https://dl.airtable.com/.attachmentThumbnails/b98eae93eaca66e2e006eab594a4c8d8/3f981698", + "screenshots": [ + "https://dl.airtable.com/.attachmentThumbnails/a681f9f056ac0bc29ab39730d2db9bda/2279dcb8", + "https://dl.airtable.com/.attachmentThumbnails/bcbe86a0096e384a54900c0e04f89448/d6341045", + "https://dl.airtable.com/.attachmentThumbnails/e90632192df8d5b6d9dea9dc8cd80c51/e59c749a", + "https://dl.airtable.com/.attachmentThumbnails/bfffa80f1a76cfdfaaa29b5e44346f2b/57eccaf6", + "https://dl.airtable.com/.attachmentThumbnails/0e0881d4f0d3459cbbf270c760ca3e94/088f4023", + "https://dl.airtable.com/.attachmentThumbnails/f6ab4891cbe033fea641e34f2f05853f/1fb9d921" + ], + "website": "https://lnshop.github.io/lnshop/", + "lightning_address": "alivesession77@walletofsatoshi.com", + "votes_count": 0, + "category": { + "id": 11, + "title": "Shock the Web ⚡️" + } + }, + { + "id": 2, + "title": "LN Markets", + "description": "LN Markets is a new type of Bitcoin derivatives trading platform, one that can only be accessed via the Lightning Network, a payment protocol running on top of Bitcoin.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lnmarkets_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lnmarkets_thumbnail.png", + "screenshots": [], + "website": "https://lnmarkets.com/", + "lightning_address": "johns@getalby.com", + "votes_count": 0, + "category": { + "id": 1, + "title": "Finance" + } + }, + { + "id": 29, + "title": "Geyser Grants", + "description": "Geyser Grants makes it easy for anyone to contribute to a cause without having to look into every crowdfunding campaign. The Geyser Fund Board will search within and beyond Geyserfund campaigns to distribute them to the most relevant and impactful projects.\r\n\r\nhttps://www.loom.com/share/6442574f45344345abf0b5ae303b35a3", + "cover_image": "", + "thumbnail_image": "https://dl.airtable.com/.attachmentThumbnails/f62e158661995a11b6119e8ff4cc4ac2/fe0219e9", + "screenshots": [ + "https://dl.airtable.com/.attachmentThumbnails/3e2d4e49d8aa7d6fb62c5a278b7bff68/249829a6", + "https://dl.airtable.com/.attachmentThumbnails/7540606967a04f51637731c0c6eb29c0/1abf8a61", + "https://dl.airtable.com/.attachmentThumbnails/f7cfff3ea2d125ebfa3ce9a1ac49df00/d7253e98", + "https://dl.airtable.com/.attachmentThumbnails/39492c2dabe7ebc78d62617cfd41103d/ae42cc14", + "https://dl.airtable.com/.attachmentThumbnails/7e86771958c7c5949bdbaa54545b341c/a7dd3e02" + ], + "website": "https://geyser.fund", + "lightning_address": "divineorgan67@walletofsatoshi.com", + "votes_count": 0, + "category": { + "id": 11, + "title": "Shock the Web ⚡️" + } + }, + { + "id": 8, + "title": "LOFT", + "description": "LOFT allows you to trade investment products with bitcoin and uses the Lightning Network for a seamless user experience.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/loft-trade_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/loft-trade_thumbnail.png", + "screenshots": [], + "website": "https://loft.trade/", + "lightning_address": "moritz@getalby.com", + "votes_count": 0, + "category": { + "id": 1, + "title": "Finance" + } + }, + { + "id": 14, + "title": "Sats 4 Likes", + "description": "Sats 4 Likes allows you to provide rewards for various tasks such as Twitter likes and followers or app reviews.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/sats-4-likes-cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/sats-4-likes_thumbnail.png", + "screenshots": [], + "website": "https://kriptode.com/satsforlikes/index.html", + "lightning_address": "moritz@getalby.com", + "votes_count": 0, + "category": { + "id": 9, + "title": "Misc / Other" + } + }, + { + "id": 18, + "title": "Scarce City", + "description": "Scarce City is an auction marketplace for art. Bidders collateralize their bids with minimal fee lightning payments.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/scarce-city_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/scarce-city_thumbnail.png", + "screenshots": [], + "website": "https://scarce.city/", + "lightning_address": "moritz@getalby.com", + "votes_count": 0, + "category": { + "id": 3, + "title": "Art & Collectibles" + } + }, + { + "id": 11, + "title": "Stacker News", + "description": "Stacker News is a crowd-sourced news aggregator with a Reddit-style voting mechanism using bitcoin.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/stacker-news_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/stacker-news_thumbnail.png", + "screenshots": [], + "website": "https://stacker.news/", + "lightning_address": "moritz@getalby.com", + "votes_count": 0, + "category": { + "id": 7, + "title": "Media & News" + } + }, + { + "id": 21, + "title": "Starbackr", + "description": "Starbackr's plattform allows to post, follow, like, comment and support your favorite creators", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/starbackr_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/starbackr_thumbail.png", + "screenshots": [], + "website": "https://www.starbackr.com/", + "lightning_address": "moritz@geralby.com", + "votes_count": 0, + "category": { + "id": 7, + "title": "Media & News" + } + }, + { + "id": 4, + "title": "Amboss Space", + "description": "Amboss Space is a Lightning Network Explorer leveraging the Lightning Network for secure and seamless logins.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/amboss-space_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/amboss-space_thumbnail.png", + "screenshots": [], + "website": "https://amboss.space/", + "lightning_address": "moritz@getalby.com", + "votes_count": 0, + "category": { + "id": 6, + "title": "Analytics" + } + }, + { + "id": 19, + "title": "Y'alls ", + "description": "Visitors on Y'alls can read and write articles with Lightning Network micropayments.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/yalls_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/yalls_thumbnail.png", + "screenshots": [], + "website": "https://yalls.org/", + "lightning_address": "moritz@getalby.com", + "votes_count": 0, + "category": { + "id": 2, + "title": "Social" + } + }, + { + "id": 13, + "title": "Lightning Network Stores", + "description": "Lightning Network Stores provides a collection of stores and websites accepting Bitcoin payments over the Lightning Network.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-network-stores_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-network-stores_thumbnail.png", + "screenshots": [], + "website": "https://lightningnetworkstores.com/", + "lightning_address": "moritz@getalby.com", + "votes_count": 0, + "category": { + "id": 8, + "title": "Shopping" + } + }, + { + "id": 9, + "title": "Lightning Poker", + "description": "Lightning Poker is platform to play poker games with bitcoin over the Lightning Network.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-poker_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lightning-poker_thumbnail.png", + "screenshots": [], + "website": "https://lightning-poker.com/", + "lightning_address": "moritz@getalby.com", + "votes_count": 0, + "category": { + "id": 4, + "title": "Gaming" + } + }, + { + "id": 6, + "title": "LNGames", + "description": "LNGames is platform with several provably fair simple games integrating payments over the Lightning Network.", + "cover_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lngames_cover.png", + "thumbnail_image": "https://fra1.digitaloceanspaces.com/alby-storage/makers-bolt-fun/bolt.fund_thumbnails_covers/lngames_thumbnail.png", + "screenshots": [], + "website": "https://lngames.net/", + "lightning_address": "moritz@getalby.com", + "votes_count": 0, + "category": { + "id": 4, + "title": "Gaming" + } + } +] + + +categories = categories.map(c => ({ ...c, __typename: "Category" })) +projects = projects.map(p => ({ ...p, __typename: "Project" })) + +// 2- Computed Fields +categories = categories.map(c => ({ ...c, apps_count: projects.reduce((acc, p) => acc + (p.category.id === c.id ? 1 : 0), 0) })) + +export { + projects, + categories +} \ No newline at end of file diff --git a/src/mocks/data/utils.ts b/src/mocks/data/utils.ts new file mode 100644 index 0000000..bf38122 --- /dev/null +++ b/src/mocks/data/utils.ts @@ -0,0 +1,25 @@ + +let coverImgsCntr = -1; + +export function getCoverImage() { + const coverImgs = [ + 'https://picsum.photos/id/10/1660/1200', + 'https://picsum.photos/id/1000/1660/1200', + 'https://picsum.photos/id/1002/1660/1200', + 'https://picsum.photos/id/1008/1660/1200', + ] + + return coverImgs[(++coverImgsCntr) % coverImgs.length] +} +let avatarImgsCntr = -1; + +export function getAvatarImage() { + const avatarImgs = [ + 'https://i.pravatar.cc/150?img=1', + 'https://i.pravatar.cc/150?img=2', + 'https://i.pravatar.cc/150?img=3', + 'https://i.pravatar.cc/150?img=4', + ] + + return avatarImgs[(++avatarImgsCntr) % avatarImgs.length] +} \ No newline at end of file From ae5cd27b5a54ef690bc427ac9c4b439a43fa0d9e Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Sat, 16 Apr 2022 17:31:17 +0300 Subject: [PATCH 03/90] feat: added schema to backend --- codegen.yml | 2 +- functions/graphql/nexus-typegen.ts | 197 ++++++++++- functions/graphql/schema.graphql | 71 ++++ functions/graphql/types/index.js | 4 + functions/graphql/types/post.js | 144 ++++++++ functions/graphql/types/users.js | 17 + .../PostCard/BountyCard.stories.tsx | 2 +- .../Posts/Components/PostCard/BountyCard.tsx | 4 +- .../Posts/Components/PostCard/Header.tsx | 23 +- .../Posts/Components/PostCard/PostCard.tsx | 36 +- .../PostCard/QuestionCard.stories.tsx | 2 +- .../Components/PostCard/QuestionCard.tsx | 20 +- .../Components/PostCard/StoryCard.stories.tsx | 2 +- .../Posts/Components/PostCard/StoryCard.tsx | 4 +- .../PostsList/PostsList.stories.tsx | 22 ++ .../Posts/Components/PostsList/PostsList.tsx | 16 + .../Posts/pages/FeedPage/FeedPage.tsx | 1 + .../Posts/pages/FeedPage/feed.graphql | 75 +++++ .../pages/PostDetailsPage/PostDetailsPage.tsx | 1 + .../pages/PostDetailsPage/postDetails.graphql | 75 +++++ src/features/Posts/types/index.ts | 51 +-- src/features/Posts/types/posts.interface.ts | 50 +++ src/graphql/index.tsx | 308 ++++++++++++++++++ src/mocks/data.ts | 10 +- src/mocks/data/posts.ts | 15 +- src/mocks/data/projects.ts | 12 +- 26 files changed, 1044 insertions(+), 120 deletions(-) create mode 100644 functions/graphql/types/post.js create mode 100644 functions/graphql/types/users.js create mode 100644 src/features/Posts/Components/PostsList/PostsList.stories.tsx create mode 100644 src/features/Posts/Components/PostsList/PostsList.tsx create mode 100644 src/features/Posts/pages/FeedPage/FeedPage.tsx create mode 100644 src/features/Posts/pages/FeedPage/feed.graphql create mode 100644 src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx create mode 100644 src/features/Posts/pages/PostDetailsPage/postDetails.graphql create mode 100644 src/features/Posts/types/posts.interface.ts diff --git a/codegen.yml b/codegen.yml index 54e6960..28cd2dd 100644 --- a/codegen.yml +++ b/codegen.yml @@ -1,5 +1,5 @@ overwrite: true -schema: "https://makers-bolt-fun-preview.netlify.app/.netlify/functions/graphql" +schema: "http://localhost:8888/dev/graphql" documents: "./src/**/*.{ts,graphql}" generates: src/graphql/index.tsx: diff --git a/functions/graphql/nexus-typegen.ts b/functions/graphql/nexus-typegen.ts index f02f63a..64c5bb2 100644 --- a/functions/graphql/nexus-typegen.ts +++ b/functions/graphql/nexus-typegen.ts @@ -34,6 +34,19 @@ export interface NexusGenObjects { title: string; // String! url: string; // String! } + Bounty: { // root type + applicants_count: number; // Int! + author: NexusGenRootTypes['User']; // User! + cover_image: string; // String! + date: string; // String! + deadline: string; // String! + excerpt: string; // String! + id: number; // Int! + reward_amount: number; // Int! + tags: NexusGenRootTypes['Tag'][]; // [Tag!]! + title: string; // String! + votes_count: number; // Int! + } Category: { // root type cover_image?: string | null; // String icon?: string | null; // String @@ -47,6 +60,12 @@ export interface NexusGenObjects { minSendable?: number | null; // Int } Mutation: {}; + PostComment: { // root type + author: NexusGenRootTypes['User']; // User! + body: string; // String! + date: string; // String! + id: number; // Int! + } Project: { // root type cover_image: string; // String! description: string; // String! @@ -60,10 +79,40 @@ export interface NexusGenObjects { website: string; // String! } Query: {}; + Question: { // root type + answers_count: number; // Int! + author: NexusGenRootTypes['User']; // User! + comments: NexusGenRootTypes['PostComment'][]; // [PostComment!]! + cover_image: string; // String! + date: string; // String! + deadline: string; // String! + excerpt: string; // String! + id: number; // Int! + reward_amount: number; // Int! + tags: NexusGenRootTypes['Tag'][]; // [Tag!]! + title: string; // String! + votes_count: number; // Int! + } + Story: { // root type + author: NexusGenRootTypes['User']; // User! + comments_count: number; // Int! + cover_image: string; // String! + date: string; // String! + excerpt: string; // String! + id: number; // Int! + tags: NexusGenRootTypes['Tag'][]; // [Tag!]! + title: string; // String! + votes_count: number; // Int! + } Tag: { // root type id: number; // Int! title: string; // String! } + User: { // root type + id: number; // Int! + image: string; // String! + name: string; // String! + } Vote: { // root type amount_in_sat: number; // Int! id: number; // Int! @@ -74,12 +123,14 @@ export interface NexusGenObjects { } export interface NexusGenInterfaces { + PostBase: NexusGenRootTypes['Bounty'] | NexusGenRootTypes['Question'] | NexusGenRootTypes['Story']; } export interface NexusGenUnions { + Post: NexusGenRootTypes['Bounty'] | NexusGenRootTypes['Question'] | NexusGenRootTypes['Story']; } -export type NexusGenRootTypes = NexusGenObjects +export type NexusGenRootTypes = NexusGenInterfaces & NexusGenObjects & NexusGenUnions export type NexusGenAllTypes = NexusGenRootTypes & NexusGenScalars @@ -91,6 +142,20 @@ export interface NexusGenFieldTypes { title: string; // String! url: string; // String! } + Bounty: { // field return type + applicants_count: number; // Int! + author: NexusGenRootTypes['User']; // User! + cover_image: string; // String! + date: string; // String! + deadline: string; // String! + excerpt: string; // String! + id: number; // Int! + reward_amount: number; // Int! + tags: NexusGenRootTypes['Tag'][]; // [Tag!]! + title: string; // String! + type: string; // String! + votes_count: number; // Int! + } Category: { // field return type apps_count: number; // Int! cover_image: string | null; // String @@ -110,6 +175,12 @@ export interface NexusGenFieldTypes { confirmVote: NexusGenRootTypes['Vote']; // Vote! vote: NexusGenRootTypes['Vote']; // Vote! } + PostComment: { // field return type + author: NexusGenRootTypes['User']; // User! + body: string; // String! + date: string; // String! + id: number; // Int! + } Project: { // field return type awards: NexusGenRootTypes['Award'][]; // [Award!]! category: NexusGenRootTypes['Category']; // Category! @@ -129,18 +200,52 @@ export interface NexusGenFieldTypes { allCategories: NexusGenRootTypes['Category'][]; // [Category!]! allProjects: NexusGenRootTypes['Project'][]; // [Project!]! getCategory: NexusGenRootTypes['Category']; // Category! + getFeed: NexusGenRootTypes['Post'][]; // [Post!]! getLnurlDetailsForProject: NexusGenRootTypes['LnurlDetails']; // LnurlDetails! + getPostById: NexusGenRootTypes['Post']; // Post! getProject: NexusGenRootTypes['Project']; // Project! hottestProjects: NexusGenRootTypes['Project'][]; // [Project!]! newProjects: NexusGenRootTypes['Project'][]; // [Project!]! projectsByCategory: NexusGenRootTypes['Project'][]; // [Project!]! searchProjects: NexusGenRootTypes['Project'][]; // [Project!]! } + Question: { // field return type + answers_count: number; // Int! + author: NexusGenRootTypes['User']; // User! + comments: NexusGenRootTypes['PostComment'][]; // [PostComment!]! + cover_image: string; // String! + date: string; // String! + deadline: string; // String! + excerpt: string; // String! + id: number; // Int! + reward_amount: number; // Int! + tags: NexusGenRootTypes['Tag'][]; // [Tag!]! + title: string; // String! + type: string; // String! + votes_count: number; // Int! + } + Story: { // field return type + author: NexusGenRootTypes['User']; // User! + comments_count: number; // Int! + cover_image: string; // String! + date: string; // String! + excerpt: string; // String! + id: number; // Int! + tags: NexusGenRootTypes['Tag'][]; // [Tag!]! + title: string; // String! + type: string; // String! + votes_count: number; // Int! + } Tag: { // field return type id: number; // Int! project: NexusGenRootTypes['Project'][]; // [Project!]! title: string; // String! } + User: { // field return type + id: number; // Int! + image: string; // String! + name: string; // String! + } Vote: { // field return type amount_in_sat: number; // Int! id: number; // Int! @@ -149,6 +254,15 @@ export interface NexusGenFieldTypes { payment_request: string; // String! project: NexusGenRootTypes['Project']; // Project! } + PostBase: { // field return type + author: NexusGenRootTypes['User']; // User! + date: string; // String! + excerpt: string; // String! + id: number; // Int! + tags: NexusGenRootTypes['Tag'][]; // [Tag!]! + title: string; // String! + votes_count: number; // Int! + } } export interface NexusGenFieldTypeNames { @@ -159,6 +273,20 @@ export interface NexusGenFieldTypeNames { title: 'String' url: 'String' } + Bounty: { // field return type name + applicants_count: 'Int' + author: 'User' + cover_image: 'String' + date: 'String' + deadline: 'String' + excerpt: 'String' + id: 'Int' + reward_amount: 'Int' + tags: 'Tag' + title: 'String' + type: 'String' + votes_count: 'Int' + } Category: { // field return type name apps_count: 'Int' cover_image: 'String' @@ -178,6 +306,12 @@ export interface NexusGenFieldTypeNames { confirmVote: 'Vote' vote: 'Vote' } + PostComment: { // field return type name + author: 'User' + body: 'String' + date: 'String' + id: 'Int' + } Project: { // field return type name awards: 'Award' category: 'Category' @@ -197,18 +331,52 @@ export interface NexusGenFieldTypeNames { allCategories: 'Category' allProjects: 'Project' getCategory: 'Category' + getFeed: 'Post' getLnurlDetailsForProject: 'LnurlDetails' + getPostById: 'Post' getProject: 'Project' hottestProjects: 'Project' newProjects: 'Project' projectsByCategory: 'Project' searchProjects: 'Project' } + Question: { // field return type name + answers_count: 'Int' + author: 'User' + comments: 'PostComment' + cover_image: 'String' + date: 'String' + deadline: 'String' + excerpt: 'String' + id: 'Int' + reward_amount: 'Int' + tags: 'Tag' + title: 'String' + type: 'String' + votes_count: 'Int' + } + Story: { // field return type name + author: 'User' + comments_count: 'Int' + cover_image: 'String' + date: 'String' + excerpt: 'String' + id: 'Int' + tags: 'Tag' + title: 'String' + type: 'String' + votes_count: 'Int' + } Tag: { // field return type name id: 'Int' project: 'Project' title: 'String' } + User: { // field return type name + id: 'Int' + image: 'String' + name: 'String' + } Vote: { // field return type name amount_in_sat: 'Int' id: 'Int' @@ -217,6 +385,15 @@ export interface NexusGenFieldTypeNames { payment_request: 'String' project: 'Project' } + PostBase: { // field return type name + author: 'User' + date: 'String' + excerpt: 'String' + id: 'Int' + tags: 'Tag' + title: 'String' + votes_count: 'Int' + } } export interface NexusGenArgTypes { @@ -238,9 +415,16 @@ export interface NexusGenArgTypes { getCategory: { // args id: number; // Int! } + getFeed: { // args + skip?: number | null; // Int + take: number | null; // Int + } getLnurlDetailsForProject: { // args project_id: number; // Int! } + getPostById: { // args + id: number; // Int! + } getProject: { // args id: number; // Int! } @@ -266,9 +450,14 @@ export interface NexusGenArgTypes { } export interface NexusGenAbstractTypeMembers { + Post: "Bounty" | "Question" | "Story" + PostBase: "Bounty" | "Question" | "Story" } export interface NexusGenTypeInterfaces { + Bounty: "PostBase" + Question: "PostBase" + Story: "PostBase" } export type NexusGenObjectNames = keyof NexusGenObjects; @@ -277,15 +466,15 @@ export type NexusGenInputNames = never; export type NexusGenEnumNames = never; -export type NexusGenInterfaceNames = never; +export type NexusGenInterfaceNames = keyof NexusGenInterfaces; export type NexusGenScalarNames = keyof NexusGenScalars; -export type NexusGenUnionNames = never; +export type NexusGenUnionNames = keyof NexusGenUnions; export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never; -export type NexusGenAbstractsUsingStrategyResolveType = never; +export type NexusGenAbstractsUsingStrategyResolveType = "Post" | "PostBase"; export type NexusGenFeaturesConfig = { abstractTypeStrategies: { diff --git a/functions/graphql/schema.graphql b/functions/graphql/schema.graphql index 2b39787..71c6dde 100644 --- a/functions/graphql/schema.graphql +++ b/functions/graphql/schema.graphql @@ -10,6 +10,21 @@ type Award { url: String! } +type Bounty implements PostBase { + applicants_count: Int! + author: User! + cover_image: String! + date: String! + deadline: String! + excerpt: String! + id: Int! + reward_amount: Int! + tags: [Tag!]! + title: String! + type: String! + votes_count: Int! +} + type Category { apps_count: Int! cover_image: String @@ -32,6 +47,25 @@ type Mutation { vote(amount_in_sat: Int!, project_id: Int!): Vote! } +union Post = Bounty | Question | Story + +interface PostBase { + author: User! + date: String! + excerpt: String! + id: Int! + tags: [Tag!]! + title: String! + votes_count: Int! +} + +type PostComment { + author: User! + body: String! + date: String! + id: Int! +} + type Project { awards: [Award!]! category: Category! @@ -52,7 +86,9 @@ type Query { allCategories: [Category!]! allProjects(skip: Int = 0, take: Int = 50): [Project!]! getCategory(id: Int!): Category! + getFeed(skip: Int = 0, take: Int = 15): [Post!]! getLnurlDetailsForProject(project_id: Int!): LnurlDetails! + getPostById(id: Int!): Post! getProject(id: Int!): Project! hottestProjects(skip: Int = 0, take: Int = 50): [Project!]! newProjects(skip: Int = 0, take: Int = 50): [Project!]! @@ -60,12 +96,47 @@ type Query { searchProjects(search: String!, skip: Int = 0, take: Int = 50): [Project!]! } +type Question implements PostBase { + answers_count: Int! + author: User! + comments: [PostComment!]! + cover_image: String! + date: String! + deadline: String! + excerpt: String! + id: Int! + reward_amount: Int! + tags: [Tag!]! + title: String! + type: String! + votes_count: Int! +} + +type Story implements PostBase { + author: User! + comments_count: Int! + cover_image: String! + date: String! + excerpt: String! + id: Int! + tags: [Tag!]! + title: String! + type: String! + votes_count: Int! +} + type Tag { id: Int! project: [Project!]! title: String! } +type User { + id: Int! + image: String! + name: String! +} + type Vote { amount_in_sat: Int! id: Int! diff --git a/functions/graphql/types/index.js b/functions/graphql/types/index.js index 021a80a..6e9b03a 100644 --- a/functions/graphql/types/index.js +++ b/functions/graphql/types/index.js @@ -1,9 +1,13 @@ const category = require('./category') const project = require('./project') const vote = require('./vote') +const post = require('./post') +const users = require('./users') module.exports = { ...category, ...project, ...vote, + ...post, + ...users } \ No newline at end of file diff --git a/functions/graphql/types/post.js b/functions/graphql/types/post.js new file mode 100644 index 0000000..b2e513c --- /dev/null +++ b/functions/graphql/types/post.js @@ -0,0 +1,144 @@ +const { + intArg, + objectType, + stringArg, + extendType, + nonNull, + interfaceType, + unionType, +} = require('nexus'); +const { paginationArgs } = require('./helpers'); + + + + +const PostBase = interfaceType({ + name: 'PostBase', + resolveType(post) { + return post.type + }, + definition(t) { + t.nonNull.int('id'); + t.nonNull.string('title'); + t.nonNull.string('date'); + t.nonNull.field('author', { + type: "User" + }); + t.nonNull.string('excerpt'); + t.nonNull.list.nonNull.field('tags', { + type: "Tag" + }); + t.nonNull.int('votes_count'); + }, +}) + +const Story = objectType({ + name: 'Story', + definition(t) { + t.implements('PostBase'); + t.nonNull.string('type', { + resolve: () => 'story' + }); + t.nonNull.string('cover_image'); + t.nonNull.int('comments_count'); + }, +}) + +const Bounty = objectType({ + name: 'Bounty', + definition(t) { + t.implements('PostBase'); + t.nonNull.string('type', { + resolve: () => 'bounty' + }); + t.nonNull.string('cover_image'); + t.nonNull.string('deadline'); + t.nonNull.int('reward_amount'); + t.nonNull.int('applicants_count'); + }, +}) + +const Question = objectType({ + name: 'Question', + definition(t) { + t.implements('PostBase'); + t.nonNull.string('type', { + resolve: () => 'question' + }); + t.nonNull.string('cover_image'); + t.nonNull.string('deadline'); + t.nonNull.int('reward_amount'); + t.nonNull.int('answers_count'); + t.nonNull.list.nonNull.field('comments', { + type: "PostComment" + }) + }, +}) + +const PostComment = objectType({ + name: 'PostComment', + definition(t) { + t.nonNull.int('id'); + t.nonNull.string('date'); + t.nonNull.string('body'); + t.nonNull.field('author', { + type: "User" + }); + } +}) + +const Post = unionType({ + name: 'Post', + definition(t) { + t.members('Story', 'Bounty', 'Question') + }, + resolveType: (item) => item.type, +}) + + + +const getFeed = extendType({ + type: "Query", + definition(t) { + t.nonNull.list.nonNull.field('getFeed', { + type: "Post", + args: { + ...paginationArgs({ take: 15 }) + }, + resolve(_, { take, skip }) { + return [] + } + }) + } +}) + +const getPostById = extendType({ + type: "Query", + definition(t) { + t.nonNull.field('getPostById', { + type: "Post", + args: { + id: nonNull(intArg()) + }, + resolve(_, { id }) { + return {} + } + }) + } +}) + + + + +module.exports = { + // Types + PostBase, + Bounty, + Story, + Question, + PostComment, + Post, + // Queries + getFeed, + getPostById +} \ No newline at end of file diff --git a/functions/graphql/types/users.js b/functions/graphql/types/users.js new file mode 100644 index 0000000..d6bd504 --- /dev/null +++ b/functions/graphql/types/users.js @@ -0,0 +1,17 @@ +const { objectType } = require("nexus"); + +const User = objectType({ + name: 'User', + definition(t) { + t.nonNull.int('id'); + t.nonNull.string('name'); + t.nonNull.string('image'); + + } +}) + + +module.exports = { + // Types + User +} \ No newline at end of file diff --git a/src/features/Posts/Components/PostCard/BountyCard.stories.tsx b/src/features/Posts/Components/PostCard/BountyCard.stories.tsx index 446fb14..dce5f37 100644 --- a/src/features/Posts/Components/PostCard/BountyCard.stories.tsx +++ b/src/features/Posts/Components/PostCard/BountyCard.stories.tsx @@ -12,7 +12,7 @@ export default { } as ComponentMeta; -const Template: ComponentStory = (args) =>
+const Template: ComponentStory = (args) =>
export const Default = Template.bind({}); Default.args = { diff --git a/src/features/Posts/Components/PostCard/BountyCard.tsx b/src/features/Posts/Components/PostCard/BountyCard.tsx index 7ad7162..7db5dad 100644 --- a/src/features/Posts/Components/PostCard/BountyCard.tsx +++ b/src/features/Posts/Components/PostCard/BountyCard.tsx @@ -13,7 +13,7 @@ export default function BountyCard({ bounty }: Props) {
-
+

{bounty.title}

@@ -26,7 +26,7 @@ export default function BountyCard({ bounty }: Props) { Apply
-

{bounty.excerpt}

+

{bounty.excerpt}

{bounty.tags.map(tag => diff --git a/src/features/Posts/Components/PostCard/Header.tsx b/src/features/Posts/Components/PostCard/Header.tsx index 5c6c7e7..d8e124e 100644 --- a/src/features/Posts/Components/PostCard/Header.tsx +++ b/src/features/Posts/Components/PostCard/Header.tsx @@ -1,24 +1,27 @@ -import React from 'react' import Avatar from 'src/features/Profiles/Components/Avatar/Avatar'; import dayjs from 'dayjs' interface Props { - name: string; - avatar: string; - date: string + author: { + id: number, + name: string, + image: string + } + date: string; + size?: 'sm' | 'md' } -export default function Header(props: Props) { +export default function Header({ size = 'md', ...props }: Props) { return (
- +
-

{props.name}

-

{dayjs(props.date).format('MMMM DD')}

+

{props.author.name}

+

{dayjs(props.date).format('MMMM DD')}

-

- 3h ago +

+ {dayjs().diff(props.date, 'hour') < 24 ? `${dayjs().diff(props.date, 'hour')}h ago` : undefined}

) diff --git a/src/features/Posts/Components/PostCard/PostCard.tsx b/src/features/Posts/Components/PostCard/PostCard.tsx index aa91beb..740a8d6 100644 --- a/src/features/Posts/Components/PostCard/PostCard.tsx +++ b/src/features/Posts/Components/PostCard/PostCard.tsx @@ -1,19 +1,21 @@ +import { Post } from "src/features/Posts/types" +import BountyCard from "./BountyCard" +import QuestionCard from "./QuestionCard" +import StoryCard from "./StoryCard" -type Props = - | { - type: 'story' - } - | { - type: 'question' - } - | { - type: 'bounty' - } - -export default function PostCard(props: Props) { - if ('question' in props) { - } - return ( -
StoryCard
- ) +type Props = { + post: Post +} + +export default function PostCard({ post }: Props) { + if (post.type === 'story') + return + + if (post.type === 'bounty') + return + + if (post.type === 'question') + return + + return null } diff --git a/src/features/Posts/Components/PostCard/QuestionCard.stories.tsx b/src/features/Posts/Components/PostCard/QuestionCard.stories.tsx index 356898d..84e05ba 100644 --- a/src/features/Posts/Components/PostCard/QuestionCard.stories.tsx +++ b/src/features/Posts/Components/PostCard/QuestionCard.stories.tsx @@ -12,7 +12,7 @@ export default { } as ComponentMeta; -const Template: ComponentStory = (args) =>
+const Template: ComponentStory = (args) =>
export const Default = Template.bind({}); Default.args = { diff --git a/src/features/Posts/Components/PostCard/QuestionCard.tsx b/src/features/Posts/Components/PostCard/QuestionCard.tsx index 0359d01..e69f32a 100644 --- a/src/features/Posts/Components/PostCard/QuestionCard.tsx +++ b/src/features/Posts/Components/PostCard/QuestionCard.tsx @@ -15,11 +15,11 @@ export default function QuestionCard({ question }: Props) {
{/* */}
-
+

{question.title}

-

{question.excerpt}

+

{question.excerpt}

@@ -39,16 +39,12 @@ export default function QuestionCard({ question }: Props) {
- {question.comments.map(comment =>
-
- -
-

{comment.author.name}

-

{dayjs(comment.date).format('MMMM DD')}

-
-
-

{comment.body}

-
)} +
+ {question.comments.map(comment =>
+
+

{comment.body}

+
)} +
diff --git a/src/features/Posts/Components/PostCard/StoryCard.stories.tsx b/src/features/Posts/Components/PostCard/StoryCard.stories.tsx index 545ca97..6649aaa 100644 --- a/src/features/Posts/Components/PostCard/StoryCard.stories.tsx +++ b/src/features/Posts/Components/PostCard/StoryCard.stories.tsx @@ -12,7 +12,7 @@ export default { } as ComponentMeta; -const Template: ComponentStory = (args) =>
+const Template: ComponentStory = (args) =>
export const Default = Template.bind({}); Default.args = { diff --git a/src/features/Posts/Components/PostCard/StoryCard.tsx b/src/features/Posts/Components/PostCard/StoryCard.tsx index bac6b64..fc92399 100644 --- a/src/features/Posts/Components/PostCard/StoryCard.tsx +++ b/src/features/Posts/Components/PostCard/StoryCard.tsx @@ -11,9 +11,9 @@ export default function StoryCard({ story }: Props) {
-
+

{story.title}

-

{story.excerpt}

+

{story.excerpt}


diff --git a/src/features/Posts/Components/PostsList/PostsList.stories.tsx b/src/features/Posts/Components/PostsList/PostsList.stories.tsx new file mode 100644 index 0000000..f34894c --- /dev/null +++ b/src/features/Posts/Components/PostsList/PostsList.stories.tsx @@ -0,0 +1,22 @@ +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { MOCK_DATA } from 'src/mocks/data'; + +import PostsList from './PostsList'; + +export default { + title: 'Posts/Components/PostsList', + component: PostsList, + argTypes: { + backgroundColor: { control: 'color' }, + }, +} as ComponentMeta; + + +const Template: ComponentStory = (args) =>
+ +export const Default = Template.bind({}); +Default.args = { + posts: MOCK_DATA['feed'] +} + + diff --git a/src/features/Posts/Components/PostsList/PostsList.tsx b/src/features/Posts/Components/PostsList/PostsList.tsx new file mode 100644 index 0000000..0e0bdfb --- /dev/null +++ b/src/features/Posts/Components/PostsList/PostsList.tsx @@ -0,0 +1,16 @@ +import { Post } from "src/features/Posts/types" +import PostCard from "../PostCard/PostCard" + +interface Props { + posts: Post[] +} + +export default function PostsList(props: Props) { + return ( +
+ { + props.posts.map(post => ) + } +
+ ) +} diff --git a/src/features/Posts/pages/FeedPage/FeedPage.tsx b/src/features/Posts/pages/FeedPage/FeedPage.tsx new file mode 100644 index 0000000..3deda80 --- /dev/null +++ b/src/features/Posts/pages/FeedPage/FeedPage.tsx @@ -0,0 +1 @@ +export { } \ No newline at end of file diff --git a/src/features/Posts/pages/FeedPage/feed.graphql b/src/features/Posts/pages/FeedPage/feed.graphql new file mode 100644 index 0000000..6d0629a --- /dev/null +++ b/src/features/Posts/pages/FeedPage/feed.graphql @@ -0,0 +1,75 @@ +query FeedQuery { + getFeed { + ... on Story { + id + title + date + author { + id + name + image + } + excerpt + tags { + id + title + } + votes_count + type + cover_image + comments_count + } + ... on Bounty { + id + title + date + author { + id + name + image + } + excerpt + tags { + id + title + } + votes_count + type + cover_image + deadline + reward_amount + applicants_count + } + ... on Question { + id + title + date + author { + id + name + image + } + excerpt + tags { + id + title + } + votes_count + type + cover_image + deadline + reward_amount + answers_count + comments { + id + date + body + author { + id + name + image + } + } + } + } +} diff --git a/src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx b/src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx new file mode 100644 index 0000000..3deda80 --- /dev/null +++ b/src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx @@ -0,0 +1 @@ +export { } \ No newline at end of file diff --git a/src/features/Posts/pages/PostDetailsPage/postDetails.graphql b/src/features/Posts/pages/PostDetailsPage/postDetails.graphql new file mode 100644 index 0000000..360d1d1 --- /dev/null +++ b/src/features/Posts/pages/PostDetailsPage/postDetails.graphql @@ -0,0 +1,75 @@ +query PostDetailsQuery($postId: Int!) { + getPostById(id: $postId) { + ... on Story { + id + title + date + author { + id + name + image + } + excerpt + tags { + id + title + } + votes_count + type + cover_image + comments_count + } + ... on Bounty { + id + title + date + author { + id + name + image + } + excerpt + tags { + id + title + } + votes_count + type + cover_image + deadline + reward_amount + applicants_count + } + ... on Question { + id + title + date + author { + id + name + image + } + excerpt + tags { + id + title + } + votes_count + type + cover_image + deadline + reward_amount + answers_count + comments { + id + date + body + author { + id + name + image + } + } + } + } +} diff --git a/src/features/Posts/types/index.ts b/src/features/Posts/types/index.ts index 868b6f4..eca6f31 100644 --- a/src/features/Posts/types/index.ts +++ b/src/features/Posts/types/index.ts @@ -1,50 +1 @@ -import { Tag } from "src/utils/interfaces" - -export type User = { - id: number - name: string - image: string -} - -export type Author = User & { - join_date: string -} - -export type PostBase = { - id: number - title: string - date: string - author: Author - excerpt: string - tags: Tag[] - votes_count: number -} - -export type Story = PostBase & { - type: 'story' - cover_image: string; - comments_count: number -} - -export type Bounty = PostBase & { - type: 'bounty' - cover_image: string; - reward_amount: number - deadline: string - applicants_count: number -} - -export type Question = PostBase & { - type: 'question' - answers_count: number - comments: PostComment[] -} - -export type PostComment = { - id: number; - author: Author - date: string - body: string -} - -export type Post = Story | Question | Bounty +export * from './posts.interface' \ No newline at end of file diff --git a/src/features/Posts/types/posts.interface.ts b/src/features/Posts/types/posts.interface.ts new file mode 100644 index 0000000..868b6f4 --- /dev/null +++ b/src/features/Posts/types/posts.interface.ts @@ -0,0 +1,50 @@ +import { Tag } from "src/utils/interfaces" + +export type User = { + id: number + name: string + image: string +} + +export type Author = User & { + join_date: string +} + +export type PostBase = { + id: number + title: string + date: string + author: Author + excerpt: string + tags: Tag[] + votes_count: number +} + +export type Story = PostBase & { + type: 'story' + cover_image: string; + comments_count: number +} + +export type Bounty = PostBase & { + type: 'bounty' + cover_image: string; + reward_amount: number + deadline: string + applicants_count: number +} + +export type Question = PostBase & { + type: 'question' + answers_count: number + comments: PostComment[] +} + +export type PostComment = { + id: number; + author: Author + date: string + body: string +} + +export type Post = Story | Question | Bounty diff --git a/src/graphql/index.tsx b/src/graphql/index.tsx index 65508c4..ab965bc 100644 --- a/src/graphql/index.tsx +++ b/src/graphql/index.tsx @@ -24,6 +24,22 @@ export type Award = { url: Scalars['String']; }; +export type Bounty = PostBase & { + __typename?: 'Bounty'; + applicants_count: Scalars['Int']; + author: User; + cover_image: Scalars['String']; + date: Scalars['String']; + deadline: Scalars['String']; + excerpt: Scalars['String']; + id: Scalars['Int']; + reward_amount: Scalars['Int']; + tags: Array; + title: Scalars['String']; + type: Scalars['String']; + votes_count: Scalars['Int']; +}; + export type Category = { __typename?: 'Category'; apps_count: Scalars['Int']; @@ -61,6 +77,26 @@ export type MutationVoteArgs = { project_id: Scalars['Int']; }; +export type Post = Bounty | Question | Story; + +export type PostBase = { + author: User; + date: Scalars['String']; + excerpt: Scalars['String']; + id: Scalars['Int']; + tags: Array; + title: Scalars['String']; + votes_count: Scalars['Int']; +}; + +export type PostComment = { + __typename?: 'PostComment'; + author: User; + body: Scalars['String']; + date: Scalars['String']; + id: Scalars['Int']; +}; + export type Project = { __typename?: 'Project'; awards: Array; @@ -83,7 +119,9 @@ export type Query = { allCategories: Array; allProjects: Array; getCategory: Category; + getFeed: Array; getLnurlDetailsForProject: LnurlDetails; + getPostById: Post; getProject: Project; hottestProjects: Array; newProjects: Array; @@ -103,11 +141,22 @@ export type QueryGetCategoryArgs = { }; +export type QueryGetFeedArgs = { + skip?: InputMaybe; + take?: InputMaybe; +}; + + export type QueryGetLnurlDetailsForProjectArgs = { project_id: Scalars['Int']; }; +export type QueryGetPostByIdArgs = { + id: Scalars['Int']; +}; + + export type QueryGetProjectArgs = { id: Scalars['Int']; }; @@ -138,6 +187,37 @@ export type QuerySearchProjectsArgs = { take?: InputMaybe; }; +export type Question = PostBase & { + __typename?: 'Question'; + answers_count: Scalars['Int']; + author: User; + comments: Array; + cover_image: Scalars['String']; + date: Scalars['String']; + deadline: Scalars['String']; + excerpt: Scalars['String']; + id: Scalars['Int']; + reward_amount: Scalars['Int']; + tags: Array; + title: Scalars['String']; + type: Scalars['String']; + votes_count: Scalars['Int']; +}; + +export type Story = PostBase & { + __typename?: 'Story'; + author: User; + comments_count: Scalars['Int']; + cover_image: Scalars['String']; + date: Scalars['String']; + excerpt: Scalars['String']; + id: Scalars['Int']; + tags: Array; + title: Scalars['String']; + type: Scalars['String']; + votes_count: Scalars['Int']; +}; + export type Tag = { __typename?: 'Tag'; id: Scalars['Int']; @@ -145,6 +225,13 @@ export type Tag = { title: Scalars['String']; }; +export type User = { + __typename?: 'User'; + id: Scalars['Int']; + image: Scalars['String']; + name: Scalars['String']; +}; + export type Vote = { __typename?: 'Vote'; amount_in_sat: Scalars['Int']; @@ -167,6 +254,18 @@ export type SearchProjectsQueryVariables = Exact<{ export type SearchProjectsQuery = { __typename?: 'Query', searchProjects: Array<{ __typename?: 'Project', id: number, thumbnail_image: string, title: string, category: { __typename?: 'Category', title: string, id: number } }> }; +export type FeedQueryQueryVariables = Exact<{ [key: string]: never; }>; + + +export type FeedQueryQuery = { __typename?: 'Query', getFeed: Array<{ __typename?: 'Bounty', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, answers_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, date: string, body: string, author: { __typename?: 'User', id: number, name: string, image: string } }> } | { __typename?: 'Story', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, comments_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> }> }; + +export type PostDetailsQueryQueryVariables = Exact<{ + postId: Scalars['Int']; +}>; + + +export type PostDetailsQueryQuery = { __typename?: 'Query', getPostById: { __typename?: 'Bounty', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, answers_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, date: string, body: string, author: { __typename?: 'User', id: number, name: string, image: string } }> } | { __typename?: 'Story', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, comments_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } }; + export type CategoryPageQueryVariables = Exact<{ categoryId: Scalars['Int']; }>; @@ -291,6 +390,215 @@ export function useSearchProjectsLazyQuery(baseOptions?: Apollo.LazyQueryHookOpt export type SearchProjectsQueryHookResult = ReturnType; export type SearchProjectsLazyQueryHookResult = ReturnType; export type SearchProjectsQueryResult = Apollo.QueryResult; +export const FeedQueryDocument = gql` + query FeedQuery { + getFeed { + ... on Story { + id + title + date + author { + id + name + image + } + excerpt + tags { + id + title + } + votes_count + type + cover_image + comments_count + } + ... on Bounty { + id + title + date + author { + id + name + image + } + excerpt + tags { + id + title + } + votes_count + type + cover_image + deadline + reward_amount + applicants_count + } + ... on Question { + id + title + date + author { + id + name + image + } + excerpt + tags { + id + title + } + votes_count + type + cover_image + deadline + reward_amount + answers_count + comments { + id + date + body + author { + id + name + image + } + } + } + } +} + `; + +/** + * __useFeedQueryQuery__ + * + * To run a query within a React component, call `useFeedQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useFeedQueryQuery` 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 query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useFeedQueryQuery({ + * variables: { + * }, + * }); + */ +export function useFeedQueryQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(FeedQueryDocument, options); + } +export function useFeedQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(FeedQueryDocument, options); + } +export type FeedQueryQueryHookResult = ReturnType; +export type FeedQueryLazyQueryHookResult = ReturnType; +export type FeedQueryQueryResult = Apollo.QueryResult; +export const PostDetailsQueryDocument = gql` + query PostDetailsQuery($postId: Int!) { + getPostById(id: $postId) { + ... on Story { + id + title + date + author { + id + name + image + } + excerpt + tags { + id + title + } + votes_count + type + cover_image + comments_count + } + ... on Bounty { + id + title + date + author { + id + name + image + } + excerpt + tags { + id + title + } + votes_count + type + cover_image + deadline + reward_amount + applicants_count + } + ... on Question { + id + title + date + author { + id + name + image + } + excerpt + tags { + id + title + } + votes_count + type + cover_image + deadline + reward_amount + answers_count + comments { + id + date + body + author { + id + name + image + } + } + } + } +} + `; + +/** + * __usePostDetailsQueryQuery__ + * + * To run a query within a React component, call `usePostDetailsQueryQuery` and pass it any options that fit your needs. + * When your component renders, `usePostDetailsQueryQuery` 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 query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = usePostDetailsQueryQuery({ + * variables: { + * postId: // value for 'postId' + * }, + * }); + */ +export function usePostDetailsQueryQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(PostDetailsQueryDocument, options); + } +export function usePostDetailsQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(PostDetailsQueryDocument, options); + } +export type PostDetailsQueryQueryHookResult = ReturnType; +export type PostDetailsQueryLazyQueryHookResult = ReturnType; +export type PostDetailsQueryQueryResult = Apollo.QueryResult; export const CategoryPageDocument = gql` query CategoryPage($categoryId: Int!) { projectsByCategory(category_id: $categoryId) { diff --git a/src/mocks/data.ts b/src/mocks/data.ts index 98dab99..269a6f6 100644 --- a/src/mocks/data.ts +++ b/src/mocks/data.ts @@ -1,9 +1,9 @@ -import { Project, ProjectCategory } from "src/utils/interfaces"; -import { posts } from "./data/posts"; +import { posts, feed } from "./data/posts"; import { categories, projects } from "./data/projects"; export const MOCK_DATA = { - projects: projects, - categories: categories, - posts: posts + projects, + categories, + posts, + feed } \ No newline at end of file diff --git a/src/mocks/data/posts.ts b/src/mocks/data/posts.ts index 7d22ecf..e6c0882 100644 --- a/src/mocks/data/posts.ts +++ b/src/mocks/data/posts.ts @@ -1,5 +1,6 @@ -import { Bounty, Question, Story } from "src/features/Posts/types"; +import dayjs from "dayjs"; +import { Bounty, Post, Question, Story } from "src/features/Posts/types"; import { getAvatarImage, getCoverImage } from "./utils"; const getAuthor = () => ({ @@ -8,9 +9,9 @@ const getAuthor = () => ({ image: getAvatarImage() }) -const date = 'Mon Mar 14 2022 20:33:17 GMT+0200 (Eastern European Standard Time)' +const date = dayjs().subtract(5, 'hour').toString(); -let posts = { +export let posts = { stories: [ { id: 1, @@ -86,7 +87,9 @@ posts.bounties = posts.bounties.map(b => ({ ...b, __typename: "Bounty" })) posts.questions = posts.questions.map(b => ({ ...b, __typename: "Question" })) posts.stories = posts.stories.map(b => ({ ...b, __typename: "Story" })) +export const feed: Post[] = [ + ...posts.stories, + ...posts.bounties, + ...posts.questions, +] -export { - posts, -} \ No newline at end of file diff --git a/src/mocks/data/projects.ts b/src/mocks/data/projects.ts index 9b928fa..7cd255b 100644 --- a/src/mocks/data/projects.ts +++ b/src/mocks/data/projects.ts @@ -1,7 +1,7 @@ import { Project, ProjectCategory } from "src/utils/interfaces"; -let categories = [ +export let categories = [ { "title": "Shock the Web ⚡️", "id": 11, @@ -79,9 +79,9 @@ let categories = [ "icon": "🔁", "votes_sum": 0 } -] +] as ProjectCategory[] -let projects = [ +export let projects = [ { "id": 16, "title": "Alby", @@ -555,7 +555,7 @@ let projects = [ "title": "Gaming" } } -] +] as Project[] categories = categories.map(c => ({ ...c, __typename: "Category" })) @@ -564,7 +564,3 @@ projects = projects.map(p => ({ ...p, __typename: "Project" })) // 2- Computed Fields categories = categories.map(c => ({ ...c, apps_count: projects.reduce((acc, p) => acc + (p.category.id === c.id ? 1 : 0), 0) })) -export { - projects, - categories -} \ No newline at end of file From 720691067019ce1e5a457524cdecf75777e89f0d Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Sun, 17 Apr 2022 11:40:07 +0300 Subject: [PATCH 04/90] feat: update mocks resolvers --- functions/graphql/types/post.js | 4 +- src/mocks/data/projects.ts | 32 ++++++++++- src/mocks/handlers.ts | 53 ++++++++++++++----- src/mocks/resolvers.ts | 6 ++- .../ProjectDetailsCard/ProjectDetailsCard.tsx | 6 +-- src/utils/interfaces/project.interfaces.ts | 18 +++---- 6 files changed, 89 insertions(+), 30 deletions(-) diff --git a/functions/graphql/types/post.js b/functions/graphql/types/post.js index b2e513c..c9328f8 100644 --- a/functions/graphql/types/post.js +++ b/functions/graphql/types/post.js @@ -14,8 +14,8 @@ const { paginationArgs } = require('./helpers'); const PostBase = interfaceType({ name: 'PostBase', - resolveType(post) { - return post.type + resolveType() { + return null }, definition(t) { t.nonNull.int('id'); diff --git a/src/mocks/data/projects.ts b/src/mocks/data/projects.ts index 7cd255b..df71fc1 100644 --- a/src/mocks/data/projects.ts +++ b/src/mocks/data/projects.ts @@ -92,6 +92,7 @@ export let projects = [ "website": "https://getalby.com/", "lightning_address": "hello@getalby.com", "votes_count": 335, + tags: [], "category": { "id": 9, "title": "Misc / Other" @@ -107,6 +108,7 @@ export let projects = [ "website": "https://geyser.fund/", "lightning_address": "divineorgan67@walletofsatoshi.com", "votes_count": 232, + tags: [], "category": { "id": 1, "title": "Finance" @@ -126,6 +128,7 @@ export let projects = [ "website": "https://kollider.xyz/", "lightning_address": "johns@getalby.com", "votes_count": 220, + tags: [], "category": { "id": 1, "title": "Finance" @@ -141,6 +144,7 @@ export let projects = [ "website": "https://lightning.video/", "lightning_address": "moritz@getalby.com", "votes_count": 205, + tags: [], "category": { "id": 7, "title": "Media & News" @@ -156,6 +160,7 @@ export let projects = [ "website": "https://www.wavlake.com/", "lightning_address": "moritz@getalby.com", "votes_count": 45, + tags: [], "category": { "id": 7, "title": "Media & News" @@ -171,6 +176,7 @@ export let projects = [ "website": "https://www.bitrefill.com/buy", "lightning_address": "moritz@getalby.com", "votes_count": 25, + tags: [], "category": { "id": 8, "title": "Shopping" @@ -186,6 +192,7 @@ export let projects = [ "website": "https://sparkshot.io/", "lightning_address": "johns@getalby.com", "votes_count": 11, + tags: [], "category": { "id": 3, "title": "Art & Collectibles" @@ -201,6 +208,7 @@ export let projects = [ "website": "https://lightning-roulette.com/", "lightning_address": "moritz@getalby.com", "votes_count": 10, + tags: [], "category": { "id": 4, "title": "Gaming" @@ -216,9 +224,11 @@ export let projects = [ "website": "https://lnshort.it/", "lightning_address": "moritz@getalby.com", "votes_count": 10, + tags: [], "category": { "id": 9, - "title": "Misc / Other" + "title": "Misc / Other", + } }, { @@ -231,6 +241,7 @@ export let projects = [ "website": "https://lightning.gifts/", "lightning_address": "moritz@getalby.com", "votes_count": 10, + tags: [], "category": { "id": 8, "title": "Shopping" @@ -246,6 +257,7 @@ export let projects = [ "website": "https://www.lnblackjack.com/", "lightning_address": "moritz@getalby.com", "votes_count": 5, + tags: [], "category": { "id": 4, "title": "Gaming" @@ -265,6 +277,7 @@ export let projects = [ "website": "https://satsbuster.herokuapp.com/", "lightning_address": "subirachs@getalby.com", "votes_count": 0, + tags: [], "category": { "id": 11, "title": "Shock the Web ⚡️" @@ -282,6 +295,7 @@ export let projects = [ "website": "https://satstreamer.vercel.app", "lightning_address": "kiwiidb@getalby.com", "votes_count": 0, + tags: [], "category": { "id": 11, "title": "Shock the Web ⚡️" @@ -300,6 +314,7 @@ export let projects = [ "website": "https://github.com/Zrce/tipwall-frontend", "lightning_address": "tobitcoin@getalby.com", "votes_count": 0, + tags: [], "category": { "id": 11, "title": "Shock the Web ⚡️" @@ -325,6 +340,7 @@ export let projects = [ "website": "https://arionparking.tech/", "lightning_address": "atlantabitdevs@getalby.com", "votes_count": 0, + tags: [], "category": { "id": 11, "title": "Shock the Web ⚡️" @@ -342,6 +358,7 @@ export let projects = [ "website": "https://webln.twentyuno.net/widget", "lightning_address": "reneaaron@getalby.com", "votes_count": 0, + tags: [], "category": { "id": 11, "title": "Shock the Web ⚡️" @@ -364,6 +381,7 @@ export let projects = [ "website": "https://lnshop.github.io/lnshop/", "lightning_address": "alivesession77@walletofsatoshi.com", "votes_count": 0, + tags: [], "category": { "id": 11, "title": "Shock the Web ⚡️" @@ -379,6 +397,7 @@ export let projects = [ "website": "https://lnmarkets.com/", "lightning_address": "johns@getalby.com", "votes_count": 0, + tags: [], "category": { "id": 1, "title": "Finance" @@ -400,6 +419,7 @@ export let projects = [ "website": "https://geyser.fund", "lightning_address": "divineorgan67@walletofsatoshi.com", "votes_count": 0, + tags: [], "category": { "id": 11, "title": "Shock the Web ⚡️" @@ -415,6 +435,7 @@ export let projects = [ "website": "https://loft.trade/", "lightning_address": "moritz@getalby.com", "votes_count": 0, + tags: [], "category": { "id": 1, "title": "Finance" @@ -430,6 +451,7 @@ export let projects = [ "website": "https://kriptode.com/satsforlikes/index.html", "lightning_address": "moritz@getalby.com", "votes_count": 0, + tags: [], "category": { "id": 9, "title": "Misc / Other" @@ -445,6 +467,7 @@ export let projects = [ "website": "https://scarce.city/", "lightning_address": "moritz@getalby.com", "votes_count": 0, + tags: [], "category": { "id": 3, "title": "Art & Collectibles" @@ -460,6 +483,7 @@ export let projects = [ "website": "https://stacker.news/", "lightning_address": "moritz@getalby.com", "votes_count": 0, + tags: [], "category": { "id": 7, "title": "Media & News" @@ -475,6 +499,7 @@ export let projects = [ "website": "https://www.starbackr.com/", "lightning_address": "moritz@geralby.com", "votes_count": 0, + tags: [], "category": { "id": 7, "title": "Media & News" @@ -490,6 +515,7 @@ export let projects = [ "website": "https://amboss.space/", "lightning_address": "moritz@getalby.com", "votes_count": 0, + tags: [], "category": { "id": 6, "title": "Analytics" @@ -505,6 +531,7 @@ export let projects = [ "website": "https://yalls.org/", "lightning_address": "moritz@getalby.com", "votes_count": 0, + tags: [], "category": { "id": 2, "title": "Social" @@ -520,6 +547,7 @@ export let projects = [ "website": "https://lightningnetworkstores.com/", "lightning_address": "moritz@getalby.com", "votes_count": 0, + tags: [], "category": { "id": 8, "title": "Shopping" @@ -535,6 +563,7 @@ export let projects = [ "website": "https://lightning-poker.com/", "lightning_address": "moritz@getalby.com", "votes_count": 0, + tags: [], "category": { "id": 4, "title": "Gaming" @@ -550,6 +579,7 @@ export let projects = [ "website": "https://lngames.net/", "lightning_address": "moritz@getalby.com", "votes_count": 0, + tags: [], "category": { "id": 4, "title": "Gaming" diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index f3a6c02..ca8a180 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -1,35 +1,46 @@ import { graphql } from 'msw' import { allCategories, getCategory, getProject, hottestProjects, newProjects, projectsByCategory, searchProjects } from './resolvers' +import { + NavCategoriesQuery, + ExploreProjectsQuery, + SearchProjectsQuery, + SearchProjectsQueryVariables, + CategoryPageQuery, + CategoryPageQueryVariables, + ProjectDetailsQuery, + ProjectDetailsQueryVariables, + HottestProjectsQuery, + HottestProjectsQueryVariables, + AllCategoriesQuery, + AllCategoriesQueryVariables +} from 'src/graphql' const delay = (ms = 1000) => new Promise((res) => setTimeout(res, ms)) export const handlers = [ - graphql.query('PROJECTS_IN_CATEGORY_QUERY', async (req, res, ctx) => { + graphql.query('NavCategories', async (req, res, ctx) => { await delay() - const { categoryId } = req.variables return res( ctx.data({ - projectsByCategory: projectsByCategory(categoryId), - getCategory: getCategory(categoryId) + allCategories: allCategories() }) ) }), - graphql.query('SEARCH_PROJECTS_QUERY', async (req, res, ctx) => { + graphql.query('AllCategories', async (req, res, ctx) => { await delay() - const { search } = req.variables return res( ctx.data({ - searchProjects: searchProjects(search), + allCategories: allCategories() }) ) }), - graphql.query('AllCategoriesProjects', async (req, res, ctx) => { + graphql.query('ExploreProjects', async (req, res, ctx) => { await delay() return res( @@ -40,27 +51,42 @@ export const handlers = [ ) }), - graphql.query('AllCategories', async (req, res, ctx) => { + graphql.query('CategoryPage', async (req, res, ctx) => { await delay() + const { categoryId } = req.variables + return res( ctx.data({ - allCategories: allCategories() + projectsByCategory: projectsByCategory(categoryId), + getCategory: getCategory(categoryId)! }) ) }), - graphql.query('Project', async (req, res, ctx) => { + + graphql.query('SearchProjects', async (req, res, ctx) => { + await delay() + const { search } = req.variables + + return res( + ctx.data({ + searchProjects: searchProjects(search), + }) + ) + }), + + graphql.query('ProjectDetails', async (req, res, ctx) => { await delay() const { projectId } = req.variables return res( ctx.data({ - getProject: getProject(projectId) + getProject: getProject(projectId) as any }) ) }), - graphql.query('HOTTEST_PROJECTS', async (req, res, ctx) => { + graphql.query('HottestProjects', async (req, res, ctx) => { await delay() return res( @@ -69,4 +95,5 @@ export const handlers = [ }) ) }), + ] \ No newline at end of file diff --git a/src/mocks/resolvers.ts b/src/mocks/resolvers.ts index 36b20dc..2542758 100644 --- a/src/mocks/resolvers.ts +++ b/src/mocks/resolvers.ts @@ -2,8 +2,10 @@ import ASSETS from "src/assets"; import { MOCK_DATA } from "./data"; export function getCategory(id: number) { + + const category = MOCK_DATA.categories.find(c => c.id === id)!; return { - ...MOCK_DATA.categories.find(c => c.id === id), + ...category, project: MOCK_DATA.projects.filter(p => p.category.id === id) } } @@ -25,7 +27,7 @@ export function newProjects() { } export function getProject(projectId: number) { - return MOCK_DATA.projects.find(p => p.id === projectId) + return MOCK_DATA.projects.find(p => p.id === projectId)! } export function searchProjects(search: string) { diff --git a/src/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx b/src/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx index 71d134e..ddd30b2 100644 --- a/src/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx +++ b/src/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx @@ -97,8 +97,8 @@ export default function ProjectDetailsCard({ onClose, direction, ...props }: Pro
-
- +
+

{project?.title}

@@ -141,7 +141,7 @@ export default function ProjectDetailsCard({ onClose, direction, ...props }: Pro
{project.screenshots.slice(0, 4).map((screenshot, idx) =>
setScreenshotsOpen(idx)} > diff --git a/src/utils/interfaces/project.interfaces.ts b/src/utils/interfaces/project.interfaces.ts index c192782..682f8f5 100644 --- a/src/utils/interfaces/project.interfaces.ts +++ b/src/utils/interfaces/project.interfaces.ts @@ -1,18 +1,18 @@ -import { Tag } from "src/graphql"; +import { Project as ApiProject, Tag } from "src/graphql"; import { Image } from "."; export interface Project { - id: number; - title: string; + id: ApiProject['id']; + title: ApiProject['title']; category: Pick; - website?: string; - description: string; + website?: ApiProject['website']; + description: ApiProject['description']; tags: Pick[]; - cover_image: Image; - thumbnail_image: Image; - lightning_address?: string | null, + cover_image: ApiProject['cover_image']; + thumbnail_image: ApiProject['thumbnail_image']; + lightning_address?: ApiProject['lightning_address'] | null, screenshots: Image[]; - votes_count: number; + votes_count: ApiProject['votes_count']; } export interface ProjectCategory { From e5a0dc08433e4c5e93c2e489865dcbbb665c105b Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Sun, 17 Apr 2022 12:23:46 +0300 Subject: [PATCH 05/90] feat: add posts mocks handlesr, add post type gurads --- functions/graphql/types/post.js | 7 ++- .../Posts/Components/PostCard/PostCard.tsx | 8 +-- .../Posts/Components/PostsList/PostsList.tsx | 6 +- .../Posts/pages/FeedPage/feed.graphql | 2 +- .../pages/PostDetailsPage/postDetails.graphql | 2 +- src/features/Posts/types/posts.interface.ts | 18 ++++-- src/graphql/index.tsx | 60 +++++++++---------- src/mocks/data/posts.ts | 12 ++-- src/mocks/handlers.ts | 28 ++++++++- src/mocks/resolvers.ts | 18 ++++++ 10 files changed, 109 insertions(+), 52 deletions(-) diff --git a/functions/graphql/types/post.js b/functions/graphql/types/post.js index c9328f8..06020f6 100644 --- a/functions/graphql/types/post.js +++ b/functions/graphql/types/post.js @@ -37,7 +37,7 @@ const Story = objectType({ definition(t) { t.implements('PostBase'); t.nonNull.string('type', { - resolve: () => 'story' + resolve: () => 'Story' }); t.nonNull.string('cover_image'); t.nonNull.int('comments_count'); @@ -49,7 +49,7 @@ const Bounty = objectType({ definition(t) { t.implements('PostBase'); t.nonNull.string('type', { - resolve: () => 'bounty' + resolve: () => 'Bounty' }); t.nonNull.string('cover_image'); t.nonNull.string('deadline'); @@ -63,7 +63,8 @@ const Question = objectType({ definition(t) { t.implements('PostBase'); t.nonNull.string('type', { - resolve: () => 'question' + resolve: () => 'Question', + }); t.nonNull.string('cover_image'); t.nonNull.string('deadline'); diff --git a/src/features/Posts/Components/PostCard/PostCard.tsx b/src/features/Posts/Components/PostCard/PostCard.tsx index 740a8d6..bf0802e 100644 --- a/src/features/Posts/Components/PostCard/PostCard.tsx +++ b/src/features/Posts/Components/PostCard/PostCard.tsx @@ -1,4 +1,4 @@ -import { Post } from "src/features/Posts/types" +import { Post, isStory, isBounty, isQuestion } from "src/features/Posts/types" import BountyCard from "./BountyCard" import QuestionCard from "./QuestionCard" import StoryCard from "./StoryCard" @@ -8,13 +8,13 @@ type Props = { } export default function PostCard({ post }: Props) { - if (post.type === 'story') + if (isStory(post)) return - if (post.type === 'bounty') + if (isBounty(post)) return - if (post.type === 'question') + if (isQuestion(post)) return return null diff --git a/src/features/Posts/Components/PostsList/PostsList.tsx b/src/features/Posts/Components/PostsList/PostsList.tsx index 0e0bdfb..52a119f 100644 --- a/src/features/Posts/Components/PostsList/PostsList.tsx +++ b/src/features/Posts/Components/PostsList/PostsList.tsx @@ -1,4 +1,5 @@ import { Post } from "src/features/Posts/types" +import { useFeedQuery } from "src/graphql" import PostCard from "../PostCard/PostCard" interface Props { @@ -6,10 +7,13 @@ interface Props { } export default function PostsList(props: Props) { + + const { data, loading } = useFeedQuery() + if (loading) return

Loading

return (
{ - props.posts.map(post => ) + data?.getFeed.map(post => ) }
) diff --git a/src/features/Posts/pages/FeedPage/feed.graphql b/src/features/Posts/pages/FeedPage/feed.graphql index 6d0629a..d012632 100644 --- a/src/features/Posts/pages/FeedPage/feed.graphql +++ b/src/features/Posts/pages/FeedPage/feed.graphql @@ -1,4 +1,4 @@ -query FeedQuery { +query Feed { getFeed { ... on Story { id diff --git a/src/features/Posts/pages/PostDetailsPage/postDetails.graphql b/src/features/Posts/pages/PostDetailsPage/postDetails.graphql index 360d1d1..db4ee2d 100644 --- a/src/features/Posts/pages/PostDetailsPage/postDetails.graphql +++ b/src/features/Posts/pages/PostDetailsPage/postDetails.graphql @@ -1,4 +1,4 @@ -query PostDetailsQuery($postId: Int!) { +query PostDetails($postId: Int!) { getPostById(id: $postId) { ... on Story { id diff --git a/src/features/Posts/types/posts.interface.ts b/src/features/Posts/types/posts.interface.ts index 868b6f4..5f4e9cb 100644 --- a/src/features/Posts/types/posts.interface.ts +++ b/src/features/Posts/types/posts.interface.ts @@ -7,7 +7,7 @@ export type User = { } export type Author = User & { - join_date: string + join_date?: string } export type PostBase = { @@ -18,28 +18,38 @@ export type PostBase = { excerpt: string tags: Tag[] votes_count: number + type: string } export type Story = PostBase & { - type: 'story' cover_image: string; comments_count: number } +export function isStory(post: Post): post is Story { + return post.type === 'Story' +} + export type Bounty = PostBase & { - type: 'bounty' cover_image: string; reward_amount: number deadline: string applicants_count: number } +export function isBounty(post: Post): post is Bounty { + return post.type === 'Bounty' +} + export type Question = PostBase & { - type: 'question' answers_count: number comments: PostComment[] } +export function isQuestion(post: Post): post is Question { + return post.type === 'Question' +} + export type PostComment = { id: number; author: Author diff --git a/src/graphql/index.tsx b/src/graphql/index.tsx index ab965bc..e354914 100644 --- a/src/graphql/index.tsx +++ b/src/graphql/index.tsx @@ -254,17 +254,17 @@ export type SearchProjectsQueryVariables = Exact<{ export type SearchProjectsQuery = { __typename?: 'Query', searchProjects: Array<{ __typename?: 'Project', id: number, thumbnail_image: string, title: string, category: { __typename?: 'Category', title: string, id: number } }> }; -export type FeedQueryQueryVariables = Exact<{ [key: string]: never; }>; +export type FeedQueryVariables = Exact<{ [key: string]: never; }>; -export type FeedQueryQuery = { __typename?: 'Query', getFeed: Array<{ __typename?: 'Bounty', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, answers_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, date: string, body: string, author: { __typename?: 'User', id: number, name: string, image: string } }> } | { __typename?: 'Story', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, comments_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> }> }; +export type FeedQuery = { __typename?: 'Query', getFeed: Array<{ __typename?: 'Bounty', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, answers_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, date: string, body: string, author: { __typename?: 'User', id: number, name: string, image: string } }> } | { __typename?: 'Story', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, comments_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> }> }; -export type PostDetailsQueryQueryVariables = Exact<{ +export type PostDetailsQueryVariables = Exact<{ postId: Scalars['Int']; }>; -export type PostDetailsQueryQuery = { __typename?: 'Query', getPostById: { __typename?: 'Bounty', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, answers_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, date: string, body: string, author: { __typename?: 'User', id: number, name: string, image: string } }> } | { __typename?: 'Story', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, comments_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } }; +export type PostDetailsQuery = { __typename?: 'Query', getPostById: { __typename?: 'Bounty', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, answers_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, date: string, body: string, author: { __typename?: 'User', id: number, name: string, image: string } }> } | { __typename?: 'Story', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, comments_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } }; export type CategoryPageQueryVariables = Exact<{ categoryId: Scalars['Int']; @@ -390,8 +390,8 @@ export function useSearchProjectsLazyQuery(baseOptions?: Apollo.LazyQueryHookOpt export type SearchProjectsQueryHookResult = ReturnType; export type SearchProjectsLazyQueryHookResult = ReturnType; export type SearchProjectsQueryResult = Apollo.QueryResult; -export const FeedQueryDocument = gql` - query FeedQuery { +export const FeedDocument = gql` + query Feed { getFeed { ... on Story { id @@ -469,33 +469,33 @@ export const FeedQueryDocument = gql` `; /** - * __useFeedQueryQuery__ + * __useFeedQuery__ * - * To run a query within a React component, call `useFeedQueryQuery` and pass it any options that fit your needs. - * When your component renders, `useFeedQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * To run a query within a React component, call `useFeedQuery` and pass it any options that fit your needs. + * When your component renders, `useFeedQuery` 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 query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; * * @example - * const { data, loading, error } = useFeedQueryQuery({ + * const { data, loading, error } = useFeedQuery({ * variables: { * }, * }); */ -export function useFeedQueryQuery(baseOptions?: Apollo.QueryHookOptions) { +export function useFeedQuery(baseOptions?: Apollo.QueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(FeedQueryDocument, options); + return Apollo.useQuery(FeedDocument, options); } -export function useFeedQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { +export function useFeedLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(FeedQueryDocument, options); + return Apollo.useLazyQuery(FeedDocument, options); } -export type FeedQueryQueryHookResult = ReturnType; -export type FeedQueryLazyQueryHookResult = ReturnType; -export type FeedQueryQueryResult = Apollo.QueryResult; -export const PostDetailsQueryDocument = gql` - query PostDetailsQuery($postId: Int!) { +export type FeedQueryHookResult = ReturnType; +export type FeedLazyQueryHookResult = ReturnType; +export type FeedQueryResult = Apollo.QueryResult; +export const PostDetailsDocument = gql` + query PostDetails($postId: Int!) { getPostById(id: $postId) { ... on Story { id @@ -573,32 +573,32 @@ export const PostDetailsQueryDocument = gql` `; /** - * __usePostDetailsQueryQuery__ + * __usePostDetailsQuery__ * - * To run a query within a React component, call `usePostDetailsQueryQuery` and pass it any options that fit your needs. - * When your component renders, `usePostDetailsQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * To run a query within a React component, call `usePostDetailsQuery` and pass it any options that fit your needs. + * When your component renders, `usePostDetailsQuery` 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 query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; * * @example - * const { data, loading, error } = usePostDetailsQueryQuery({ + * const { data, loading, error } = usePostDetailsQuery({ * variables: { * postId: // value for 'postId' * }, * }); */ -export function usePostDetailsQueryQuery(baseOptions: Apollo.QueryHookOptions) { +export function usePostDetailsQuery(baseOptions: Apollo.QueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(PostDetailsQueryDocument, options); + return Apollo.useQuery(PostDetailsDocument, options); } -export function usePostDetailsQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { +export function usePostDetailsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(PostDetailsQueryDocument, options); + return Apollo.useLazyQuery(PostDetailsDocument, options); } -export type PostDetailsQueryQueryHookResult = ReturnType; -export type PostDetailsQueryLazyQueryHookResult = ReturnType; -export type PostDetailsQueryQueryResult = Apollo.QueryResult; +export type PostDetailsQueryHookResult = ReturnType; +export type PostDetailsLazyQueryHookResult = ReturnType; +export type PostDetailsQueryResult = Apollo.QueryResult; export const CategoryPageDocument = gql` query CategoryPage($categoryId: Int!) { projectsByCategory(category_id: $categoryId) { diff --git a/src/mocks/data/posts.ts b/src/mocks/data/posts.ts index e6c0882..6aae6b7 100644 --- a/src/mocks/data/posts.ts +++ b/src/mocks/data/posts.ts @@ -14,14 +14,14 @@ const date = dayjs().subtract(5, 'hour').toString(); export let posts = { stories: [ { - id: 1, + id: 4, title: 'Digital Editor, Mars Review of Books', cover_image: getCoverImage(), comments_count: 31, date, votes_count: 120, excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...', - type: "story", + type: "Story", tags: [ { id: 1, title: "lnurl" }, { id: 2, title: "webln" }, @@ -32,8 +32,8 @@ export let posts = { ] as Story[], bounties: [ { - type: "bounty", - id: 1, + type: "Bounty", + id: 2, title: 'Digital Editor, Mars Review of Books', cover_image: getCoverImage(), applicants_count: 31, @@ -52,8 +52,8 @@ export let posts = { ] as Bounty[], questions: [ { - type: "question", - id: 1, + type: "Question", + id: 3, title: 'Digital Editor, Mars Review of Books', answers_count: 31, date, diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index ca8a180..5b19143 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -1,6 +1,6 @@ import { graphql } from 'msw' -import { allCategories, getCategory, getProject, hottestProjects, newProjects, projectsByCategory, searchProjects } from './resolvers' +import { allCategories, getCategory, getFeed, getPostById, getProject, hottestProjects, newProjects, projectsByCategory, searchProjects } from './resolvers' import { NavCategoriesQuery, ExploreProjectsQuery, @@ -13,7 +13,10 @@ import { HottestProjectsQuery, HottestProjectsQueryVariables, AllCategoriesQuery, - AllCategoriesQueryVariables + AllCategoriesQueryVariables, + FeedQuery, + PostDetailsQuery, + PostDetailsQueryVariables, } from 'src/graphql' const delay = (ms = 1000) => new Promise((res) => setTimeout(res, ms)) @@ -96,4 +99,25 @@ export const handlers = [ ) }), + graphql.query('Feed', async (req, res, ctx) => { + await delay() + + return res( + ctx.data({ + getFeed: getFeed() + }) + ) + }), + + graphql.query('PostDetails', async (req, res, ctx) => { + await delay() + const { postId } = req.variables + + return res( + ctx.data({ + getPostById: getPostById(postId) + }) + ) + }), + ] \ No newline at end of file diff --git a/src/mocks/resolvers.ts b/src/mocks/resolvers.ts index 2542758..b432d25 100644 --- a/src/mocks/resolvers.ts +++ b/src/mocks/resolvers.ts @@ -1,5 +1,6 @@ import ASSETS from "src/assets"; import { MOCK_DATA } from "./data"; +import { Query } from 'src/graphql' export function getCategory(id: number) { @@ -39,5 +40,22 @@ export function searchProjects(search: string) { export function hottestProjects() { return MOCK_DATA.projects.sort((p1, p2) => p2.votes_count - p1.votes_count).slice(0, 20) +} +export function getFeed(): Query['getFeed'] { + return MOCK_DATA.feed as any; +} + +export function getPostById(postId: number): Query['getPostById'] { + for (const key in MOCK_DATA.posts) { + if (Object.prototype.hasOwnProperty.call(MOCK_DATA.posts, key)) { + const t = key as keyof typeof MOCK_DATA.posts + for (const p of MOCK_DATA.posts[t]) { + if (p.id === postId) return p as any; + } + + } + } + + throw new Error("Post doesn't exist") } \ No newline at end of file From 116d6a43c9ed24eedd900c85e89a5656e9b253f0 Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Sun, 17 Apr 2022 14:28:45 +0300 Subject: [PATCH 06/90] feat: create a "Projects" feature directory --- src/App.tsx | 6 +++--- src/features/Projects/index.tsx | 3 +++ .../Projects}/pages/CategoryPage/CategoryPage.tsx | 0 .../pages/CategoryPage/HeaderImage/HeaderImage.stories.tsx | 0 .../pages/CategoryPage/HeaderImage/HeaderImage.tsx | 0 .../CategoryPage/ProjectsGrid/ProjectsGrid.stories.tsx | 0 .../pages/CategoryPage/ProjectsGrid/ProjectsGrid.tsx | 0 .../Projects}/pages/CategoryPage/categoryPage.graphql | 0 .../pages/ExplorePage/Categories/Categories.stories.tsx | 0 .../Projects}/pages/ExplorePage/Categories/Categories.tsx | 0 .../pages/ExplorePage/Categories/allCategories.graphql | 0 .../Projects}/pages/ExplorePage/ExplorePage.tsx | 0 .../pages/ExplorePage/Header/CustomDot/CustomDot.tsx | 0 .../Projects}/pages/ExplorePage/Header/Header.stories.tsx | 0 .../Projects}/pages/ExplorePage/Header/Header.tsx | 0 .../Projects}/pages/ExplorePage/Header/styles.module.css | 0 .../pages/ExplorePage/ProjectsRow/ProjectsRow.Skeleton.tsx | 0 .../pages/ExplorePage/ProjectsRow/ProjectsRow.stories.tsx | 0 .../Projects}/pages/ExplorePage/ProjectsRow/ProjectsRow.tsx | 0 .../Projects}/pages/ExplorePage/ProjectsRow/style.css | 0 .../ExplorePage/ProjectsSection/ProjectsSection.stories.tsx | 0 .../pages/ExplorePage/ProjectsSection/ProjectsSection.tsx | 0 .../ExplorePage/ProjectsSection/exploreProjects.graphql | 0 src/{ => features/Projects}/pages/ExplorePage/index.ts | 0 .../Projects}/pages/HottestPage/HottestPage.tsx | 4 ++-- .../Projects}/pages/HottestPage/hottestProjects.graphql | 0 .../ClaimProject/Claim_CopySignatureCard.stories.tsx | 0 .../ProjectPage/ClaimProject/Claim_CopySignatureCard.tsx | 0 .../ClaimProject/Claim_FundWithdrawCard.stories.tsx | 0 .../ProjectPage/ClaimProject/Claim_FundWithdrawCard.tsx | 0 .../ClaimProject/Claim_GenerateSignatureCard.stories.tsx | 0 .../ClaimProject/Claim_GenerateSignatureCard.tsx | 0 .../ClaimProject/Claim_SubmittedCard.stories.tsx | 0 .../pages/ProjectPage/ClaimProject/Claim_SubmittedCard.tsx | 0 .../Projects}/pages/ProjectPage/ClaimProject/index.tsx | 0 .../ProjectPage/ProjectDetailsCard/ProjectDetails.graphql | 0 .../ProjectDetailsCard/ProjectDetailsCard.Skeleton.tsx | 0 .../ProjectDetailsCard/ProjectDetailsCard.stories.tsx | 0 .../ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx | 2 +- .../pages/ProjectPage/ProjectDetailsCard/index.tsx | 0 .../pages/ProjectPage/VoteButton/VoteButton.stories.tsx | 0 .../Projects}/pages/ProjectPage/VoteButton/VoteButton.tsx | 0 .../pages/ProjectPage/VoteButton/vote-button.style.css | 0 .../pages/ProjectPage/VoteCard/VoteCard.stories.tsx | 0 .../Projects}/pages/ProjectPage/VoteCard/VoteCard.tsx | 0 .../Projects}/pages/ProjectPage/VoteCard/index.tsx | 0 .../Projects}/pages/ProjectPage/VoteCard/style.module.css | 0 .../Projects}/pages/ProjectPage/VoteCard/vote.graphql | 0 src/features/Projects/types/index.ts | 1 + .../Projects/types}/project.interfaces.ts | 2 +- src/redux/features/modals.slice.ts | 6 +++--- src/utils/interfaces/index.ts | 2 +- 52 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 src/features/Projects/index.tsx rename src/{ => features/Projects}/pages/CategoryPage/CategoryPage.tsx (100%) rename src/{ => features/Projects}/pages/CategoryPage/HeaderImage/HeaderImage.stories.tsx (100%) rename src/{ => features/Projects}/pages/CategoryPage/HeaderImage/HeaderImage.tsx (100%) rename src/{ => features/Projects}/pages/CategoryPage/ProjectsGrid/ProjectsGrid.stories.tsx (100%) rename src/{ => features/Projects}/pages/CategoryPage/ProjectsGrid/ProjectsGrid.tsx (100%) rename src/{ => features/Projects}/pages/CategoryPage/categoryPage.graphql (100%) rename src/{ => features/Projects}/pages/ExplorePage/Categories/Categories.stories.tsx (100%) rename src/{ => features/Projects}/pages/ExplorePage/Categories/Categories.tsx (100%) rename src/{ => features/Projects}/pages/ExplorePage/Categories/allCategories.graphql (100%) rename src/{ => features/Projects}/pages/ExplorePage/ExplorePage.tsx (100%) rename src/{ => features/Projects}/pages/ExplorePage/Header/CustomDot/CustomDot.tsx (100%) rename src/{ => features/Projects}/pages/ExplorePage/Header/Header.stories.tsx (100%) rename src/{ => features/Projects}/pages/ExplorePage/Header/Header.tsx (100%) rename src/{ => features/Projects}/pages/ExplorePage/Header/styles.module.css (100%) rename src/{ => features/Projects}/pages/ExplorePage/ProjectsRow/ProjectsRow.Skeleton.tsx (100%) rename src/{ => features/Projects}/pages/ExplorePage/ProjectsRow/ProjectsRow.stories.tsx (100%) rename src/{ => features/Projects}/pages/ExplorePage/ProjectsRow/ProjectsRow.tsx (100%) rename src/{ => features/Projects}/pages/ExplorePage/ProjectsRow/style.css (100%) rename src/{ => features/Projects}/pages/ExplorePage/ProjectsSection/ProjectsSection.stories.tsx (100%) rename src/{ => features/Projects}/pages/ExplorePage/ProjectsSection/ProjectsSection.tsx (100%) rename src/{ => features/Projects}/pages/ExplorePage/ProjectsSection/exploreProjects.graphql (100%) rename src/{ => features/Projects}/pages/ExplorePage/index.ts (100%) rename src/{ => features/Projects}/pages/HottestPage/HottestPage.tsx (81%) rename src/{ => features/Projects}/pages/HottestPage/hottestProjects.graphql (100%) rename src/{ => features/Projects}/pages/ProjectPage/ClaimProject/Claim_CopySignatureCard.stories.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/ClaimProject/Claim_CopySignatureCard.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/ClaimProject/Claim_FundWithdrawCard.stories.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/ClaimProject/Claim_FundWithdrawCard.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/ClaimProject/Claim_GenerateSignatureCard.stories.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/ClaimProject/Claim_GenerateSignatureCard.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/ClaimProject/Claim_SubmittedCard.stories.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/ClaimProject/Claim_SubmittedCard.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/ClaimProject/index.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/ProjectDetailsCard/ProjectDetails.graphql (100%) rename src/{ => features/Projects}/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.Skeleton.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.stories.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx (98%) rename src/{ => features/Projects}/pages/ProjectPage/ProjectDetailsCard/index.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/VoteButton/VoteButton.stories.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/VoteButton/VoteButton.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/VoteButton/vote-button.style.css (100%) rename src/{ => features/Projects}/pages/ProjectPage/VoteCard/VoteCard.stories.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/VoteCard/VoteCard.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/VoteCard/index.tsx (100%) rename src/{ => features/Projects}/pages/ProjectPage/VoteCard/style.module.css (100%) rename src/{ => features/Projects}/pages/ProjectPage/VoteCard/vote.graphql (100%) create mode 100644 src/features/Projects/types/index.ts rename src/{utils/interfaces => features/Projects/types}/project.interfaces.ts (94%) diff --git a/src/App.tsx b/src/App.tsx index c17a8e6..e428027 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,13 +1,13 @@ import { useEffect } from "react"; import Navbar from "src/Components/Navbar/Navbar"; -import ExplorePage from "src/pages/ExplorePage"; +import ExplorePage from "src/features/Projects/pages/ExplorePage"; import ModalsContainer from "src/Components/Modals/ModalsContainer/ModalsContainer"; import { useAppSelector } from './utils/hooks'; import { Wallet_Service } from "./services"; import { Route, Routes } from "react-router-dom"; -import CategoryPage from "./pages/CategoryPage/CategoryPage"; +import CategoryPage from "src/features/Projects/pages/CategoryPage/CategoryPage"; import { useWrapperSetup } from "./utils/Wrapper"; -import HottestPage from "./pages/HottestPage/HottestPage"; +import HottestPage from "src/features/Projects/pages/HottestPage/HottestPage"; function App() { const { isWalletConnected } = useAppSelector(state => ({ diff --git a/src/features/Projects/index.tsx b/src/features/Projects/index.tsx new file mode 100644 index 0000000..4ee7951 --- /dev/null +++ b/src/features/Projects/index.tsx @@ -0,0 +1,3 @@ +export * from './pages/CategoryPage/CategoryPage' +export * from './pages/ExplorePage/ExplorePage' +export * from './pages/HottestPage/HottestPage' diff --git a/src/pages/CategoryPage/CategoryPage.tsx b/src/features/Projects/pages/CategoryPage/CategoryPage.tsx similarity index 100% rename from src/pages/CategoryPage/CategoryPage.tsx rename to src/features/Projects/pages/CategoryPage/CategoryPage.tsx diff --git a/src/pages/CategoryPage/HeaderImage/HeaderImage.stories.tsx b/src/features/Projects/pages/CategoryPage/HeaderImage/HeaderImage.stories.tsx similarity index 100% rename from src/pages/CategoryPage/HeaderImage/HeaderImage.stories.tsx rename to src/features/Projects/pages/CategoryPage/HeaderImage/HeaderImage.stories.tsx diff --git a/src/pages/CategoryPage/HeaderImage/HeaderImage.tsx b/src/features/Projects/pages/CategoryPage/HeaderImage/HeaderImage.tsx similarity index 100% rename from src/pages/CategoryPage/HeaderImage/HeaderImage.tsx rename to src/features/Projects/pages/CategoryPage/HeaderImage/HeaderImage.tsx diff --git a/src/pages/CategoryPage/ProjectsGrid/ProjectsGrid.stories.tsx b/src/features/Projects/pages/CategoryPage/ProjectsGrid/ProjectsGrid.stories.tsx similarity index 100% rename from src/pages/CategoryPage/ProjectsGrid/ProjectsGrid.stories.tsx rename to src/features/Projects/pages/CategoryPage/ProjectsGrid/ProjectsGrid.stories.tsx diff --git a/src/pages/CategoryPage/ProjectsGrid/ProjectsGrid.tsx b/src/features/Projects/pages/CategoryPage/ProjectsGrid/ProjectsGrid.tsx similarity index 100% rename from src/pages/CategoryPage/ProjectsGrid/ProjectsGrid.tsx rename to src/features/Projects/pages/CategoryPage/ProjectsGrid/ProjectsGrid.tsx diff --git a/src/pages/CategoryPage/categoryPage.graphql b/src/features/Projects/pages/CategoryPage/categoryPage.graphql similarity index 100% rename from src/pages/CategoryPage/categoryPage.graphql rename to src/features/Projects/pages/CategoryPage/categoryPage.graphql diff --git a/src/pages/ExplorePage/Categories/Categories.stories.tsx b/src/features/Projects/pages/ExplorePage/Categories/Categories.stories.tsx similarity index 100% rename from src/pages/ExplorePage/Categories/Categories.stories.tsx rename to src/features/Projects/pages/ExplorePage/Categories/Categories.stories.tsx diff --git a/src/pages/ExplorePage/Categories/Categories.tsx b/src/features/Projects/pages/ExplorePage/Categories/Categories.tsx similarity index 100% rename from src/pages/ExplorePage/Categories/Categories.tsx rename to src/features/Projects/pages/ExplorePage/Categories/Categories.tsx diff --git a/src/pages/ExplorePage/Categories/allCategories.graphql b/src/features/Projects/pages/ExplorePage/Categories/allCategories.graphql similarity index 100% rename from src/pages/ExplorePage/Categories/allCategories.graphql rename to src/features/Projects/pages/ExplorePage/Categories/allCategories.graphql diff --git a/src/pages/ExplorePage/ExplorePage.tsx b/src/features/Projects/pages/ExplorePage/ExplorePage.tsx similarity index 100% rename from src/pages/ExplorePage/ExplorePage.tsx rename to src/features/Projects/pages/ExplorePage/ExplorePage.tsx diff --git a/src/pages/ExplorePage/Header/CustomDot/CustomDot.tsx b/src/features/Projects/pages/ExplorePage/Header/CustomDot/CustomDot.tsx similarity index 100% rename from src/pages/ExplorePage/Header/CustomDot/CustomDot.tsx rename to src/features/Projects/pages/ExplorePage/Header/CustomDot/CustomDot.tsx diff --git a/src/pages/ExplorePage/Header/Header.stories.tsx b/src/features/Projects/pages/ExplorePage/Header/Header.stories.tsx similarity index 100% rename from src/pages/ExplorePage/Header/Header.stories.tsx rename to src/features/Projects/pages/ExplorePage/Header/Header.stories.tsx diff --git a/src/pages/ExplorePage/Header/Header.tsx b/src/features/Projects/pages/ExplorePage/Header/Header.tsx similarity index 100% rename from src/pages/ExplorePage/Header/Header.tsx rename to src/features/Projects/pages/ExplorePage/Header/Header.tsx diff --git a/src/pages/ExplorePage/Header/styles.module.css b/src/features/Projects/pages/ExplorePage/Header/styles.module.css similarity index 100% rename from src/pages/ExplorePage/Header/styles.module.css rename to src/features/Projects/pages/ExplorePage/Header/styles.module.css diff --git a/src/pages/ExplorePage/ProjectsRow/ProjectsRow.Skeleton.tsx b/src/features/Projects/pages/ExplorePage/ProjectsRow/ProjectsRow.Skeleton.tsx similarity index 100% rename from src/pages/ExplorePage/ProjectsRow/ProjectsRow.Skeleton.tsx rename to src/features/Projects/pages/ExplorePage/ProjectsRow/ProjectsRow.Skeleton.tsx diff --git a/src/pages/ExplorePage/ProjectsRow/ProjectsRow.stories.tsx b/src/features/Projects/pages/ExplorePage/ProjectsRow/ProjectsRow.stories.tsx similarity index 100% rename from src/pages/ExplorePage/ProjectsRow/ProjectsRow.stories.tsx rename to src/features/Projects/pages/ExplorePage/ProjectsRow/ProjectsRow.stories.tsx diff --git a/src/pages/ExplorePage/ProjectsRow/ProjectsRow.tsx b/src/features/Projects/pages/ExplorePage/ProjectsRow/ProjectsRow.tsx similarity index 100% rename from src/pages/ExplorePage/ProjectsRow/ProjectsRow.tsx rename to src/features/Projects/pages/ExplorePage/ProjectsRow/ProjectsRow.tsx diff --git a/src/pages/ExplorePage/ProjectsRow/style.css b/src/features/Projects/pages/ExplorePage/ProjectsRow/style.css similarity index 100% rename from src/pages/ExplorePage/ProjectsRow/style.css rename to src/features/Projects/pages/ExplorePage/ProjectsRow/style.css diff --git a/src/pages/ExplorePage/ProjectsSection/ProjectsSection.stories.tsx b/src/features/Projects/pages/ExplorePage/ProjectsSection/ProjectsSection.stories.tsx similarity index 100% rename from src/pages/ExplorePage/ProjectsSection/ProjectsSection.stories.tsx rename to src/features/Projects/pages/ExplorePage/ProjectsSection/ProjectsSection.stories.tsx diff --git a/src/pages/ExplorePage/ProjectsSection/ProjectsSection.tsx b/src/features/Projects/pages/ExplorePage/ProjectsSection/ProjectsSection.tsx similarity index 100% rename from src/pages/ExplorePage/ProjectsSection/ProjectsSection.tsx rename to src/features/Projects/pages/ExplorePage/ProjectsSection/ProjectsSection.tsx diff --git a/src/pages/ExplorePage/ProjectsSection/exploreProjects.graphql b/src/features/Projects/pages/ExplorePage/ProjectsSection/exploreProjects.graphql similarity index 100% rename from src/pages/ExplorePage/ProjectsSection/exploreProjects.graphql rename to src/features/Projects/pages/ExplorePage/ProjectsSection/exploreProjects.graphql diff --git a/src/pages/ExplorePage/index.ts b/src/features/Projects/pages/ExplorePage/index.ts similarity index 100% rename from src/pages/ExplorePage/index.ts rename to src/features/Projects/pages/ExplorePage/index.ts diff --git a/src/pages/HottestPage/HottestPage.tsx b/src/features/Projects/pages/HottestPage/HottestPage.tsx similarity index 81% rename from src/pages/HottestPage/HottestPage.tsx rename to src/features/Projects/pages/HottestPage/HottestPage.tsx index ba10779..61379bc 100644 --- a/src/pages/HottestPage/HottestPage.tsx +++ b/src/features/Projects/pages/HottestPage/HottestPage.tsx @@ -1,8 +1,8 @@ import ASSETS from 'src/assets'; import ErrorMessage from 'src/Components/ErrorMessage/ErrorMessage'; -import HeaderImage from 'src/pages/CategoryPage/HeaderImage/HeaderImage'; -import ProjectsGrid from 'src/pages/CategoryPage/ProjectsGrid/ProjectsGrid'; +import HeaderImage from 'src/features/Projects/pages/CategoryPage/HeaderImage/HeaderImage'; +import ProjectsGrid from 'src/features/Projects/pages/CategoryPage/ProjectsGrid/ProjectsGrid'; import { useHottestProjectsQuery } from 'src/graphql' diff --git a/src/pages/HottestPage/hottestProjects.graphql b/src/features/Projects/pages/HottestPage/hottestProjects.graphql similarity index 100% rename from src/pages/HottestPage/hottestProjects.graphql rename to src/features/Projects/pages/HottestPage/hottestProjects.graphql diff --git a/src/pages/ProjectPage/ClaimProject/Claim_CopySignatureCard.stories.tsx b/src/features/Projects/pages/ProjectPage/ClaimProject/Claim_CopySignatureCard.stories.tsx similarity index 100% rename from src/pages/ProjectPage/ClaimProject/Claim_CopySignatureCard.stories.tsx rename to src/features/Projects/pages/ProjectPage/ClaimProject/Claim_CopySignatureCard.stories.tsx diff --git a/src/pages/ProjectPage/ClaimProject/Claim_CopySignatureCard.tsx b/src/features/Projects/pages/ProjectPage/ClaimProject/Claim_CopySignatureCard.tsx similarity index 100% rename from src/pages/ProjectPage/ClaimProject/Claim_CopySignatureCard.tsx rename to src/features/Projects/pages/ProjectPage/ClaimProject/Claim_CopySignatureCard.tsx diff --git a/src/pages/ProjectPage/ClaimProject/Claim_FundWithdrawCard.stories.tsx b/src/features/Projects/pages/ProjectPage/ClaimProject/Claim_FundWithdrawCard.stories.tsx similarity index 100% rename from src/pages/ProjectPage/ClaimProject/Claim_FundWithdrawCard.stories.tsx rename to src/features/Projects/pages/ProjectPage/ClaimProject/Claim_FundWithdrawCard.stories.tsx diff --git a/src/pages/ProjectPage/ClaimProject/Claim_FundWithdrawCard.tsx b/src/features/Projects/pages/ProjectPage/ClaimProject/Claim_FundWithdrawCard.tsx similarity index 100% rename from src/pages/ProjectPage/ClaimProject/Claim_FundWithdrawCard.tsx rename to src/features/Projects/pages/ProjectPage/ClaimProject/Claim_FundWithdrawCard.tsx diff --git a/src/pages/ProjectPage/ClaimProject/Claim_GenerateSignatureCard.stories.tsx b/src/features/Projects/pages/ProjectPage/ClaimProject/Claim_GenerateSignatureCard.stories.tsx similarity index 100% rename from src/pages/ProjectPage/ClaimProject/Claim_GenerateSignatureCard.stories.tsx rename to src/features/Projects/pages/ProjectPage/ClaimProject/Claim_GenerateSignatureCard.stories.tsx diff --git a/src/pages/ProjectPage/ClaimProject/Claim_GenerateSignatureCard.tsx b/src/features/Projects/pages/ProjectPage/ClaimProject/Claim_GenerateSignatureCard.tsx similarity index 100% rename from src/pages/ProjectPage/ClaimProject/Claim_GenerateSignatureCard.tsx rename to src/features/Projects/pages/ProjectPage/ClaimProject/Claim_GenerateSignatureCard.tsx diff --git a/src/pages/ProjectPage/ClaimProject/Claim_SubmittedCard.stories.tsx b/src/features/Projects/pages/ProjectPage/ClaimProject/Claim_SubmittedCard.stories.tsx similarity index 100% rename from src/pages/ProjectPage/ClaimProject/Claim_SubmittedCard.stories.tsx rename to src/features/Projects/pages/ProjectPage/ClaimProject/Claim_SubmittedCard.stories.tsx diff --git a/src/pages/ProjectPage/ClaimProject/Claim_SubmittedCard.tsx b/src/features/Projects/pages/ProjectPage/ClaimProject/Claim_SubmittedCard.tsx similarity index 100% rename from src/pages/ProjectPage/ClaimProject/Claim_SubmittedCard.tsx rename to src/features/Projects/pages/ProjectPage/ClaimProject/Claim_SubmittedCard.tsx diff --git a/src/pages/ProjectPage/ClaimProject/index.tsx b/src/features/Projects/pages/ProjectPage/ClaimProject/index.tsx similarity index 100% rename from src/pages/ProjectPage/ClaimProject/index.tsx rename to src/features/Projects/pages/ProjectPage/ClaimProject/index.tsx diff --git a/src/pages/ProjectPage/ProjectDetailsCard/ProjectDetails.graphql b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetails.graphql similarity index 100% rename from src/pages/ProjectPage/ProjectDetailsCard/ProjectDetails.graphql rename to src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetails.graphql diff --git a/src/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.Skeleton.tsx b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.Skeleton.tsx similarity index 100% rename from src/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.Skeleton.tsx rename to src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.Skeleton.tsx diff --git a/src/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.stories.tsx b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.stories.tsx similarity index 100% rename from src/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.stories.tsx rename to src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.stories.tsx diff --git a/src/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx similarity index 98% rename from src/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx rename to src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx index ddd30b2..3d7941b 100644 --- a/src/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx +++ b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx @@ -8,7 +8,7 @@ import { setProject } from 'src/redux/features/project.slice'; import Button from 'src/Components/Button/Button'; import { AiFillThunderbolt } from 'react-icons/ai'; import ProjectCardSkeleton from './ProjectDetailsCard.Skeleton' -import VoteButton from 'src/pages/ProjectPage/VoteButton/VoteButton'; +import VoteButton from 'src/features/Projects/pages/ProjectPage/VoteButton/VoteButton'; import { Wallet_Service } from 'src/services' import { useProjectDetailsQuery } from 'src/graphql'; import Lightbox from 'src/Components/Lightbox/Lightbox' diff --git a/src/pages/ProjectPage/ProjectDetailsCard/index.tsx b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/index.tsx similarity index 100% rename from src/pages/ProjectPage/ProjectDetailsCard/index.tsx rename to src/features/Projects/pages/ProjectPage/ProjectDetailsCard/index.tsx diff --git a/src/pages/ProjectPage/VoteButton/VoteButton.stories.tsx b/src/features/Projects/pages/ProjectPage/VoteButton/VoteButton.stories.tsx similarity index 100% rename from src/pages/ProjectPage/VoteButton/VoteButton.stories.tsx rename to src/features/Projects/pages/ProjectPage/VoteButton/VoteButton.stories.tsx diff --git a/src/pages/ProjectPage/VoteButton/VoteButton.tsx b/src/features/Projects/pages/ProjectPage/VoteButton/VoteButton.tsx similarity index 100% rename from src/pages/ProjectPage/VoteButton/VoteButton.tsx rename to src/features/Projects/pages/ProjectPage/VoteButton/VoteButton.tsx diff --git a/src/pages/ProjectPage/VoteButton/vote-button.style.css b/src/features/Projects/pages/ProjectPage/VoteButton/vote-button.style.css similarity index 100% rename from src/pages/ProjectPage/VoteButton/vote-button.style.css rename to src/features/Projects/pages/ProjectPage/VoteButton/vote-button.style.css diff --git a/src/pages/ProjectPage/VoteCard/VoteCard.stories.tsx b/src/features/Projects/pages/ProjectPage/VoteCard/VoteCard.stories.tsx similarity index 100% rename from src/pages/ProjectPage/VoteCard/VoteCard.stories.tsx rename to src/features/Projects/pages/ProjectPage/VoteCard/VoteCard.stories.tsx diff --git a/src/pages/ProjectPage/VoteCard/VoteCard.tsx b/src/features/Projects/pages/ProjectPage/VoteCard/VoteCard.tsx similarity index 100% rename from src/pages/ProjectPage/VoteCard/VoteCard.tsx rename to src/features/Projects/pages/ProjectPage/VoteCard/VoteCard.tsx diff --git a/src/pages/ProjectPage/VoteCard/index.tsx b/src/features/Projects/pages/ProjectPage/VoteCard/index.tsx similarity index 100% rename from src/pages/ProjectPage/VoteCard/index.tsx rename to src/features/Projects/pages/ProjectPage/VoteCard/index.tsx diff --git a/src/pages/ProjectPage/VoteCard/style.module.css b/src/features/Projects/pages/ProjectPage/VoteCard/style.module.css similarity index 100% rename from src/pages/ProjectPage/VoteCard/style.module.css rename to src/features/Projects/pages/ProjectPage/VoteCard/style.module.css diff --git a/src/pages/ProjectPage/VoteCard/vote.graphql b/src/features/Projects/pages/ProjectPage/VoteCard/vote.graphql similarity index 100% rename from src/pages/ProjectPage/VoteCard/vote.graphql rename to src/features/Projects/pages/ProjectPage/VoteCard/vote.graphql diff --git a/src/features/Projects/types/index.ts b/src/features/Projects/types/index.ts new file mode 100644 index 0000000..f4629c3 --- /dev/null +++ b/src/features/Projects/types/index.ts @@ -0,0 +1 @@ +export * from './project.interfaces' \ No newline at end of file diff --git a/src/utils/interfaces/project.interfaces.ts b/src/features/Projects/types/project.interfaces.ts similarity index 94% rename from src/utils/interfaces/project.interfaces.ts rename to src/features/Projects/types/project.interfaces.ts index 682f8f5..dea9356 100644 --- a/src/utils/interfaces/project.interfaces.ts +++ b/src/features/Projects/types/project.interfaces.ts @@ -1,5 +1,5 @@ import { Project as ApiProject, Tag } from "src/graphql"; -import { Image } from "."; +import { Image } from "../../../utils/interfaces"; export interface Project { id: ApiProject['id']; diff --git a/src/redux/features/modals.slice.ts b/src/redux/features/modals.slice.ts index 5d13b01..fa12b2b 100644 --- a/src/redux/features/modals.slice.ts +++ b/src/redux/features/modals.slice.ts @@ -1,8 +1,8 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { Login_ScanningWalletCard, Login_ExternalWalletCard, Login_NativeWalletCard, Login_SuccessCard } from "src/Components/Modals/Login"; -import { ProjectDetailsCard } from "src/pages/ProjectPage/ProjectDetailsCard"; -import VoteCard from "src/pages/ProjectPage/VoteCard/VoteCard"; -import { Claim_FundWithdrawCard, Claim_CopySignatureCard, Claim_GenerateSignatureCard, Claim_SubmittedCard } from "src/pages/ProjectPage/ClaimProject"; +import { ProjectDetailsCard } from "src/features/Projects/pages/ProjectPage/ProjectDetailsCard"; +import VoteCard from "src/features/Projects/pages/ProjectPage/VoteCard/VoteCard"; +import { Claim_FundWithdrawCard, Claim_CopySignatureCard, Claim_GenerateSignatureCard, Claim_SubmittedCard } from "src/features/Projects/pages/ProjectPage/ClaimProject"; import { ModalCard } from "src/Components/Modals/ModalsContainer/ModalsContainer"; import { ComponentProps } from "react"; diff --git a/src/utils/interfaces/index.ts b/src/utils/interfaces/index.ts index c62ce17..fb1638f 100644 --- a/src/utils/interfaces/index.ts +++ b/src/utils/interfaces/index.ts @@ -1,4 +1,4 @@ export * from './misc.interfaces' -export * from './project.interfaces' +export * from 'src/features/Projects/types' From 3441aee98eae27580eda2e54eabfcd56e32d0e73 Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Sun, 17 Apr 2022 14:46:32 +0300 Subject: [PATCH 07/90] fix: update bounty card styles --- .../Posts/Components/PostCard/BountyCard.tsx | 14 +++++++++----- .../Posts/Components/PostCard/QuestionCard.tsx | 2 +- .../Posts/Components/PostCard/StoryCard.tsx | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/features/Posts/Components/PostCard/BountyCard.tsx b/src/features/Posts/Components/PostCard/BountyCard.tsx index 7db5dad..0bdce44 100644 --- a/src/features/Posts/Components/PostCard/BountyCard.tsx +++ b/src/features/Posts/Components/PostCard/BountyCard.tsx @@ -11,21 +11,25 @@ interface Props { export default function BountyCard({ bounty }: Props) { return (
- +
-

{bounty.title}

-
+

Bounty - {bounty.reward_amount} sats -

+ {bounty.title} + +
+
+ Reward: + {bounty.reward_amount} sats +

{bounty.excerpt}

diff --git a/src/features/Posts/Components/PostCard/QuestionCard.tsx b/src/features/Posts/Components/PostCard/QuestionCard.tsx index e69f32a..60b073e 100644 --- a/src/features/Posts/Components/PostCard/QuestionCard.tsx +++ b/src/features/Posts/Components/PostCard/QuestionCard.tsx @@ -17,7 +17,7 @@ export default function QuestionCard({ question }: Props) {
-

{question.title}

+

{question.title}

{question.excerpt}

diff --git a/src/features/Posts/Components/PostCard/StoryCard.tsx b/src/features/Posts/Components/PostCard/StoryCard.tsx index fc92399..10af4e4 100644 --- a/src/features/Posts/Components/PostCard/StoryCard.tsx +++ b/src/features/Posts/Components/PostCard/StoryCard.tsx @@ -12,7 +12,7 @@ export default function StoryCard({ story }: Props) {
-

{story.title}

+

{story.title}

{story.excerpt}


From 72144d61e7983981178920527982861b1c82c854 Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Sun, 17 Apr 2022 15:46:28 +0300 Subject: [PATCH 08/90] feat: Build Feed Page, Built Feed filters cards --- .storybook/preview.js | 18 +++++- .../TrendingCard/TrendingCard.stories.tsx | 20 ++++++ .../Components/TrendingCard/TrendingCard.tsx | 61 +++++++++++++++++++ .../Posts/pages/FeedPage/FeedPage.stories.tsx | 20 ++++++ .../Posts/pages/FeedPage/FeedPage.tsx | 29 ++++++++- .../PopularCategories.stories.tsx | 20 ++++++ .../PopularCategories/PopularCategories.tsx | 54 ++++++++++++++++ .../pages/FeedPage/SortBy/SortBy.stories.tsx | 20 ++++++ .../Posts/pages/FeedPage/SortBy/SortBy.tsx | 45 ++++++++++++++ src/index.css | 8 +++ 10 files changed, 293 insertions(+), 2 deletions(-) create mode 100644 src/features/Posts/Components/TrendingCard/TrendingCard.stories.tsx create mode 100644 src/features/Posts/Components/TrendingCard/TrendingCard.tsx create mode 100644 src/features/Posts/pages/FeedPage/FeedPage.stories.tsx create mode 100644 src/features/Posts/pages/FeedPage/PopularCategories/PopularCategories.stories.tsx create mode 100644 src/features/Posts/pages/FeedPage/PopularCategories/PopularCategories.tsx create mode 100644 src/features/Posts/pages/FeedPage/SortBy/SortBy.stories.tsx create mode 100644 src/features/Posts/pages/FeedPage/SortBy/SortBy.tsx diff --git a/.storybook/preview.js b/.storybook/preview.js index 510d86a..164314a 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -1,5 +1,5 @@ import "../src/index.css"; -import { configure, addDecorator } from "@storybook/react"; +import { configure, addDecorator, addParameters } from "@storybook/react"; import { WrapperDecorator, AppDecorator } from 'src/utils/storybook/decorators' @@ -20,6 +20,22 @@ addDecorator(AppDecorator); addDecorator(WrapperDecorator); +addParameters({ + backgrounds: { + + default: 'light', + values: [ + { + name: 'light', + value: '#F8FAFC', + }, + { + name: 'dark', + value: '#3f3f4c', + }, + ], + } +}); configure(require.context("../src", true, /\.stories\.ts$/), module); diff --git a/src/features/Posts/Components/TrendingCard/TrendingCard.stories.tsx b/src/features/Posts/Components/TrendingCard/TrendingCard.stories.tsx new file mode 100644 index 0000000..6938216 --- /dev/null +++ b/src/features/Posts/Components/TrendingCard/TrendingCard.stories.tsx @@ -0,0 +1,20 @@ +import { ComponentStory, ComponentMeta } from '@storybook/react'; + +import TrendingCard from './TrendingCard'; + +export default { + title: 'Posts/Components/TrendingCard', + component: TrendingCard, + argTypes: { + backgroundColor: { control: 'color' }, + }, +} as ComponentMeta; + + +const Template: ComponentStory = (args) =>
+ +export const Default = Template.bind({}); +Default.args = { +} + + diff --git a/src/features/Posts/Components/TrendingCard/TrendingCard.tsx b/src/features/Posts/Components/TrendingCard/TrendingCard.tsx new file mode 100644 index 0000000..d4c6cc4 --- /dev/null +++ b/src/features/Posts/Components/TrendingCard/TrendingCard.tsx @@ -0,0 +1,61 @@ +import React from 'react' +import { Link } from 'react-router-dom' +import Avatar from 'src/features/Profiles/Components/Avatar/Avatar' +import { Author } from '../../types' + +const data = [ + { + id: 1, + title: 'How to collect donations within lightning network?', + author: { + id: 2, + name: "John Doe", + image: "https://i.pravatar.cc/150?img=2" + } as Author + }, + { + id: 2, + title: 'How to implement the RSMC part of Lightning network?', + author: { + id: 2, + name: "John Doe", + image: "https://i.pravatar.cc/150?img=2" + } as Author + }, + { + id: 3, + title: 'c-lightning public node data on explorers', + author: { + id: 2, + name: "John Doe", + image: "https://i.pravatar.cc/150?img=2" + } as Author + }, + { + id: 4, + title: 'How to find all nodes and connections in LN?', + author: { + id: 2, + name: "John Doe", + image: "https://i.pravatar.cc/150?img=2" + } as Author + }, +] + +export default function TrendingCard() { + return ( +
+

Trending on BOLT.FUN

+
    + {data.map(post => + +
  • + +

    {post.title}

    +
  • + + )} +
+
+ ) +} diff --git a/src/features/Posts/pages/FeedPage/FeedPage.stories.tsx b/src/features/Posts/pages/FeedPage/FeedPage.stories.tsx new file mode 100644 index 0000000..7fa6c68 --- /dev/null +++ b/src/features/Posts/pages/FeedPage/FeedPage.stories.tsx @@ -0,0 +1,20 @@ +import { ComponentStory, ComponentMeta } from '@storybook/react'; + +import FeedPage from './FeedPage'; + +export default { + title: 'Posts/FeedPage', + component: FeedPage, + argTypes: { + backgroundColor: { control: 'color' }, + }, +} as ComponentMeta; + + +const Template: ComponentStory = (args) => + +export const Default = Template.bind({}); +Default.args = { +} + + diff --git a/src/features/Posts/pages/FeedPage/FeedPage.tsx b/src/features/Posts/pages/FeedPage/FeedPage.tsx index 3deda80..728dfdd 100644 --- a/src/features/Posts/pages/FeedPage/FeedPage.tsx +++ b/src/features/Posts/pages/FeedPage/FeedPage.tsx @@ -1 +1,28 @@ -export { } \ No newline at end of file + +import React from 'react' +import { MOCK_DATA } from 'src/mocks/data' +import PostsList from '../../Components/PostsList/PostsList' +import TrendingCard from '../../Components/TrendingCard/TrendingCard' +import PopularCategories from './PopularCategories/PopularCategories' +import SortBy from './SortBy/SortBy' + +export default function FeedPage() { + return ( +
+
+ +
+ +
+ +
+ +
+
+ ) +} diff --git a/src/features/Posts/pages/FeedPage/PopularCategories/PopularCategories.stories.tsx b/src/features/Posts/pages/FeedPage/PopularCategories/PopularCategories.stories.tsx new file mode 100644 index 0000000..47024da --- /dev/null +++ b/src/features/Posts/pages/FeedPage/PopularCategories/PopularCategories.stories.tsx @@ -0,0 +1,20 @@ +import { ComponentStory, ComponentMeta } from '@storybook/react'; + +import PopularCategories from './PopularCategories'; + +export default { + title: 'Posts/FeedPage/Components/PopularCategories', + component: PopularCategories, + argTypes: { + backgroundColor: { control: 'color' }, + }, +} as ComponentMeta; + + +const Template: ComponentStory = (args) =>
+ +export const Default = Template.bind({}); +Default.args = { +} + + diff --git a/src/features/Posts/pages/FeedPage/PopularCategories/PopularCategories.tsx b/src/features/Posts/pages/FeedPage/PopularCategories/PopularCategories.tsx new file mode 100644 index 0000000..ea3adac --- /dev/null +++ b/src/features/Posts/pages/FeedPage/PopularCategories/PopularCategories.tsx @@ -0,0 +1,54 @@ +import React, { useState } from 'react' + +const filters = [ + { + text: "🔥 All", + value: 'all' + }, { + text: "Lightning Network", + value: 'lightning-network' + }, { + text: "Bitcoin", + value: 'bitcoin' + }, { + text: "Cybersecurity", + value: 'cybersecurity' + }, { + text: "Bounties", + value: 'bounties' + }, { + text: "Grants", + value: 'Grants' + }, +] + +interface Props { + filterChanged?: (newFilter: string) => void +} + +export default function PopularCategories({ filterChanged }: Props) { + + const [selected, setSelected] = useState(filters[0].value); + + const filterClicked = (newValue: string) => { + if (selected === newValue) + return + setSelected(newValue); + filterChanged?.(newValue); + } + + return ( +
+

Popular Categories

+
    + {filters.map((f, idx) =>
  • filterClicked(f.value)} + > + {f.text} +
  • )} +
+
+ ) +} diff --git a/src/features/Posts/pages/FeedPage/SortBy/SortBy.stories.tsx b/src/features/Posts/pages/FeedPage/SortBy/SortBy.stories.tsx new file mode 100644 index 0000000..9ec18b5 --- /dev/null +++ b/src/features/Posts/pages/FeedPage/SortBy/SortBy.stories.tsx @@ -0,0 +1,20 @@ +import { ComponentStory, ComponentMeta } from '@storybook/react'; + +import SortBy from './SortBy'; + +export default { + title: 'Posts/FeedPage/Components/SortBy', + component: SortBy, + argTypes: { + backgroundColor: { control: 'color' }, + }, +} as ComponentMeta; + + +const Template: ComponentStory = (args) =>
+ +export const Default = Template.bind({}); +Default.args = { +} + + diff --git a/src/features/Posts/pages/FeedPage/SortBy/SortBy.tsx b/src/features/Posts/pages/FeedPage/SortBy/SortBy.tsx new file mode 100644 index 0000000..265a7b9 --- /dev/null +++ b/src/features/Posts/pages/FeedPage/SortBy/SortBy.tsx @@ -0,0 +1,45 @@ +import React, { useState } from 'react' + +const filters = [ + { + text: "🔥 Popular", + value: 'popular' + }, { + text: "📆 Newest", + value: 'newest' + }, { + text: "🎭 Trending", + value: 'trending' + }, +] + +interface Props { + filterChanged?: (newFilter: string) => void +} + +export default function SortBy({ filterChanged }: Props) { + + const [selected, setSelected] = useState(filters[0].value); + + const filterClicked = (newValue: string) => { + if (selected === newValue) + return + setSelected(newValue); + filterChanged?.(newValue); + } + + return ( +
+

Sort By

+
    + {filters.map((f, idx) =>
  • filterClicked(f.value)} + > + {f.text} +
  • )} +
+
+ ) +} diff --git a/src/index.css b/src/index.css index 89dcaaf..91aa6dd 100644 --- a/src/index.css +++ b/src/index.css @@ -38,12 +38,20 @@ .modal-card { @apply rounded-[40px] bg-gray-50 overflow-hidden w-full shadow-2xl z-10; } + + } body { overflow-x: hidden; } +.page-container{ + width: 98%; + margin: 0 auto; + max-width: 1440px; +} + svg { display: inline-block; } From 83652b09a679d98d9dbff24d96ecf396879e0ba9 Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Sun, 17 Apr 2022 16:10:01 +0300 Subject: [PATCH 09/90] fix: feed layout style --- src/features/Posts/pages/FeedPage/FeedPage.tsx | 16 +++++++--------- .../Posts/pages/FeedPage/styles.module.css | 13 +++++++++++++ 2 files changed, 20 insertions(+), 9 deletions(-) create mode 100644 src/features/Posts/pages/FeedPage/styles.module.css diff --git a/src/features/Posts/pages/FeedPage/FeedPage.tsx b/src/features/Posts/pages/FeedPage/FeedPage.tsx index 728dfdd..be484bd 100644 --- a/src/features/Posts/pages/FeedPage/FeedPage.tsx +++ b/src/features/Posts/pages/FeedPage/FeedPage.tsx @@ -1,28 +1,26 @@ -import React from 'react' import { MOCK_DATA } from 'src/mocks/data' import PostsList from '../../Components/PostsList/PostsList' import TrendingCard from '../../Components/TrendingCard/TrendingCard' import PopularCategories from './PopularCategories/PopularCategories' import SortBy from './SortBy/SortBy' +import styles from './styles.module.css' export default function FeedPage() { return (
-
+
+ -
+
+
) } diff --git a/src/features/Posts/pages/FeedPage/styles.module.css b/src/features/Posts/pages/FeedPage/styles.module.css new file mode 100644 index 0000000..20b9de8 --- /dev/null +++ b/src/features/Posts/pages/FeedPage/styles.module.css @@ -0,0 +1,13 @@ +.grid{ + grid-template-columns: 1fr 2fr 1fr; +} + +@media screen and (max-width:680px) { + aside{ + display: none; + } + + .grid{ + grid-template-columns: 1fr; + } +} \ No newline at end of file From c75777f5a899229e3574a00139e700fa516a26f7 Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Mon, 18 Apr 2022 14:16:55 +0300 Subject: [PATCH 10/90] feat: Add useReachedBottom hook, add post card skeleton, clean-up Post Card components --- package-lock.json | 19 ++++++++++ package.json | 1 + .../{ => BountyCard}/BountyCard.stories.tsx | 0 .../PostCard/{ => BountyCard}/BountyCard.tsx | 2 +- .../PostCard/Header/Header.Skeleton.tsx | 24 ++++++++++++ .../PostCard/{ => Header}/Header.tsx | 0 .../PostCard/PostCard/PostCard.Skeleton.tsx | 29 ++++++++++++++ .../PostCard/PostCard/PostCard.stories.tsx | 29 ++++++++++++++ .../PostCard/{ => PostCard}/PostCard.tsx | 6 +-- .../QuestionCard.stories.tsx | 0 .../{ => QuestionCard}/QuestionCard.tsx | 2 +- .../{ => StoryCard}/StoryCard.stories.tsx | 0 .../PostCard/{ => StoryCard}/StoryCard.tsx | 2 +- .../Posts/Components/PostCard/index.tsx | 5 ++- .../PostsList/PostsList.stories.tsx | 2 +- .../Posts/Components/PostsList/PostsList.tsx | 38 +++++++++++++------ .../Posts/pages/FeedPage/FeedPage.tsx | 7 +++- src/utils/hooks/useReachedBottom.ts | 30 +++++++++++++++ src/utils/interfaces/misc.interfaces.ts | 8 ++++ 19 files changed, 183 insertions(+), 21 deletions(-) rename src/features/Posts/Components/PostCard/{ => BountyCard}/BountyCard.stories.tsx (100%) rename src/features/Posts/Components/PostCard/{ => BountyCard}/BountyCard.tsx (98%) create mode 100644 src/features/Posts/Components/PostCard/Header/Header.Skeleton.tsx rename src/features/Posts/Components/PostCard/{ => Header}/Header.tsx (100%) create mode 100644 src/features/Posts/Components/PostCard/PostCard/PostCard.Skeleton.tsx create mode 100644 src/features/Posts/Components/PostCard/PostCard/PostCard.stories.tsx rename src/features/Posts/Components/PostCard/{ => PostCard}/PostCard.tsx (70%) rename src/features/Posts/Components/PostCard/{ => QuestionCard}/QuestionCard.stories.tsx (100%) rename src/features/Posts/Components/PostCard/{ => QuestionCard}/QuestionCard.tsx (98%) rename src/features/Posts/Components/PostCard/{ => StoryCard}/StoryCard.stories.tsx (100%) rename src/features/Posts/Components/PostCard/{ => StoryCard}/StoryCard.tsx (96%) create mode 100644 src/utils/hooks/useReachedBottom.ts diff --git a/package-lock.json b/package-lock.json index c8cb542..ba3cfcf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -67,6 +67,7 @@ "@storybook/node-logger": "^6.3.12", "@storybook/preset-create-react-app": "^3.2.0", "@storybook/react": "^6.3.12", + "@types/lodash.debounce": "^4.0.6", "@types/lodash.throttle": "^4.1.6", "@types/react-copy-to-clipboard": "^5.0.2", "autoprefixer": "^9.8.8", @@ -9612,6 +9613,15 @@ "integrity": "sha512-0fDwydE2clKe9MNfvXHBHF9WEahRuj+msTuQqOmAApNORFvhMYZKNGGJdCzuhheVjMps/ti0Ak/iJPACMaevvw==", "dev": true }, + "node_modules/@types/lodash.debounce": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.6.tgz", + "integrity": "sha512-4WTmnnhCfDvvuLMaF3KV4Qfki93KebocUF45msxhYyjMttZDQYzHkO639ohhk8+oco2cluAFL3t5+Jn4mleylQ==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/lodash.throttle": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/@types/lodash.throttle/-/lodash.throttle-4.1.6.tgz", @@ -68051,6 +68061,15 @@ "integrity": "sha512-0fDwydE2clKe9MNfvXHBHF9WEahRuj+msTuQqOmAApNORFvhMYZKNGGJdCzuhheVjMps/ti0Ak/iJPACMaevvw==", "dev": true }, + "@types/lodash.debounce": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.6.tgz", + "integrity": "sha512-4WTmnnhCfDvvuLMaF3KV4Qfki93KebocUF45msxhYyjMttZDQYzHkO639ohhk8+oco2cluAFL3t5+Jn4mleylQ==", + "dev": true, + "requires": { + "@types/lodash": "*" + } + }, "@types/lodash.throttle": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/@types/lodash.throttle/-/lodash.throttle-4.1.6.tgz", diff --git a/package.json b/package.json index 4f9f345..3286bf5 100644 --- a/package.json +++ b/package.json @@ -117,6 +117,7 @@ "@storybook/node-logger": "^6.3.12", "@storybook/preset-create-react-app": "^3.2.0", "@storybook/react": "^6.3.12", + "@types/lodash.debounce": "^4.0.6", "@types/lodash.throttle": "^4.1.6", "@types/react-copy-to-clipboard": "^5.0.2", "autoprefixer": "^9.8.8", diff --git a/src/features/Posts/Components/PostCard/BountyCard.stories.tsx b/src/features/Posts/Components/PostCard/BountyCard/BountyCard.stories.tsx similarity index 100% rename from src/features/Posts/Components/PostCard/BountyCard.stories.tsx rename to src/features/Posts/Components/PostCard/BountyCard/BountyCard.stories.tsx diff --git a/src/features/Posts/Components/PostCard/BountyCard.tsx b/src/features/Posts/Components/PostCard/BountyCard/BountyCard.tsx similarity index 98% rename from src/features/Posts/Components/PostCard/BountyCard.tsx rename to src/features/Posts/Components/PostCard/BountyCard/BountyCard.tsx index 0bdce44..736116e 100644 --- a/src/features/Posts/Components/PostCard/BountyCard.tsx +++ b/src/features/Posts/Components/PostCard/BountyCard/BountyCard.tsx @@ -1,6 +1,6 @@ import VotesCount from "src/Components/VotesCount/VotesCount" import { Bounty } from "src/features/Posts/types" -import Header from "./Header" +import Header from "../Header/Header" import { FiUsers } from "react-icons/fi" import Badge from "src/Components/Badge/Badge" import Button from "src/Components/Button/Button" diff --git a/src/features/Posts/Components/PostCard/Header/Header.Skeleton.tsx b/src/features/Posts/Components/PostCard/Header/Header.Skeleton.tsx new file mode 100644 index 0000000..9917276 --- /dev/null +++ b/src/features/Posts/Components/PostCard/Header/Header.Skeleton.tsx @@ -0,0 +1,24 @@ +import Avatar from 'src/features/Profiles/Components/Avatar/Avatar'; +import dayjs from 'dayjs' +import Skeleton from 'react-loading-skeleton'; + +interface Props { + size?: 'sm' | 'md' +} + +export default function HeaderSkeleton({ size = 'md', }: Props) { + + return ( +
+ +
+

+ +

+

+ +

+
+
+ ) +} diff --git a/src/features/Posts/Components/PostCard/Header.tsx b/src/features/Posts/Components/PostCard/Header/Header.tsx similarity index 100% rename from src/features/Posts/Components/PostCard/Header.tsx rename to src/features/Posts/Components/PostCard/Header/Header.tsx diff --git a/src/features/Posts/Components/PostCard/PostCard/PostCard.Skeleton.tsx b/src/features/Posts/Components/PostCard/PostCard/PostCard.Skeleton.tsx new file mode 100644 index 0000000..9fab751 --- /dev/null +++ b/src/features/Posts/Components/PostCard/PostCard/PostCard.Skeleton.tsx @@ -0,0 +1,29 @@ +import Skeleton from "react-loading-skeleton" +import HeaderSkeleton from "../Header/Header.Skeleton" +import Badge from 'src/Components/Badge/Badge' + +export default function PostCardSkeleton() { + return
+
+ +
+
+ +

+ +

+

+ + +

+ +
+
+ +
+ +
+
+
+
+} diff --git a/src/features/Posts/Components/PostCard/PostCard/PostCard.stories.tsx b/src/features/Posts/Components/PostCard/PostCard/PostCard.stories.tsx new file mode 100644 index 0000000..bc31427 --- /dev/null +++ b/src/features/Posts/Components/PostCard/PostCard/PostCard.stories.tsx @@ -0,0 +1,29 @@ +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { MOCK_DATA } from 'src/mocks/data'; + +import PostCard from './PostCard'; +import PostCardSkeleton from './PostCard.Skeleton'; + +export default { + title: 'Posts/Components/PostCard', + component: PostCard, + argTypes: { + backgroundColor: { control: 'color' }, + }, +} as ComponentMeta; + + +const Template: ComponentStory = (args) =>
+ +export const Default = Template.bind({}); +Default.args = { + post: MOCK_DATA['posts'].stories[0] +} + +const LoadingTemplate: ComponentStory = (args) =>
+ +export const Loading = LoadingTemplate.bind({}); +Loading.args = { +} + + diff --git a/src/features/Posts/Components/PostCard/PostCard.tsx b/src/features/Posts/Components/PostCard/PostCard/PostCard.tsx similarity index 70% rename from src/features/Posts/Components/PostCard/PostCard.tsx rename to src/features/Posts/Components/PostCard/PostCard/PostCard.tsx index bf0802e..324df10 100644 --- a/src/features/Posts/Components/PostCard/PostCard.tsx +++ b/src/features/Posts/Components/PostCard/PostCard/PostCard.tsx @@ -1,7 +1,7 @@ import { Post, isStory, isBounty, isQuestion } from "src/features/Posts/types" -import BountyCard from "./BountyCard" -import QuestionCard from "./QuestionCard" -import StoryCard from "./StoryCard" +import BountyCard from "../BountyCard/BountyCard" +import QuestionCard from "../QuestionCard/QuestionCard" +import StoryCard from "../StoryCard/StoryCard" type Props = { post: Post diff --git a/src/features/Posts/Components/PostCard/QuestionCard.stories.tsx b/src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.stories.tsx similarity index 100% rename from src/features/Posts/Components/PostCard/QuestionCard.stories.tsx rename to src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.stories.tsx diff --git a/src/features/Posts/Components/PostCard/QuestionCard.tsx b/src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.tsx similarity index 98% rename from src/features/Posts/Components/PostCard/QuestionCard.tsx rename to src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.tsx index 60b073e..47eca06 100644 --- a/src/features/Posts/Components/PostCard/QuestionCard.tsx +++ b/src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.tsx @@ -1,6 +1,6 @@ import VotesCount from "src/Components/VotesCount/VotesCount" import { Question } from "src/features/Posts/types" -import Header from "./Header" +import Header from "../Header/Header" import { FiUsers } from "react-icons/fi" import Badge from "src/Components/Badge/Badge" import Avatar from "src/features/Profiles/Components/Avatar/Avatar" diff --git a/src/features/Posts/Components/PostCard/StoryCard.stories.tsx b/src/features/Posts/Components/PostCard/StoryCard/StoryCard.stories.tsx similarity index 100% rename from src/features/Posts/Components/PostCard/StoryCard.stories.tsx rename to src/features/Posts/Components/PostCard/StoryCard/StoryCard.stories.tsx diff --git a/src/features/Posts/Components/PostCard/StoryCard.tsx b/src/features/Posts/Components/PostCard/StoryCard/StoryCard.tsx similarity index 96% rename from src/features/Posts/Components/PostCard/StoryCard.tsx rename to src/features/Posts/Components/PostCard/StoryCard/StoryCard.tsx index 10af4e4..aa5f3df 100644 --- a/src/features/Posts/Components/PostCard/StoryCard.tsx +++ b/src/features/Posts/Components/PostCard/StoryCard/StoryCard.tsx @@ -1,6 +1,6 @@ import VotesCount from "src/Components/VotesCount/VotesCount" import { Story } from "src/features/Posts/types" -import Header from "./Header" +import Header from "../Header/Header" import { BiComment } from 'react-icons/bi' interface Props { diff --git a/src/features/Posts/Components/PostCard/index.tsx b/src/features/Posts/Components/PostCard/index.tsx index bcdab81..dbbd0ac 100644 --- a/src/features/Posts/Components/PostCard/index.tsx +++ b/src/features/Posts/Components/PostCard/index.tsx @@ -1,2 +1,5 @@ +import PostCard from "./PostCard/PostCard"; -export { } \ No newline at end of file +export { default as PostCardSkeleton } from './PostCard/PostCard.Skeleton' + +export default PostCard; \ No newline at end of file diff --git a/src/features/Posts/Components/PostsList/PostsList.stories.tsx b/src/features/Posts/Components/PostsList/PostsList.stories.tsx index f34894c..4bb226b 100644 --- a/src/features/Posts/Components/PostsList/PostsList.stories.tsx +++ b/src/features/Posts/Components/PostsList/PostsList.stories.tsx @@ -16,7 +16,7 @@ const Template: ComponentStory = (args) =>
export default function PostsList(props: Props) { - const { data, loading } = useFeedQuery() - if (loading) return

Loading

- return ( -
- { - data?.getFeed.map(post => ) + + const reachedBottom = useCallback(() => { + console.log("NEW FETCH") + }, []) + + const { ref } = useReachedBottom(reachedBottom) + + if (props.isLoading) + return
+ {<> + + + + }
+ + return ( +
+ { + props.items?.map(post => ) + } + {props.isFetching && } +
) } diff --git a/src/features/Posts/pages/FeedPage/FeedPage.tsx b/src/features/Posts/pages/FeedPage/FeedPage.tsx index be484bd..282f0f8 100644 --- a/src/features/Posts/pages/FeedPage/FeedPage.tsx +++ b/src/features/Posts/pages/FeedPage/FeedPage.tsx @@ -1,4 +1,5 @@ +import { useFeedQuery } from 'src/graphql' import { MOCK_DATA } from 'src/mocks/data' import PostsList from '../../Components/PostsList/PostsList' import TrendingCard from '../../Components/TrendingCard/TrendingCard' @@ -7,17 +8,19 @@ import SortBy from './SortBy/SortBy' import styles from './styles.module.css' export default function FeedPage() { + + const feedQuery = useFeedQuery() + return (
- + diff --git a/src/utils/hooks/useReachedBottom.ts b/src/utils/hooks/useReachedBottom.ts new file mode 100644 index 0000000..1837ef6 --- /dev/null +++ b/src/utils/hooks/useReachedBottom.ts @@ -0,0 +1,30 @@ +import _debounce from "lodash.debounce"; +import { useEffect, useRef } from "react"; + +export const useReachedBottom = (cb?: () => void, options: Partial<{ offset: number, throttle: number }> = {}) => { + + const { offset = window.innerHeight, throttle = 600 } = options + + const ref = useRef(null); + + + useEffect(() => { + if (!cb) return; + + const cbDebounced = _debounce(cb, throttle) + const listener = () => { + if (!ref.current) return; + const curWindowPosition = window.scrollY + window.innerHeight; + const elTriggerPosition = ref.current.offsetTop + ref.current.scrollHeight - offset; + if (curWindowPosition > elTriggerPosition) cbDebounced(); + } + + document.addEventListener('scroll', listener) + + return () => { + document.removeEventListener('scroll', listener) + } + }, [cb, offset, throttle]) + + return { ref } +} \ No newline at end of file diff --git a/src/utils/interfaces/misc.interfaces.ts b/src/utils/interfaces/misc.interfaces.ts index d810cbb..2831c9c 100644 --- a/src/utils/interfaces/misc.interfaces.ts +++ b/src/utils/interfaces/misc.interfaces.ts @@ -4,4 +4,12 @@ export type Tag = { title: string } + +export type ListProps = { + items?: T[] + isLoading?: boolean; + isFetching?: boolean; + onReachedBottom?: () => void +} + export type Image = string; \ No newline at end of file From 1a13cd6c3c824dde3a80b4a274e13c52e6a0e760 Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Mon, 18 Apr 2022 14:39:42 +0300 Subject: [PATCH 11/90] feat: make filters sticky --- .../Components/PostCard/BountyCard/BountyCard.tsx | 15 +++++++++------ .../PostCard/QuestionCard/QuestionCard.tsx | 4 +++- .../Components/PostCard/StoryCard/StoryCard.tsx | 5 ++++- src/features/Posts/pages/FeedPage/FeedPage.tsx | 12 ++++++++---- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/features/Posts/Components/PostCard/BountyCard/BountyCard.tsx b/src/features/Posts/Components/PostCard/BountyCard/BountyCard.tsx index 736116e..cef4220 100644 --- a/src/features/Posts/Components/PostCard/BountyCard/BountyCard.tsx +++ b/src/features/Posts/Components/PostCard/BountyCard/BountyCard.tsx @@ -4,6 +4,7 @@ import Header from "../Header/Header" import { FiUsers } from "react-icons/fi" import Badge from "src/Components/Badge/Badge" import Button from "src/Components/Button/Button" +import { Link } from "react-router-dom" interface Props { bounty: Bounty @@ -14,15 +15,17 @@ export default function BountyCard({ bounty }: Props) {
-
+
-

- Bounty - {bounty.title} -

+ + +

+ Bounty {bounty.title} +

+
-
diff --git a/src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.tsx b/src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.tsx index 47eca06..a5a366d 100644 --- a/src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.tsx +++ b/src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.tsx @@ -17,7 +17,9 @@ export default function QuestionCard({ question }: Props) {
-

{question.title}

+ +

{question.title}

+

{question.excerpt}

diff --git a/src/features/Posts/Components/PostCard/StoryCard/StoryCard.tsx b/src/features/Posts/Components/PostCard/StoryCard/StoryCard.tsx index aa5f3df..babe031 100644 --- a/src/features/Posts/Components/PostCard/StoryCard/StoryCard.tsx +++ b/src/features/Posts/Components/PostCard/StoryCard/StoryCard.tsx @@ -2,6 +2,7 @@ import VotesCount from "src/Components/VotesCount/VotesCount" import { Story } from "src/features/Posts/types" import Header from "../Header/Header" import { BiComment } from 'react-icons/bi' +import { Link } from "react-router-dom" interface Props { story: Story @@ -12,7 +13,9 @@ export default function StoryCard({ story }: Props) {
-

{story.title}

+ +

{story.title}

+

{story.excerpt}


diff --git a/src/features/Posts/pages/FeedPage/FeedPage.tsx b/src/features/Posts/pages/FeedPage/FeedPage.tsx index 282f0f8..81c2c89 100644 --- a/src/features/Posts/pages/FeedPage/FeedPage.tsx +++ b/src/features/Posts/pages/FeedPage/FeedPage.tsx @@ -16,13 +16,17 @@ export default function FeedPage() { className={`page-container grid w-full gap-32 ${styles.grid}`} >
) From 1f817c8a79c5cb669d2f410c45dea4297d841058 Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Mon, 18 Apr 2022 16:37:59 +0300 Subject: [PATCH 12/90] feat: added infinite scroll to feed page --- .../Posts/Components/PostsList/PostsList.tsx | 11 ++---- .../Posts/pages/FeedPage/FeedPage.tsx | 18 +++++++-- .../Posts/pages/FeedPage/feed.graphql | 4 +- src/graphql/index.tsx | 11 ++++-- src/mocks/data/posts.ts | 8 ++-- src/mocks/handlers.ts | 7 ++-- src/mocks/resolvers.ts | 8 ++-- src/utils/apollo.ts | 39 ++++++++++++++++++- src/utils/hooks/index.ts | 2 + src/utils/hooks/useInfiniteQuery.ts | 34 ++++++++++++++++ src/utils/hooks/useReachedBottom.ts | 17 +++++--- src/utils/interfaces/misc.interfaces.ts | 2 +- 12 files changed, 125 insertions(+), 36 deletions(-) create mode 100644 src/utils/hooks/useInfiniteQuery.ts diff --git a/src/features/Posts/Components/PostsList/PostsList.tsx b/src/features/Posts/Components/PostsList/PostsList.tsx index 383f97a..d983037 100644 --- a/src/features/Posts/Components/PostsList/PostsList.tsx +++ b/src/features/Posts/Components/PostsList/PostsList.tsx @@ -1,19 +1,14 @@ import { useCallback } from "react" import { Post } from "src/features/Posts/types" import { useReachedBottom } from "src/utils/hooks/useReachedBottom" -import { ListProps } from "src/utils/interfaces" +import { ListComponentProps } from "src/utils/interfaces" import PostCard, { PostCardSkeleton } from "../PostCard" -type Props = ListProps +type Props = ListComponentProps export default function PostsList(props: Props) { - - const reachedBottom = useCallback(() => { - console.log("NEW FETCH") - }, []) - - const { ref } = useReachedBottom(reachedBottom) + const { ref } = useReachedBottom(props.onReachedBottom) if (props.isLoading) return
diff --git a/src/features/Posts/pages/FeedPage/FeedPage.tsx b/src/features/Posts/pages/FeedPage/FeedPage.tsx index 81c2c89..c72d99d 100644 --- a/src/features/Posts/pages/FeedPage/FeedPage.tsx +++ b/src/features/Posts/pages/FeedPage/FeedPage.tsx @@ -1,15 +1,22 @@ import { useFeedQuery } from 'src/graphql' -import { MOCK_DATA } from 'src/mocks/data' +import { useInfiniteQuery } from 'src/utils/hooks' import PostsList from '../../Components/PostsList/PostsList' import TrendingCard from '../../Components/TrendingCard/TrendingCard' import PopularCategories from './PopularCategories/PopularCategories' import SortBy from './SortBy/SortBy' import styles from './styles.module.css' + export default function FeedPage() { - const feedQuery = useFeedQuery() + const feedQuery = useFeedQuery({ + variables: { + take: 10, + skip: 0 + } + }) + const { fetchMore, isFetchingMore } = useInfiniteQuery(feedQuery, 'getFeed') return (
- +
; From 518828c5a49902c7196b342432431c9ac1696846 Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Tue, 19 Apr 2022 10:44:21 +0300 Subject: [PATCH 15/90] fix: fixed sticky filters --- src/App.tsx | 4 +-- src/Components/Navbar/Navbar.tsx | 7 ++++++ .../Posts/pages/FeedPage/FeedPage.tsx | 25 ++++++++++++++----- src/index.css | 11 +++++--- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index c34c872..d3559a2 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -35,12 +35,12 @@ function App() { - return
+ return
} /> } /> - } /> + } /> } /> diff --git a/src/Components/Navbar/Navbar.tsx b/src/Components/Navbar/Navbar.tsx index 20283aa..428dff6 100644 --- a/src/Components/Navbar/Navbar.tsx +++ b/src/Components/Navbar/Navbar.tsx @@ -9,6 +9,7 @@ import { useResizeListener } from "src/utils/hooks"; import NavDesktop from "./NavDesktop"; import { useMediaQuery } from "@react-hookz/web"; import { MEDIA_QUERIES } from "src/utils/theme/media_queries"; +import { BiComment } from "react-icons/bi"; export const navLinks = [ { text: "Explore", url: "/", icon: MdHomeFilled, color: "text-primary-600" }, @@ -18,6 +19,12 @@ export const navLinks = [ icon: MdLocalFireDepartment, color: "text-primary-600", }, + { + text: "Blog", + url: "/blog", + icon: BiComment, + color: "text-primary-600", + }, // { // text: "Categories", // url: "/categories", diff --git a/src/features/Posts/pages/FeedPage/FeedPage.tsx b/src/features/Posts/pages/FeedPage/FeedPage.tsx index 9daaa43..f35e79c 100644 --- a/src/features/Posts/pages/FeedPage/FeedPage.tsx +++ b/src/features/Posts/pages/FeedPage/FeedPage.tsx @@ -1,6 +1,6 @@ import { useFeedQuery } from 'src/graphql' -import { useInfiniteQuery } from 'src/utils/hooks' +import { useAppSelector, useInfiniteQuery } from 'src/utils/hooks' import PostsList from '../../Components/PostsList/PostsList' import TrendingCard from '../../Components/TrendingCard/TrendingCard' import PopularCategories from './PopularCategories/PopularCategories' @@ -17,13 +17,21 @@ export default function FeedPage() { }, }) const { fetchMore, isFetchingMore } = useInfiniteQuery(feedQuery, 'getFeed') + const { navHeight } = useAppSelector((state) => ({ + navHeight: state.ui.navHeight + })); return (
-