Skip to content

Commit 0d2a1b4

Browse files
committed
Merge remote-tracking branch 'origin/dev' into feat/applications
2 parents 1a75efe + 0c7cd4d commit 0d2a1b4

File tree

26 files changed

+314
-174
lines changed

26 files changed

+314
-174
lines changed

.github/workflows/ci.yaml

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
name: CI
2+
on:
3+
push:
4+
branches: [master, dev]
5+
pull_request:
6+
branches: [master, dev]
7+
8+
jobs:
9+
lint:
10+
runs-on: self-hosted
11+
strategy:
12+
matrix:
13+
node-version: [18]
14+
steps:
15+
- uses: actions/checkout@v3
16+
- uses: pnpm/action-setup@v4
17+
with:
18+
version: 9
19+
- name: Use Node.js ${{ matrix.node-version }}
20+
uses: actions/setup-node@v3
21+
with:
22+
node-version: ${{ matrix.node-version }}
23+
cache: 'pnpm'
24+
- run: pnpm install --frozen-lockfile
25+
- run: pnpm lint
26+
27+
deploy-dev:
28+
if: ${{ github.event_name != 'pull_request' && (github.ref == 'refs/heads/dev') }}
29+
runs-on: self-hosted
30+
needs:
31+
- lint
32+
steps:
33+
- uses: actions/checkout@v4
34+
- name: Install docker
35+
uses: docker/setup-buildx-action@v3
36+
- name: Login to registry
37+
uses: docker/login-action@v3
38+
with:
39+
registry: ${{ secrets.REGISTRY_URL }}
40+
username: ${{ secrets.REGISTRY_USERNAME }}
41+
password: ${{ secrets.REGISTRY_TOKEN }}
42+
- run: cp .env.dist .env.prod
43+
- name: Build and push
44+
uses: docker/build-push-action@v6
45+
with:
46+
push: true
47+
build-args: |
48+
NODE_ENV=production
49+
NEXT_PUBLIC_API_URL=https://etu.dev.uttnetgroup.fr/api
50+
NEXT_PUBLIC_CAS_SERVICE_URL=https://etu.utt.fr/login
51+
NEXT_PUBLIC_API_VERSION=v1
52+
NEXT_PUBLIC_API_REQUEST_TIMEOUT=5000
53+
tags: |
54+
${{ secrets.REGISTRY_URL }}/etuutt/front:dev
55+
56+
deploy-prod:
57+
if: ${{ github.event_name != 'pull_request' && (github.ref == 'refs/heads/master') }}
58+
runs-on: self-hosted
59+
needs:
60+
- lint
61+
steps:
62+
- uses: actions/checkout@v4
63+
- name: Install docker
64+
uses: docker/setup-buildx-action@v3
65+
- name: Login to registry
66+
uses: docker/login-action@v3
67+
with:
68+
registry: ${{ secrets.REGISTRY_URL }}
69+
username: ${{ secrets.REGISTRY_USERNAME }}
70+
password: ${{ secrets.REGISTRY_TOKEN }}
71+
- run: cp .env.dist .env.prod
72+
- name: Build and push
73+
uses: docker/build-push-action@v6
74+
with:
75+
push: true
76+
build-args: |
77+
NODE_ENV=production
78+
NEXT_PUBLIC_API_URL=https://etu.utt.fr/api
79+
NEXT_PUBLIC_CAS_SERVICE_URL=https://etu.utt.fr/login
80+
NEXT_PUBLIC_API_VERSION=v1
81+
NEXT_PUBLIC_API_REQUEST_TIMEOUT=5000
82+
tags: |
83+
${{ secrets.REGISTRY_URL }}/etuutt/front:prod

Dockerfile

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
1-
ARG NODE_VERSION=19-alpine
1+
ARG NODE_VERSION=22-alpine
22

33
FROM node:${NODE_VERSION}
44

5+
ARG NODE_ENV=production
6+
ARG NEXT_PUBLIC_API_URL=http://localhost:3000
7+
ARG NEXT_PUBLIC_CAS_SERVICE_URL=http://localhost:3000
8+
ARG NEXT_PUBLIC_API_VERSION=v1
9+
ARG NEXT_PUBLIC_API_REQUEST_TIMEOUT=10000
10+
11+
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
12+
ENV NEXT_PUBLIC_CAS_SERVICE_URL=${NEXT_PUBLIC_CAS_SERVICE_URL}
13+
ENV NEXT_PUBLIC_API_VERSION=${NEXT_PUBLIC_API_VERSION}
14+
ENV NEXT_PUBLIC_API_REQUEST_TIMEOUT=${NEXT_PUBLIC_API_REQUEST_TIMEOUT}
15+
516
WORKDIR /usr/src/app
617

18+
# Add alpine dependencies for 'sharp'
19+
RUN apk add --upgrade --no-cache vips-dev build-base
20+
721
COPY --chown=node:node package.json pnpm-lock.yaml ./
822

923
RUN npm i -g pnpm && pnpm install --frozen-lockfile --prod=false

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,10 @@
4747
"eslint-plugin-react": "^7.34.2",
4848
"sass": "^1.77.4",
4949
"typescript": "^5.4.5"
50+
},
51+
"pnpm": {
52+
"onlyBuiltDependencies": [
53+
"sharp"
54+
]
5055
}
5156
}

src/app/assos/page.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import { createInputFilter } from '@/components/filteredSearch/InputFilter';
44
import FilteredSearch, { FiltersDataType, GenericFiltersType } from '@/components/filteredSearch/FilteredSearch';
55
import Icons from '@/icons';
66
import { ResultsList } from '@/components/ResultsList';
7-
import { usePageSettings } from '@/module/pageSettings';
87
import { useAppTranslation } from '@/lib/i18n';
98
import { useAssos } from '@/api/assos/searchAssos.hook';
9+
import Page from '@/components/utilities/Page';
1010

1111
/**
1212
* The different filters that exist.
@@ -28,12 +28,11 @@ const assoFilters = Object.freeze({
2828
}, // This one does not need a name as it will never be displayed
2929
} satisfies FiltersDataType<FilterNames, AssoFiltersType>);
3030

31-
export default function Page() {
32-
usePageSettings({});
31+
export default function AssoPage() {
3332
const { t } = useAppTranslation();
3433
const [assos, totalAssosCount, updateAssos] = useAssos();
3534
return (
36-
<div className={styles.page}>
35+
<Page className={styles.page}>
3736
<h1 className={styles.title}>{t('assos:browser')}</h1>
3837
<div className={styles.content}>
3938
<FilteredSearch<FilterNames, AssoFiltersType> filtersData={assoFilters} updateSearch={updateAssos} />
@@ -52,6 +51,6 @@ export default function Page() {
5251
/>
5352
</div>
5453
</div>
55-
</div>
54+
</Page>
5655
);
5756
}

src/app/cookies/page.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
import styles from './style.module.scss';
33
import { useAppDispatch, useAppSelector } from '@/lib/hooks';
44
import { CookieNames, setCookiesAcceptance } from '@/module/cookies';
5-
import { usePageSettings } from '@/module/pageSettings';
65
import { useEffect, useState } from 'react';
76
import { NotParameteredTranslationKey, useAppTranslation } from '@/lib/i18n';
7+
import Page from '@/components/utilities/Page';
88

99
const DEFAULT_COOKIES = Object.fromEntries(Object.values(CookieNames).map((name) => [name, true])) as {
1010
[K in CookieNames]: boolean;
@@ -23,7 +23,6 @@ const cookies = [
2323
}>;
2424

2525
export default function CookiesPage() {
26-
usePageSettings({});
2726
const dispatch = useAppDispatch();
2827
const cookiesAcceptedFromRedux = useAppSelector((state) => state.cookies.cookiesAccepted);
2928
const [cookiesAccepted, setCookiesAccepted] = useState(cookiesAcceptedFromRedux ?? DEFAULT_COOKIES);
@@ -41,7 +40,7 @@ export default function CookiesPage() {
4140
};
4241

4342
return (
44-
<div className={styles.cookiesPage}>
43+
<Page className={styles.cookiesPage}>
4544
<h1>{t('cookies:title')}</h1>
4645
<h2>{t('cookies:whatIsIt.title')}</h2>
4746
<p>{t('cookies:whatIsIt.text')}</p>
@@ -60,6 +59,6 @@ export default function CookiesPage() {
6059
))}
6160
</div>
6261
<button onClick={() => dispatch(setCookiesAcceptance(cookiesAccepted))}>{t('cookies:validate')}</button>
63-
</div>
62+
</Page>
6463
);
6564
}

src/app/layout.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Wrapper from '@/components/utilities/Wrapper';
77
import PageSearchParams from '@/components/utilities/PageSearchParams';
88
import { Lexend } from 'next/font/google';
99
import { CookiePopup } from '@/components/CookiePopup';
10+
import PageSettingsInitializer from '@/components/utilities/PageSettingsInitializer';
1011

1112
const lexend = Lexend({
1213
weight: ['400', '600', '700', '800'],
@@ -27,6 +28,7 @@ export default function RootLayout({ children }: { children: ReactNode }) {
2728
<Providers>
2829
<Redirecter />
2930
<AutoLogin />
31+
<PageSettingsInitializer />
3032
<Suspense>
3133
<PageSearchParams />
3234
</Suspense>

src/app/login/page.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@ import { CasLoginRequestDto, CasLoginResponseDto } from '@/api/auth/casLogin';
66
import { setToken } from '@/module/session';
77
import { useAppDispatch } from '@/lib/hooks';
88
import { useEffect, useState } from 'react';
9-
import { usePageLoaded, usePageSettings, useSearchParam } from '@/module/pageSettings';
9+
import { usePageLoaded, useSearchParam } from '@/module/pageSettings';
1010
import Button from '@/components/UI/Button';
1111
import { RegisterResponseDto } from '@/api/auth/register';
1212
import { CasRegisterRequestDto } from '@/api/auth/casRegister';
1313
import { useAPI } from '@/api/api';
1414
import { useAppTranslation } from '@/lib/i18n';
1515
import { Trans } from 'react-i18next';
1616
import { etuuttWebApplicationId } from '@/utils/environment';
17+
import Page from '@/components/utilities/Page';
1718

1819
export default function LoginPage() {
19-
usePageSettings({ hasNavbar: false, permissions: 'public', needsLoading: true });
2020
const { internallyLoaded, markPageLoaded } = usePageLoaded();
2121
const ticket = useSearchParam('ticket');
2222
const application = useSearchParam('application');
@@ -59,7 +59,7 @@ export default function LoginPage() {
5959
}
6060
if (registerToken) {
6161
return (
62-
<div className={styles.confirmRegister}>
62+
<Page hasNavbar={true} permissions={'public'} needsLoading={true} className={styles.confirmRegister}>
6363
<div>
6464
<Trans
6565
i18nKey={'login:legal.text'}
@@ -90,13 +90,13 @@ export default function LoginPage() {
9090
{t('login:legal.dontConnect')}
9191
</Button>
9292
</div>
93-
</div>
93+
</Page>
9494
);
9595
}
9696

9797
return (
98-
<div id="login-page" className={styles.loginPage}>
98+
<Page hasNavbar={true} permissions={'public'} needsLoading={true} id="login-page" className={styles.loginPage}>
9999
<LoginForm application={application} />
100-
</div>
100+
</Page>
101101
);
102102
}

src/app/not-found.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
'use client';
22

3-
import { usePageSettings } from '@/module/pageSettings';
3+
import Page from '@/components/utilities/Page';
44

55
export default function PageNotFound() {
6-
usePageSettings({});
7-
return <h1>404 - Page not found</h1>;
6+
return (
7+
<Page>
8+
<h1>404 - Page not found</h1>
9+
</Page>
10+
);
811
}

src/app/page.tsx

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
import styles from './style.module.scss';
44
import WidgetRenderer from '@/components/homeWidgets/WidgetRenderer';
5-
import { usePageLoaded, usePageSettings } from '@/module/pageSettings';
5+
import { usePageLoaded } from '@/module/pageSettings';
66
import Button from '@/components/UI/Button';
77
import { useStateWithReference } from '@/utils/hooks';
88
import { useAppDispatch, useAppSelector } from '@/lib/hooks';
99
import { addWidget, modifyBB, removeWidget, WIDGETS } from '@/module/homepage';
1010
import { useEffect, useMemo, useState } from 'react';
1111
import { isClientSide } from '@/utils/environment';
12+
import Page from '@/components/utilities/Page';
1213

1314
function AdditionalNavbarComponent({
1415
modifyingLayout,
@@ -21,7 +22,6 @@ function AdditionalNavbarComponent({
2122
onModify: () => void;
2223
onDone: () => void;
2324
}) {
24-
//usePageSettings({});
2525
const [widgetToAdd /*, setWidgetToAdd*/] = useState<keyof typeof WIDGETS>('ueBrowserWidget');
2626
return (
2727
<>
@@ -46,22 +46,16 @@ export default function HomePage() {
4646
const { markPageLoaded } = usePageLoaded();
4747
const [isSmallScreen, setIsSmallScreen] = useState(false);
4848
const [modifyingLayout, setModifyingLayout, modifyingLayoutRef] = useStateWithReference(false);
49-
usePageSettings(
50-
{
51-
navbarAdditionalComponent: isSmallScreen
52-
? null
53-
: () => (
54-
<AdditionalNavbarComponent
55-
modifyingLayout={modifyingLayoutRef.current}
56-
onModify={() => setModifyingLayout(true)}
57-
onDone={() => setModifyingLayout(false)}
58-
onAdd={(widget) => dispatch(addWidget(widget))}
59-
/>
60-
),
61-
needsLoading: true,
62-
},
63-
[modifyingLayout, isSmallScreen],
64-
);
49+
const navbarAdditionalComponent = isSmallScreen
50+
? null
51+
: () => (
52+
<AdditionalNavbarComponent
53+
modifyingLayout={modifyingLayoutRef.current}
54+
onModify={() => setModifyingLayout(true)}
55+
onDone={() => setModifyingLayout(false)}
56+
onAdd={(widget) => dispatch(addWidget(widget))}
57+
/>
58+
);
6559
const resizeObserver = useMemo(
6660
() =>
6761
isClientSide()
@@ -82,7 +76,7 @@ export default function HomePage() {
8276
return () => resizeObserver.disconnect();
8377
}, [resizeObserver]);
8478
return (
85-
<div className={styles.page}>
79+
<Page needsLoading={true} navbarAdditionalComponent={navbarAdditionalComponent} className={styles.page}>
8680
{!isSmallScreen
8781
? widgets.map((widget, i) => {
8882
return (
@@ -103,6 +97,6 @@ export default function HomePage() {
10397
const Widget = WIDGETS[widget.widget].component;
10498
return <Widget key={widget.id} />;
10599
})}
106-
</div>
100+
</Page>
107101
);
108102
}

src/app/profile/page.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
'use client';
2-
import { usePageSettings } from '@/module/pageSettings';
2+
33
// import { useConnectedUser } from '@/module/user';
44
import { setProfilePicture } from '@/api/profile/setProfilePicture';
55
import { useAPI } from '@/api/api';
66
import { useAppTranslation } from '@/lib/i18n';
7+
import Page from '@/components/utilities/Page';
78

89
export default function ProfilePage() {
9-
usePageSettings({});
1010
// const user = useConnectedUser();
1111
const api = useAPI();
1212
const { t } = useAppTranslation();
1313
return (
14-
<div>
14+
<Page>
1515
<h1>{t('users:profile.title')}</h1>
1616
<img src="/images/default-avatar.jpg" alt="Default avatar" />
1717
<input type="file" onChange={(e) => e.target.files && setProfilePicture(api, e.target.files[0])} />
18-
</div>
18+
</Page>
1919
);
2020
}

0 commit comments

Comments
 (0)