();
+
const fetching = useAppSelector((state) => state.surveys.fetching);
const actionGrant = survey?.actionGrant;
@@ -32,61 +36,43 @@ const SurveyDetailPage = () => {
navigate(`/surveys/${surveyId}/answer`);
}
- const isTemplate = !!survey.templateType;
-
return (
-
- )
- }
- title={survey.title}
- back={{ href: `/surveys/${isTemplate ? 'templates' : ''}` }}
- tabs={!isTemplate && }
- >
-
-
-
-
- {survey.templateType ? (
-
- Dette er malen for arrangementer av type{' '}
- {displayNameForEventType(survey.templateType)}
-
- ) : (
- <>
-
- Spørreundersøkelse for{' '}
- {event.title}
-
+
+
+ {survey.templateType ? (
+
+ Dette er malen for arrangementer av type{' '}
+ {displayNameForEventType(survey.templateType)}
+
+ ) : (
+ <>
+
+ Spørreundersøkelse for{' '}
+ {event.title}
+
-
- Aktiv fra
-
+
+ Aktiv fra
+
-
- Svar på undersøkelsen
-
- >
- )}
-
-
+
+ Svar på undersøkelsen
+
+ >
+ )}
+
+
-
-
-
+
+
);
};
diff --git a/app/routes/surveys/components/SurveyList/SurveyList.tsx b/app/routes/surveys/components/SurveyList/SurveyList.tsx
index 2f82223a59..ba5e1ca6c4 100644
--- a/app/routes/surveys/components/SurveyList/SurveyList.tsx
+++ b/app/routes/surveys/components/SurveyList/SurveyList.tsx
@@ -7,14 +7,15 @@ import type { DetailedSurvey } from 'app/store/models/Survey';
type Props = {
surveys: DetailedSurvey[];
fetching: boolean;
+ isTemplates?: boolean;
};
-const SurveyList = ({ surveys, fetching }: Props) => {
+const SurveyList = ({ surveys, fetching, isTemplates }: Props) => {
if (isEmpty(surveys) && !fetching) {
return (
}
- body="Ingen spørreundersøkelser funnet"
+ body={`Ingen ${isTemplates ? 'maler' : 'spørreundersøkelser'} funnet`}
/>
);
}
diff --git a/app/routes/surveys/components/SurveyList/SurveyListPage.tsx b/app/routes/surveys/components/SurveyList/SurveyListPage.tsx
index 89fc6347b0..aced6e5892 100644
--- a/app/routes/surveys/components/SurveyList/SurveyListPage.tsx
+++ b/app/routes/surveys/components/SurveyList/SurveyListPage.tsx
@@ -1,56 +1,32 @@
-import { LinkButton, Page } from '@webkom/lego-bricks';
import { usePreparedEffect } from '@webkom/react-prepare';
import { Helmet } from 'react-helmet-async';
-import {
- fetchAll as fetchSurveys,
- fetchTemplates,
-} from 'app/actions/SurveyActions';
-import { NavigationTab } from 'app/components/NavigationTab/NavigationTab';
+import { fetchAll as fetchSurveys } from 'app/actions/SurveyActions';
import Paginator from 'app/components/Paginator';
import { selectPaginationNext } from 'app/reducers/selectors';
-import { selectAllSurveys, selectSurveyTemplates } from 'app/reducers/surveys';
+import { selectAllSurveys } from 'app/reducers/surveys';
import { useAppDispatch, useAppSelector } from 'app/store/hooks';
import { EntityType } from 'app/store/models/entities';
import { guardLogin } from 'app/utils/replaceUnlessLoggedIn';
import SurveyList from './SurveyList';
import type { DetailedSurvey } from 'app/store/models/Survey';
-type Props = {
- templates?: boolean;
-};
-const SurveyListPage = ({ templates }: Props) => {
+const SurveyListPage = () => {
const dispatch = useAppDispatch();
- const fetchAll = templates ? fetchTemplates : fetchSurveys;
- usePreparedEffect('fetchSurveys', () => dispatch(fetchAll()), [templates]);
+ usePreparedEffect('fetchSurveys', () => dispatch(fetchSurveys()), []);
- const surveys = useAppSelector((state) =>
- templates
- ? selectSurveyTemplates(state)
- : selectAllSurveys(state).filter((survey) => !survey.templateType),
- ) as DetailedSurvey[];
+ const surveys = useAppSelector(selectAllSurveys) as DetailedSurvey[];
const { pagination } = useAppSelector(
selectPaginationNext({
- endpoint: templates ? '/survey-templates/' : '/surveys/',
+ endpoint: '/surveys/',
entity: EntityType.Surveys,
query: {},
}),
);
return (
- Ny undersøkelse
- }
- tabs={
- <>
- Undersøkelser
- Maler
- >
- }
- >
+ <>
{
fetching={pagination.fetching}
fetchNext={() => {
dispatch(
- fetchAll({
+ fetchSurveys({
next: true,
}),
);
@@ -66,7 +42,7 @@ const SurveyListPage = ({ templates }: Props) => {
>
-
+ >
);
};
diff --git a/app/routes/surveys/components/SurveyList/SurveyTemplatesListPage.tsx b/app/routes/surveys/components/SurveyList/SurveyTemplatesListPage.tsx
new file mode 100644
index 0000000000..2f29d729bc
--- /dev/null
+++ b/app/routes/surveys/components/SurveyList/SurveyTemplatesListPage.tsx
@@ -0,0 +1,57 @@
+import { usePreparedEffect } from '@webkom/react-prepare';
+import { Helmet } from 'react-helmet-async';
+import { fetchTemplates } from 'app/actions/SurveyActions';
+import Paginator from 'app/components/Paginator';
+import { selectPaginationNext } from 'app/reducers/selectors';
+import { selectSurveyTemplates } from 'app/reducers/surveys';
+import { useAppDispatch, useAppSelector } from 'app/store/hooks';
+import { EntityType } from 'app/store/models/entities';
+import { guardLogin } from 'app/utils/replaceUnlessLoggedIn';
+import SurveyList from './SurveyList';
+import type { DetailedSurvey } from 'app/store/models/Survey';
+
+const SurveyTemplatesListPage = () => {
+ const dispatch = useAppDispatch();
+
+ usePreparedEffect(
+ 'fetchSurveyTemplates',
+ () => dispatch(fetchTemplates()),
+ [],
+ );
+
+ const surveys = useAppSelector(selectSurveyTemplates) as DetailedSurvey[];
+
+ const { pagination } = useAppSelector(
+ selectPaginationNext({
+ endpoint: '/survey-templates/',
+ entity: EntityType.Surveys,
+ query: {},
+ }),
+ );
+
+ return (
+ <>
+
+
+ {
+ dispatch(
+ fetchTemplates({
+ next: true,
+ }),
+ );
+ }}
+ >
+
+
+ >
+ );
+};
+
+export default guardLogin(SurveyTemplatesListPage);
diff --git a/app/routes/surveys/components/SurveysWrapper.tsx b/app/routes/surveys/components/SurveysWrapper.tsx
new file mode 100644
index 0000000000..f5fa4e2d9b
--- /dev/null
+++ b/app/routes/surveys/components/SurveysWrapper.tsx
@@ -0,0 +1,49 @@
+import { LoadingPage, Page, PageCover } from '@webkom/lego-bricks';
+import { Helmet } from 'react-helmet-async';
+import { Outlet, useParams } from 'react-router-dom';
+import { useFetchedSurveySubmissions } from 'app/reducers/surveySubmissions';
+import { useFetchedSurvey } from 'app/reducers/surveys';
+import { useAppSelector } from 'app/store/hooks';
+import { SurveyDetailTabs } from '../utils';
+import type { SurveysRouteContext } from 'app/routes/surveys';
+
+type Params = {
+ surveyId: string;
+};
+
+const SurveysWrapper = () => {
+ const { surveyId } = useParams() as Params;
+ const { survey, event } = useFetchedSurvey('surveyWrapper', surveyId);
+ const submissions = useFetchedSurveySubmissions(
+ 'surveySubmissions',
+ surveyId,
+ );
+ const fetching = useAppSelector((state) => state.surveys.fetching);
+
+ if (!survey) {
+ return ;
+ }
+
+ const isTemplate = !!survey.templateType;
+
+ return (
+
+ )
+ }
+ title={survey.title}
+ back={{ href: `/surveys/${isTemplate ? 'templates' : ''}` }}
+ tabs={!isTemplate && }
+ >
+
+
+
+ );
+};
+
+export default SurveysWrapper;
diff --git a/app/routes/surveys/index.tsx b/app/routes/surveys/index.tsx
index a28f3a7d35..093aa58496 100644
--- a/app/routes/surveys/index.tsx
+++ b/app/routes/surveys/index.tsx
@@ -1,12 +1,20 @@
import loadable from '@loadable/component';
+import { Page } from '@webkom/lego-bricks';
import { type RouteObject, Outlet } from 'react-router-dom';
+import { NavigationTab } from 'app/components/NavigationTab/NavigationTab';
+import { LinkButton } from 'packages/lego-bricks/src/components/Button';
import pageNotFound from '../pageNotFound';
+import type { EventForSurvey } from 'app/store/models/Event';
import type { DetailedSurvey } from 'app/store/models/Survey';
import type { SurveySubmission } from 'app/store/models/SurveySubmission';
const SurveyListPage = loadable(
() => import('./components/SurveyList/SurveyListPage'),
);
+const SurveyTemplatesListPage = loadable(
+ () => import('./components/SurveyList/SurveyTemplatesListPage'),
+);
+const SurveysWrapper = loadable(() => import('./components/SurveysWrapper'));
const SurveyDetailPage = loadable(() => import('./components/SurveyDetail'));
const AddSurveyPage = loadable(
() => import('./components/SurveyEditor/AddSurveyPage'),
@@ -30,32 +38,68 @@ const SubmissionPublicResultsPage = loadable(
() => import('./components/Submissions/SubmissionPublicResultsPage'),
);
+const SurveysOverview = () => {
+ return (
+ Ny undersøkelse
+ }
+ tabs={
+ <>
+ Undersøkelser
+
+ Maler
+
+ >
+ }
+ >
+
+
+ );
+};
+
export type SurveysRouteContext = {
- submissions: SurveySubmission[];
survey: DetailedSurvey;
+ event: EventForSurvey;
+ submissions: SurveySubmission[];
};
const surveysRoute: RouteObject[] = [
- { index: true, Component: SurveyListPage },
- { path: 'templates', Component: () => },
+ {
+ path: '',
+ Component: SurveysOverview,
+ children: [
+ { index: true, Component: SurveyListPage },
+ { path: 'templates', Component: SurveyTemplatesListPage },
+ ],
+ },
{ path: 'add', Component: AddSurveyPage },
- { path: ':surveyId', Component: SurveyDetailPage },
{ path: ':surveyId/edit', Component: EditSurveyPage },
{ path: ':surveyId/answer', Component: AddSubmissionPage },
{
- path: ':surveyId/submissions/*',
- Component: () => (
-
- {({ submissions, survey }) => (
-
- )}
-
- ),
+ path: ':surveyId',
+ Component: SurveysWrapper,
children: [
- { path: 'summary', Component: SubmissionsSummary },
- { path: 'individual', Component: SubmissionsIndividual },
+ { index: true, Component: SurveyDetailPage },
+ {
+ path: 'submissions',
+ Component: () => (
+
+ {({ survey, event, submissions }) => (
+
+ )}
+
+ ),
+ children: [
+ { path: 'summary', Component: SubmissionsSummary },
+ { path: 'individual', Component: SubmissionsIndividual },
+ ],
+ },
],
},
{ path: ':surveyId/results', Component: SubmissionPublicResultsPage },
diff --git a/packages/lego-bricks/src/components/Layout/Page/Page.module.css b/packages/lego-bricks/src/components/Layout/Page/Page.module.css
index b05c1a40d7..84e4204736 100644
--- a/packages/lego-bricks/src/components/Layout/Page/Page.module.css
+++ b/packages/lego-bricks/src/components/Layout/Page/Page.module.css
@@ -11,6 +11,7 @@
align-items: center;
width: fit-content;
margin-bottom: var(--spacing-sm);
+ outline: none;
}
span.backLabel {
@@ -22,6 +23,7 @@
transition: transform var(--easing-medium);
}
+ .back:focus > .backIcon,
.back:hover > .backIcon {
transform: translateX(calc(-1 * var(--spacing-xs)));
}
diff --git a/packages/lego-bricks/src/components/Tabs/Tab.module.css b/packages/lego-bricks/src/components/Tabs/Tab.module.css
index 5dac8e5631..67559b95e5 100644
--- a/packages/lego-bricks/src/components/Tabs/Tab.module.css
+++ b/packages/lego-bricks/src/components/Tabs/Tab.module.css
@@ -1,15 +1,28 @@
+.tabContainer {
+ position: relative;
+ display: inline-flex;
+ flex-direction: column;
+}
+
.tab {
display: inline-block;
color: var(--lego-font-color);
padding: var(--spacing-sm) var(--spacing-md);
- border-bottom: 2px solid var(--border-gray);
-}
-
-.tab.active {
- border-bottom: 2px solid var(--color-black);
+ cursor: pointer;
+ outline: none;
}
.tab.disabled {
- color: var(--border-gray);
+ opacity: 0.5;
pointer-events: none;
}
+
+.tabIndicator {
+ position: absolute;
+ bottom: -2px;
+ height: 2px;
+ background-color: var(--color-black);
+ transition:
+ transform var(--easing-medium),
+ width var(--easing-medium);
+}
diff --git a/packages/lego-bricks/src/components/Tabs/Tab.tsx b/packages/lego-bricks/src/components/Tabs/Tab.tsx
index 51280577c5..b6f535b81e 100644
--- a/packages/lego-bricks/src/components/Tabs/Tab.tsx
+++ b/packages/lego-bricks/src/components/Tabs/Tab.tsx
@@ -13,31 +13,31 @@ type Props = {
};
export const Tab = ({ active, disabled, onPress, href, children }: Props) => {
- const className = cx(
- styles.tab,
- active && styles.active,
- disabled && styles.disabled,
- );
+ const className = cx(styles.tab, disabled && styles.disabled);
- return href ? (
-
- {children}
-
- ) : (
-
+ return (
+
+ {href ? (
+
+ {children}
+
+ ) : (
+
+ )}
+
);
};
diff --git a/packages/lego-bricks/src/components/Tabs/TabContainer.module.css b/packages/lego-bricks/src/components/Tabs/TabContainer.module.css
index 724f2f6c8e..c1e2a3bfbb 100644
--- a/packages/lego-bricks/src/components/Tabs/TabContainer.module.css
+++ b/packages/lego-bricks/src/components/Tabs/TabContainer.module.css
@@ -1,8 +1,24 @@
.container {
margin: var(--spacing-sm) 0 var(--spacing-md);
+ position: relative;
+ display: flex;
+ flex-wrap: wrap;
}
-.spacer {
- flex-grow: 1;
+.tabList {
+ display: flex;
+ position: relative;
border-bottom: 2px solid var(--border-gray);
+ width: 100%;
+}
+
+.indicator {
+ position: absolute;
+ bottom: -2px;
+ left: 0;
+ height: 2px;
+ background-color: var(--color-black);
+ transition:
+ transform var(--easing-medium),
+ width var(--easing-medium);
}
diff --git a/packages/lego-bricks/src/components/Tabs/TabContainer.tsx b/packages/lego-bricks/src/components/Tabs/TabContainer.tsx
index 33117a7a2b..8c0f9a7d3d 100644
--- a/packages/lego-bricks/src/components/Tabs/TabContainer.tsx
+++ b/packages/lego-bricks/src/components/Tabs/TabContainer.tsx
@@ -1,5 +1,6 @@
import cx from 'classnames';
-import { Flex } from '../Layout';
+import { useEffect, useState } from 'react';
+import { useLocation } from 'react-router-dom';
import styles from './TabContainer.module.css';
import type { ReactNode } from 'react';
@@ -9,9 +10,28 @@ type Props = {
children?: ReactNode;
};
-export const TabContainer = ({ className, lineColor, children }: Props) => (
-
- {children}
-
-
-);
+export const TabContainer = ({ className, lineColor, children }: Props) => {
+ const [indicatorStyle, setIndicatorStyle] = useState({});
+ const location = useLocation();
+
+ useEffect(() => {
+ const activeTab = document.querySelector('[data-active="true"]');
+ if (activeTab) {
+ const width = activeTab.clientWidth;
+ const left = (activeTab as HTMLElement).offsetLeft;
+ setIndicatorStyle({
+ width: `${width}px`,
+ transform: `translateX(${left}px)`,
+ });
+ }
+ }, [children, location.pathname]);
+
+ return (
+
+ );
+};