From 32b07ddd3f26439e9a6949277b2d79480f648590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Santana=20Gon=C3=A7alves?= Date: Wed, 14 Aug 2024 12:17:57 -0300 Subject: [PATCH] DAO-597: Implement loading spinner (#101) * add loading spinner component * add loading to protected content * add loading button * add alert message for canceling transaction * loading request allowance * add loading to confirm staking button * add loading to unstaking button * pending claiming nft * fix build --- package-lock.json | 22 +++++++++++++++-- package.json | 1 + public/loading.json | 1 + src/app/proposals/hooks/useCreateProposal.ts | 4 ++-- src/app/proposals/shared/utils.ts | 5 ++++ src/app/user/Stake/StakePreview.tsx | 7 ++++-- src/app/user/Stake/StakingContext.tsx | 8 ++++++- src/app/user/Stake/Steps/StepTwo.tsx | 7 +++++- src/app/user/Stake/hooks/useStakeRIF.tsx | 24 +++++++++++++++---- src/app/user/Stake/hooks/useUnstakeStRIF.tsx | 3 ++- src/components/Alert/Alert.tsx | 3 ++- src/components/Button/Button.tsx | 4 ++++ .../LoadingSpinner/LoadingSpinner.stories.tsx | 15 ++++++++++++ .../LoadingSpinner/LoadingSpinner.tsx | 9 +++++++ src/components/LoadingSpinner/index.ts | 1 + .../ProtectedContent/ProtectedContent.tsx | 3 ++- src/pages/communities/nft/[address].tsx | 5 ++-- src/pages/proposals/create.tsx | 17 ++++++++----- src/shared/hooks/useMintNFT.ts | 4 ++-- tsconfig.json | 3 ++- 20 files changed, 119 insertions(+), 27 deletions(-) create mode 100644 public/loading.json create mode 100644 src/components/LoadingSpinner/LoadingSpinner.stories.tsx create mode 100644 src/components/LoadingSpinner/LoadingSpinner.tsx create mode 100644 src/components/LoadingSpinner/index.ts diff --git a/package-lock.json b/package-lock.json index 9250e3e2..5b3837ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "dao-frontend", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dao-frontend", - "version": "0.1.0", + "version": "0.1.1", "dependencies": { "@hookform/resolvers": "^3.7.0", "@radix-ui/react-accordion": "^1.2.0", @@ -19,6 +19,7 @@ "clsx": "^2.1.1", "ethers": "^6.13.1", "jdenticon": "^3.3.0", + "lottie-react": "^2.4.0", "lucide-react": "^0.400.0", "moment": "^2.30.1", "next": "14.2.3", @@ -19576,6 +19577,23 @@ "loose-envify": "cli.js" } }, + "node_modules/lottie-react": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/lottie-react/-/lottie-react-2.4.0.tgz", + "integrity": "sha512-pDJGj+AQlnlyHvOHFK7vLdsDcvbuqvwPZdMlJ360wrzGFurXeKPr8SiRCjLf3LrNYKANQtSsh5dz9UYQHuqx4w==", + "dependencies": { + "lottie-web": "^5.10.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/lottie-web": { + "version": "5.12.2", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.12.2.tgz", + "integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==" + }, "node_modules/loupe": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", diff --git a/package.json b/package.json index b722f21e..4aeeade9 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "clsx": "^2.1.1", "ethers": "^6.13.1", "jdenticon": "^3.3.0", + "lottie-react": "^2.4.0", "lucide-react": "^0.400.0", "moment": "^2.30.1", "next": "14.2.3", diff --git a/public/loading.json b/public/loading.json new file mode 100644 index 00000000..95e6f990 --- /dev/null +++ b/public/loading.json @@ -0,0 +1 @@ +{"nm":"final","ddd":0,"h":432,"w":768,"meta":{"g":"LottieFiles AE "},"layers":[{"ty":0,"nm":"applying r","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[160,160,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[384,216,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":320,"h":320,"refId":"comp_0","ind":1},{"ty":0,"nm":"applying r","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[160,160,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[384,239,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":38,"ix":11}},"ef":[{"ty":29,"mn":"ADBE Gaussian Blur 2","nm":"Gaussian Blur","ix":1,"en":1,"ef":[{"ty":0,"mn":"ADBE Gaussian Blur 2-0001","nm":"Blurriness","ix":1,"v":{"a":0,"k":65.3,"ix":1}},{"ty":7,"mn":"ADBE Gaussian Blur 2-0002","nm":"Blur Dimensions","ix":2,"v":{"a":0,"k":1,"ix":2}},{"ty":7,"mn":"ADBE Gaussian Blur 2-0003","nm":"Repeat Edge Pixels","ix":3,"v":{"a":0,"k":0,"ix":3}}]}],"w":320,"h":320,"refId":"comp_0","ind":2}],"v":"4.8.0","fr":60,"op":480,"ip":0,"assets":[{"nm":"","id":"comp_0","layers":[{"ty":0,"nm":"one seq","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[160,160,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[160,160,0],"ix":2},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"s":[900],"t":481.000019591532}],"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":320,"h":320,"refId":"comp_1","ind":1}]},{"nm":"","id":"comp_1","layers":[{"ty":4,"nm":"04_dec","sr":1,"st":360.000014663101,"op":480.000019550801,"ip":420.000017106951,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[10.547,16.547,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[160,160,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":4,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[177.094,177.094],"ix":2}},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[75],"t":420},{"s":[75],"t":480.000019550801}],"ix":2},"o":{"a":0,"k":-270,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[0],"t":420},{"s":[75],"t":480.000019550801}],"ix":1},"m":1},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":2,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"c":{"a":0,"k":[0.4,0.3686,0.9647],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[10.547,16.547],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":4,"nm":"04_inc","sr":1,"st":360.000014663101,"op":420.000017106951,"ip":356.000014500177,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[10.547,16.547,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[160,160,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":4,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[177.094,177.094],"ix":2}},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[0],"t":360},{"s":[75],"t":420.000017106951}],"ix":2},"o":{"a":0,"k":-270,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[0],"t":360},{"s":[0],"t":420.000017106951}],"ix":1},"m":1},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":2,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"c":{"a":0,"k":[0.4,0.3686,0.9647],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[10.547,16.547],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2},{"ty":4,"nm":"03_dec","sr":1,"st":240.0000097754,"op":365.000014866755,"ip":300.00001221925,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[10.547,16.547,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[160,160,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":4,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[177.094,177.094],"ix":2}},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[75],"t":300},{"s":[75],"t":360.000014663101}],"ix":2},"o":{"a":0,"k":-180,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[0],"t":300},{"s":[75],"t":360.000014663101}],"ix":1},"m":1},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":2,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"c":{"a":0,"k":[0.4,0.3686,0.9647],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[10.547,16.547],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3},{"ty":4,"nm":"03_inc","sr":1,"st":240.0000097754,"op":301.000012259981,"ip":236.000009612477,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[10.547,16.547,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[160,160,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":4,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[177.094,177.094],"ix":2}},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[0],"t":240},{"s":[75],"t":300.00001221925}],"ix":2},"o":{"a":0,"k":-180,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[0],"t":240},{"s":[0],"t":300.00001221925}],"ix":1},"m":1},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":2,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"c":{"a":0,"k":[0.4,0.3686,0.9647],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[10.547,16.547],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":4},{"ty":4,"nm":"02_dec","sr":1,"st":121.000004928431,"op":246.000010019785,"ip":180.00000733155,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[10.547,16.547,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[160,160,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":4,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[177.094,177.094],"ix":2}},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[75],"t":180},{"s":[75],"t":240.0000097754}],"ix":2},"o":{"a":0,"k":-90,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[0],"t":180},{"s":[75],"t":240.0000097754}],"ix":1},"m":1},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":2,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"c":{"a":0,"k":[0.4,0.3686,0.9647],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[10.547,16.547],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":5},{"ty":4,"nm":"02_inc","sr":1,"st":121.000004928431,"op":180.00000733155,"ip":116.000004724777,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[10.547,16.547,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[160,160,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":4,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[177.094,177.094],"ix":2}},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[0],"t":120},{"s":[75],"t":180.00000733155}],"ix":2},"o":{"a":0,"k":-90,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[0],"t":120},{"s":[0],"t":180.00000733155}],"ix":1},"m":1},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":2,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"c":{"a":0,"k":[0.4,0.3686,0.9647],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[10.547,16.547],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":6},{"ty":4,"nm":"01_dec","sr":1,"st":0,"op":125.000005091354,"ip":60.0000024438501,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[10.547,16.547,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[160,160,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":4,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[177.094,177.094],"ix":2}},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[75],"t":60},{"s":[75],"t":120.0000048877}],"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[0],"t":60},{"s":[75],"t":120.0000048877}],"ix":1},"m":1},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":2,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"c":{"a":0,"k":[0.4,0.3686,0.9647],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[10.547,16.547],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":7},{"ty":4,"nm":"01_inc","sr":1,"st":0,"op":60.0000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[10.547,16.547,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[160,160,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":4,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[177.094,177.094],"ix":2}},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[0],"t":0},{"s":[75],"t":60.0000024438501}],"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.85,"y":0},"i":{"x":0.15,"y":1},"s":[0],"t":0},{"s":[0],"t":60.0000024438501}],"ix":1},"m":1},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":2,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"c":{"a":0,"k":[0.4,0.3686,0.9647],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[10.547,16.547],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":8},{"ty":4,"nm":"01_inc 2","sr":1,"st":0,"op":486.000019795186,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[10.547,16.547,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[160,160,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":15,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":4,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[177.094,177.094],"ix":2}},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":0,"k":0,"ix":1},"m":1},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":2,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"c":{"a":0,"k":[0.4,0.3686,0.9647],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[10.547,16.547],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":9}]}]} \ No newline at end of file diff --git a/src/app/proposals/hooks/useCreateProposal.ts b/src/app/proposals/hooks/useCreateProposal.ts index b7c441aa..4e0ccded 100644 --- a/src/app/proposals/hooks/useCreateProposal.ts +++ b/src/app/proposals/hooks/useCreateProposal.ts @@ -34,7 +34,7 @@ const createProposalForRIFTransfer = ( export const useCreateProposal = () => { const { canCreateProposal } = useVotingPower() - const { writeContractAsync: propose } = useWriteContract() + const { writeContractAsync: propose, isPending: isPublishing } = useWriteContract() const onCreateProposal = async (address: Address, amount: string, description: string) => { if (!canCreateProposal) { @@ -49,5 +49,5 @@ export const useCreateProposal = () => { args: proposal, }) } - return { onCreateProposal } + return { onCreateProposal, isPublishing } } diff --git a/src/app/proposals/shared/utils.ts b/src/app/proposals/shared/utils.ts index 0c089a43..08195a6e 100644 --- a/src/app/proposals/shared/utils.ts +++ b/src/app/proposals/shared/utils.ts @@ -65,4 +65,9 @@ export const TRANSACTION_SENT_MESSAGES = { 'Proposal successfully created. Your proposal has been published successfully! It is now visible to the community for review and feedback. Thank you for your contribution.', severity: 'success', }, + canceled: { + title: 'Transaction canceled', + content: 'Proposal creation canceled. Your proposal has been canceled.', + severity: 'warning', + }, } as const diff --git a/src/app/user/Stake/StakePreview.tsx b/src/app/user/Stake/StakePreview.tsx index b405081d..010bd30c 100644 --- a/src/app/user/Stake/StakePreview.tsx +++ b/src/app/user/Stake/StakePreview.tsx @@ -15,6 +15,7 @@ interface StakePreviewProps { confirmButtonText?: string customComponentBeforeFooter?: ReactNode disableConfirm?: boolean + loading?: boolean } export const StakePreview = ({ @@ -27,6 +28,7 @@ export const StakePreview = ({ actionName, actionText, confirmButtonText = 'Confirm', + loading = false, }: StakePreviewProps) => { return (
@@ -58,8 +60,9 @@ export const StakePreview = ({ Cancel
diff --git a/src/app/user/Stake/hooks/useUnstakeStRIF.tsx b/src/app/user/Stake/hooks/useUnstakeStRIF.tsx index f7f8a4e2..235eb6f0 100644 --- a/src/app/user/Stake/hooks/useUnstakeStRIF.tsx +++ b/src/app/user/Stake/hooks/useUnstakeStRIF.tsx @@ -6,7 +6,7 @@ import { Address, parseEther } from 'viem' export const useUnstakeStRIF: ActionHookToUse = (amount, tokenToSendContract) => { const { address } = useAccount() - const { writeContractAsync: unstake } = useWriteContract() + const { writeContractAsync: unstake, isPending } = useWriteContract() const onRequestUnstake = () => unstake({ @@ -19,5 +19,6 @@ export const useUnstakeStRIF: ActionHookToUse = (amount, tokenToSendContract) => shouldEnableConfirm: true, customFooter: null, onConfirm: onRequestUnstake, + isPending, } } diff --git a/src/components/Alert/Alert.tsx b/src/components/Alert/Alert.tsx index c73f160c..60240f0e 100644 --- a/src/components/Alert/Alert.tsx +++ b/src/components/Alert/Alert.tsx @@ -4,7 +4,7 @@ import { Paragraph } from '@/components/Typography' import { MdClose } from 'react-icons/md' interface AlertProps { - severity: 'error' | 'success' | 'info' + severity: 'error' | 'success' | 'info' | 'warning' title: string content: string onDismiss?: () => void @@ -14,6 +14,7 @@ const IconToUse = { error: , info: , success: , + warning: , } export const Alert = ({ severity, title, content, onDismiss }: AlertProps) => { diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index e0da42bd..451f06ed 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -1,6 +1,7 @@ import { ButtonVariants } from '@/components/Button/types' import { cn } from '@/lib/utils' import { FC, JSX, MouseEvent, ReactNode } from 'react' +import { FaSpinner } from 'react-icons/fa6' export const BUTTON_DEFAULT_CLASSES = 'px-[24px] py-[12px] flex gap-x-1 items-center relative' @@ -15,6 +16,7 @@ interface Props { className?: string textClassName?: string buttonProps?: JSX.IntrinsicElements['button'] & { 'data-testid'?: string } + loading?: boolean } const DEFAULT_DATA_TESTID = 'Button' @@ -30,7 +32,9 @@ export const Button: FC = ({ className = '', textClassName = '', buttonProps = {}, + loading = false, }) => { + startIcon = loading ? : startIcon const classes = cn({ [BUTTON_DEFAULT_CLASSES]: true, 'bg-primary rounded-[6px]': variant === 'primary', diff --git a/src/components/LoadingSpinner/LoadingSpinner.stories.tsx b/src/components/LoadingSpinner/LoadingSpinner.stories.tsx new file mode 100644 index 00000000..75879819 --- /dev/null +++ b/src/components/LoadingSpinner/LoadingSpinner.stories.tsx @@ -0,0 +1,15 @@ +import { Meta, StoryObj } from '@storybook/react' +import { LoadingSpinner } from './LoadingSpinner' + +const meta = { + title: 'Components/LoadingSpinner', + component: LoadingSpinner, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = { + args: {}, +} diff --git a/src/components/LoadingSpinner/LoadingSpinner.tsx b/src/components/LoadingSpinner/LoadingSpinner.tsx new file mode 100644 index 00000000..5751835e --- /dev/null +++ b/src/components/LoadingSpinner/LoadingSpinner.tsx @@ -0,0 +1,9 @@ +import { cn } from '@/lib/utils' +import Lottie from 'lottie-react' +import loadingAnimation from '@/public/loading.json' + +export const LoadingSpinner = ({ className = '' }) => ( +
+ +
+) diff --git a/src/components/LoadingSpinner/index.ts b/src/components/LoadingSpinner/index.ts new file mode 100644 index 00000000..fb8da18f --- /dev/null +++ b/src/components/LoadingSpinner/index.ts @@ -0,0 +1 @@ +export * from './LoadingSpinner' diff --git a/src/components/ProtectedContent/ProtectedContent.tsx b/src/components/ProtectedContent/ProtectedContent.tsx index 9eab98ee..b7b5d294 100644 --- a/src/components/ProtectedContent/ProtectedContent.tsx +++ b/src/components/ProtectedContent/ProtectedContent.tsx @@ -1,6 +1,7 @@ import { FC, ReactNode, useEffect, useState } from 'react' import { useAccount } from 'wagmi' import { ConnectWalletModal } from '../Modal/ConnectWalletModal' +import { LoadingSpinner } from '../LoadingSpinner' interface Props { children: ReactNode @@ -19,7 +20,7 @@ export const ProtectedContent: FC = ({ children }) => { return ( <> {!hasMounted || isConnecting ? ( -
Loading...
+ ) : ( <>{isConnected ? children : } )} diff --git a/src/pages/communities/nft/[address].tsx b/src/pages/communities/nft/[address].tsx index 2397d701..e1fb7c69 100644 --- a/src/pages/communities/nft/[address].tsx +++ b/src/pages/communities/nft/[address].tsx @@ -23,7 +23,7 @@ export default function Page() { const { address } = useAccount() const { cidsAvailable } = useCidsAvailable(nftAddress as Address) - const { onMintNFT } = useMintNFT(nftAddress as Address) + const { onMintNFT, isPending: isClaiming } = useMintNFT(nftAddress as Address) const [message, setMessage] = useState('') const { isLoadingImage: loadingNftImage, data: nftData } = useNFTImage(nftAddress as Address) @@ -147,7 +147,8 @@ export default function Page() { variant="secondary-full" className="my-[16px]" onClick={handleMinting} - disabled={!cidsAvailable || !address} + disabled={!cidsAvailable || !address || isClaiming} + loading={isClaiming} > Claim it! diff --git a/src/pages/proposals/create.tsx b/src/pages/proposals/create.tsx index 733505d5..8445bea1 100644 --- a/src/pages/proposals/create.tsx +++ b/src/pages/proposals/create.tsx @@ -57,7 +57,7 @@ export default function CreateProposal() { const router = useRouter() const prices = useGetSpecificPrices() const { isLoading: isVotingPowerLoading, canCreateProposal } = useVotingPower() - const { onCreateProposal } = useCreateProposal() + const { onCreateProposal, isPublishing } = useCreateProposal() const [message, setMessage] = useState< (typeof TRANSACTION_SENT_MESSAGES)[keyof typeof TRANSACTION_SENT_MESSAGES] | null >(null) @@ -104,7 +104,11 @@ export default function CreateProposal() { router.push(`/proposals?txHash=${txHash}`) }) .catch(err => { - setMessage(TRANSACTION_SENT_MESSAGES.error) + if (err?.cause?.code === 4001) { + setMessage(TRANSACTION_SENT_MESSAGES.canceled) + } else { + setMessage(TRANSACTION_SENT_MESSAGES.error) + } }) } @@ -133,7 +137,7 @@ export default function CreateProposal() { )}
- + @@ -293,13 +298,13 @@ export default function CreateProposal() { ) } -const HeaderSection = ({ disabled = true }) => ( +const HeaderSection = ({ disabled = true, loading = false }) => (
Create proposal
-
diff --git a/src/shared/hooks/useMintNFT.ts b/src/shared/hooks/useMintNFT.ts index be3de8db..1f5317a7 100644 --- a/src/shared/hooks/useMintNFT.ts +++ b/src/shared/hooks/useMintNFT.ts @@ -5,7 +5,7 @@ import { useCidsAvailable } from './useCidsAvailable' export const useMintNFT = (nftAddress: Address | undefined) => { const { cidsAvailable } = useCidsAvailable(nftAddress) - const { writeContractAsync: mint } = useWriteContract() + const { writeContractAsync: mint, isPending } = useWriteContract() const onMintNFT = async () => { if (!cidsAvailable) { @@ -20,5 +20,5 @@ export const useMintNFT = (nftAddress: Address | undefined) => { }) } - return { onMintNFT } + return { onMintNFT, isPending } } diff --git a/tsconfig.json b/tsconfig.json index 2f23c256..e46f3133 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,8 @@ } ], "paths": { - "@/*": ["./src/*"] + "@/*": ["./src/*"], + "@/public/*": ["./public/*"] } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],