Skip to content

Commit 87825a0

Browse files
authored
feat: pull down to refresh (#2908)
* feat: pull down to refresh functionality Custom pull down to refresh added to replace the default browser pull down to refresh. This will allow you to manually reload the page if you are using it as a PWA. * test: update test to check api call correctly changed api call for test and made sure it pulls down all the way to trigger refresh * fix: changed positioning of pull to refresh Refresh indicator now has absolute positioning and will prevent the top edge from pulling down.
1 parent 99fc9a2 commit 87825a0

File tree

7 files changed

+102
-0
lines changed

7 files changed

+102
-0
lines changed

cypress/e2e/pull-to-refresh.cy.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
describe('Pull To Refresh', () => {
2+
beforeEach(() => {
3+
cy.login(Cypress.env('ADMIN_EMAIL'), Cypress.env('ADMIN_PASSWORD'));
4+
cy.viewport(390, 844);
5+
cy.visitMobile('/');
6+
});
7+
8+
it('reloads the current page', () => {
9+
cy.wait(500);
10+
11+
cy.intercept({
12+
method: 'GET',
13+
url: '/api/v1/*',
14+
}).as('apiCall');
15+
16+
cy.get('.searchbar').swipe('bottom', [190, 400]);
17+
18+
cy.wait('@apiCall').then((interception) => {
19+
assert.isNotNull(
20+
interception.response.body,
21+
'API was called and received data'
22+
);
23+
});
24+
});
25+
});

cypress/support/commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/// <reference types="cypress" />
2+
import 'cy-mobile-commands';
23

34
Cypress.Commands.add('login', (email, password) => {
45
cy.session(

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
"openpgp": "5.4.0",
6868
"plex-api": "5.3.2",
6969
"pug": "3.0.2",
70+
"pulltorefreshjs": "0.1.22",
7071
"react": "18.2.0",
7172
"react-ace": "10.1.0",
7273
"react-animate-height": "2.1.2",
@@ -116,6 +117,7 @@
116117
"@types/node": "17.0.36",
117118
"@types/node-schedule": "2.1.0",
118119
"@types/nodemailer": "6.4.5",
120+
"@types/pulltorefreshjs": "0.1.5",
119121
"@types/react": "18.0.17",
120122
"@types/react-dom": "18.0.6",
121123
"@types/react-transition-group": "4.4.5",
@@ -133,6 +135,7 @@
133135
"babel-plugin-react-intl-auto": "3.3.0",
134136
"commitizen": "4.2.5",
135137
"copyfiles": "2.4.1",
138+
"cy-mobile-commands": "0.3.0",
136139
"cypress": "10.6.0",
137140
"cz-conventional-changelog": "3.3.0",
138141
"eslint": "8.22.0",

src/components/Layout/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import SearchInput from '@app/components/Layout/SearchInput';
22
import Sidebar from '@app/components/Layout/Sidebar';
33
import UserDropdown from '@app/components/Layout/UserDropdown';
4+
import PullToRefresh from '@app/components/PullToRefresh';
45
import type { AvailableLocale } from '@app/context/LanguageContext';
56
import useLocale from '@app/hooks/useLocale';
67
import useSettings from '@app/hooks/useSettings';
@@ -57,6 +58,7 @@ const Layout = ({ children }: LayoutProps) => {
5758
<Sidebar open={isSidebarOpen} setClosed={() => setSidebarOpen(false)} />
5859

5960
<div className="relative mb-16 flex w-0 min-w-0 flex-1 flex-col lg:ml-64">
61+
<PullToRefresh />
6062
<div
6163
className={`searchbar fixed left-0 right-0 top-0 z-10 flex flex-shrink-0 bg-opacity-80 transition duration-300 ${
6264
isScrolled ? 'bg-gray-700' : 'bg-transparent'
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { RefreshIcon } from '@heroicons/react/outline';
2+
import Router from 'next/router';
3+
import PR from 'pulltorefreshjs';
4+
import { useEffect } from 'react';
5+
import ReactDOMServer from 'react-dom/server';
6+
7+
const PullToRefresh: React.FC = () => {
8+
useEffect(() => {
9+
PR.init({
10+
mainElement: '#pull-to-refresh',
11+
onRefresh() {
12+
Router.reload();
13+
},
14+
iconArrow: ReactDOMServer.renderToString(
15+
<RefreshIcon className="z-50 m-auto h-9 w-9 rounded-full border-4 border-gray-800 bg-gray-800 text-indigo-500 ring-1 ring-gray-700" />
16+
),
17+
iconRefreshing: ReactDOMServer.renderToString(
18+
<RefreshIcon
19+
className="z-50 m-auto h-9 w-9 animate-spin rounded-full border-4 border-gray-800 bg-gray-800 text-indigo-500 ring-1 ring-gray-700"
20+
style={{ animationDirection: 'reverse' }}
21+
/>
22+
),
23+
instructionsPullToRefresh: ReactDOMServer.renderToString(<div />),
24+
instructionsReleaseToRefresh: ReactDOMServer.renderToString(<div />),
25+
instructionsRefreshing: ReactDOMServer.renderToString(<div />),
26+
distReload: 55,
27+
});
28+
return () => {
29+
PR.destroyAll();
30+
};
31+
}, []);
32+
33+
return <div id="pull-to-refresh"></div>;
34+
};
35+
36+
export default PullToRefresh;

src/styles/globals.css

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
body {
1313
@apply bg-gray-900;
14+
overscroll-behavior-y: contain;
1415
}
1516

1617
code {
@@ -453,3 +454,22 @@
453454
}
454455
}
455456
}
457+
458+
.ptr--ptr {
459+
box-shadow: initial !important;
460+
position: absolute !important;
461+
z-index: 30 !important;
462+
}
463+
464+
.ptr--refresh {
465+
overflow: visible !important;
466+
z-index: 30 !important;
467+
}
468+
469+
.ptr--pull {
470+
z-index: 30 !important;
471+
}
472+
473+
.ptr--ptr .ptr--box {
474+
margin-bottom: -13px !important;
475+
}

yarn.lock

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3047,6 +3047,11 @@
30473047
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
30483048
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
30493049

3050+
"@types/pulltorefreshjs@0.1.5":
3051+
version "0.1.5"
3052+
resolved "https://registry.yarnpkg.com/@types/pulltorefreshjs/-/pulltorefreshjs-0.1.5.tgz#f15c9dbc91b8fdd8135093d81ece9e9d4d2324d7"
3053+
integrity sha512-/VRTgBettvBg1KI8mGnA9oeWs359tTXQ7qsxLuXnksL88jvK6ZNMStG5T9x9vUO9O7jLsgREB0cElz/BWFfdew==
3054+
30503055
"@types/qs@*":
30513056
version "6.9.7"
30523057
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb"
@@ -4942,6 +4947,11 @@ csurf@1.11.0:
49424947
csrf "3.1.0"
49434948
http-errors "~1.7.3"
49444949

4950+
cy-mobile-commands@0.3.0:
4951+
version "0.3.0"
4952+
resolved "https://registry.yarnpkg.com/cy-mobile-commands/-/cy-mobile-commands-0.3.0.tgz#2bf242093149154d846b755977da197b4730429e"
4953+
integrity sha512-Bj5P2ylw88hPqolLu68xWB6euVH5uNt8zyh+Ju8sBukGv39mWZxpjp6LtnUX/LK/YMthwvILYHhvr9SG1TP+4w==
4954+
49454955
cypress@10.6.0:
49464956
version "10.6.0"
49474957
resolved "https://registry.yarnpkg.com/cypress/-/cypress-10.6.0.tgz#13f46867febf2c3715874ed5dce9c2e946b175fe"
@@ -10157,6 +10167,11 @@ pug@3.0.2, pug@^3.0.2:
1015710167
pug-runtime "^3.0.1"
1015810168
pug-strip-comments "^2.0.0"
1015910169

10170+
pulltorefreshjs@0.1.22:
10171+
version "0.1.22"
10172+
resolved "https://registry.yarnpkg.com/pulltorefreshjs/-/pulltorefreshjs-0.1.22.tgz#ddb5e3feee0b2a49fd46e1b18e84fffef2c47ac0"
10173+
integrity sha512-haxNVEHnS4NCQA7NeG7TSV69z4uqy/N7nfPRuc4dPWe8H6ygUrMjdNeohE+6v0lVVX/ukSjbLYwPUGUYtFKfvQ==
10174+
1016010175
pump@^3.0.0:
1016110176
version "3.0.0"
1016210177
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"

0 commit comments

Comments
 (0)