Skip to content

Commit

Permalink
Merge branch 'main' into feature/III-4493
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/pages/steps/AdditionalInformationStep/ContactInfoStep.tsx
  • Loading branch information
Anahkiasen committed Sep 21, 2023
2 parents 7ea2225 + 21c4530 commit 02db456
Show file tree
Hide file tree
Showing 21 changed files with 199 additions and 105 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

Copy the `.env.example` and rename it to `.env.local`.
Fill in the correct values for the variables.
For running it in combination with [udb3-backend](https://github.com/cultuurnet/udb3-backend) on [Docker](https://www.docker.com),
a sample `.env` is available in [appconfig](https://github.com/cultuurnet/appconfig/blob/main/files/udb3/docker/udb3-frontend/.env).

## Build Setup

Expand Down
1 change: 1 addition & 0 deletions src/hooks/useHandleWindowMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const WindowMessageTypes = {
URL_UNKNOWN: 'URL_UNKNOWN',
JOB_ADDED: 'JOB_ADDED',
HTTP_ERROR_CODE: 'HTTP_ERROR_CODE',
OFFER_MODERATED: 'OFFER_MODERATED',
};

const useHandleWindowMessage = (eventsMap = {}) => {
Expand Down
5 changes: 4 additions & 1 deletion src/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,10 @@
"everyone": "Für alle",
"members": "Nur für Mitglieder",
"title": "Zugang",
"help": "Ihr Artikel wird nur auf kulturellen Bildungskanälen wie cultuurkuur.be veröffentlicht. Nach der Veröffentlichung können Sie spezifische Informationen für Schulen hinzufügen."
"help": {
"education": "Ihr Artikel wird nur auf kulturellen Bildungskanälen wie cultuurkuur.be veröffentlicht. Nach der Veröffentlichung können Sie spezifische Informationen für Schulen hinzufügen.",
"members": "Ihr Item wird nur auf Kanälen für Vereinigungen und deren Mitglieder veröffentlicht."
}
},
"contact_info": {
"add_more_singular": "Kontaktdaten hinzufügen",
Expand Down
5 changes: 4 additions & 1 deletion src/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,10 @@
"everyone": "Pour tout le monde",
"members": "Seulement pour des membres",
"title": "Accès",
"help": "Votre article ne sera publié que sur des chaînes d'éducation culturelle telles que cultuurkuur.be. Après la publication, vous pouvez ajouter des informations spécifiques pour les écoles."
"help": {
"education": "Votre article ne sera publié que sur des chaînes d'éducation culturelle telles que cultuurkuur.be. Après la publication, vous pouvez ajouter des informations spécifiques pour les écoles.",
"members": "Votre article est seulement publié sur des chaînes pour des associations et leurs membres."
}
},
"contact_info": {
"add_more_singular": "Ajouter des coordonnées",
Expand Down
5 changes: 4 additions & 1 deletion src/i18n/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,10 @@
"education": "Specifiek voor scholen",
"everyone": "Voor iedereen",
"members": "Enkel voor leden",
"help": "Je item wordt enkel gepubliceerd op cultuureducatieve kanalen zoals cultuurkuur.be. Na het publiceren kan je nog specifieke informatie voor scholen toevoegen."
"help": {
"education": "Je item wordt enkel gepubliceerd op cultuureducatieve kanalen zoals cultuurkuur.be. Na het publiceren kan je nog specifieke informatie voor scholen toevoegen.",
"members": "Je item wordt enkel gepubliceerd op kanalen voor verenigingen en hun leden."
}
},
"contact_info": {
"add_more_singular": "Contactgegevens toevoegen",
Expand Down
2 changes: 2 additions & 0 deletions src/layouts/Announcements.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,11 @@ const AnnouncementContent = ({
alt={callToActionLabel ?? ''}
width="100%"
maxHeight="30vh"
objectFit="contain"
opacity={{ hover: 0.85 }}
/>
);

return (
<Stack as="article" padding={4} spacing={3} width="70%">
<Title>{title}</Title>
Expand Down
18 changes: 12 additions & 6 deletions src/layouts/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ import {
} from '@/hooks/api/user';
import { useCookiesWithOptions } from '@/hooks/useCookiesWithOptions';
import { FeatureFlags, useFeatureFlag } from '@/hooks/useFeatureFlag';
import {
useHandleWindowMessage,
WindowMessageTypes,
} from '@/hooks/useHandleWindowMessage';
import { useLocalStorage } from '@/hooks/useLocalStorage';
import { useMatchBreakpoint } from '@/hooks/useMatchBreakpoint';
import {
Features,
NewFeatureTooltip,
QuestionCircleIcon,
} from '@/pages/NewFeatureTooltip';
import { QuestionCircleIcon } from '@/pages/NewFeatureTooltip';
import type { Values } from '@/types/Values';
import { Badge } from '@/ui/Badge';
import { Button, ButtonVariants } from '@/ui/Button';
Expand Down Expand Up @@ -317,6 +317,7 @@ const BetaVersionToggle = ({
const Sidebar = () => {
const { t, i18n } = useTranslation();

const queryClient = useQueryClient();
const storage = useLocalStorage();

const [isJobLoggerVisible, setIsJobLoggerVisible] = useState(true);
Expand Down Expand Up @@ -422,6 +423,11 @@ const Sidebar = () => {
// @ts-expect-error
}, [getRolesQuery.data]);

useHandleWindowMessage({
[WindowMessageTypes.OFFER_MODERATED]: () =>
queryClient.invalidateQueries(['events']),
});

const announcements = useMemo(
() =>
rawAnnouncements.map((announcement) => {
Expand Down Expand Up @@ -641,4 +647,4 @@ const Sidebar = () => {
];
};

export { Sidebar };
export { PermissionTypes, Sidebar };
10 changes: 10 additions & 0 deletions src/pages/dashboard/index.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ import {
useGetPlacesByCreatorQuery,
} from '@/hooks/api/places';
import {
useGetPermissionsQuery,
useGetUserQuery,
useGetUserQueryServerSide,
User,
} from '@/hooks/api/user';
import { FeatureFlags, useFeatureFlag } from '@/hooks/useFeatureFlag';
import { PermissionTypes } from '@/layouts/Sidebar';
import { Footer } from '@/pages/Footer';
import type { Event } from '@/types/Event';
import { Offer } from '@/types/Offer';
Expand Down Expand Up @@ -360,6 +362,7 @@ const OrganizerRow = ({
const { t, i18n } = useTranslation();

const getUserQuery = useGetUserQuery();
const getPermissionsQuery = useGetPermissionsQuery();
// @ts-expect-error
const userId = getUserQuery.data?.sub;
// @ts-expect-error
Expand All @@ -372,6 +375,8 @@ const OrganizerRow = ({
const formattedAddress = address ? formatAddressInternal(address) : '';
const editUrl = `/organizer/${parseOfferId(organizer['@id'])}/edit`;
const previewUrl = `/organizer/${parseOfferId(organizer['@id'])}/preview`;
// @ts-expect-error
const permissions = getPermissionsQuery?.data ?? [];

return (
<Row
Expand All @@ -384,6 +389,11 @@ const OrganizerRow = ({
<Link href={editUrl} variant={LinkVariants.BUTTON_SECONDARY} key="edit">
{t('dashboard.actions.edit')}
</Link>,
permissions?.includes(PermissionTypes.ORGANISATIES_BEHEREN) && (
<Dropdown.Item onClick={() => onDelete(organizer)} key="delete">
{t('dashboard.actions.delete')}
</Dropdown.Item>
),
]}
status={{
isExternalCreator,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ import { Text } from '@/ui/Text';
import { getGlobalBorderRadius, getValueFromTheme } from '@/ui/theme';
import { Title } from '@/ui/Title';
import { formatDateToISO } from '@/utils/formatDateToISO';
import { isValidEmail, isValidPhone, isValidUrl } from '@/utils/isValidInfo';
import { prefixUrlWithHttps } from '@/utils/url';

import { TabContentProps, ValidationStatus } from './AdditionalInformationStep';
import { isValidEmail, isValidPhone, isValidUrl } from './ContactInfoStep';

const schema = yup
.object({
Expand Down
16 changes: 16 additions & 0 deletions src/pages/steps/AdditionalInformationStep/ContactInfoStep.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { isValidUrl } from '@/utils/isValidInfo';

describe('isValidUrl', () => {
const tests = {
goobar: false,
'goobar.com': false,
'http://goobar.com': true,
'https://speeltuin.vlaanderen/speeltuinen': true,
'https://speeltuin.vlaanderen/speeltuinen?foo[]=bar&baz=50': true,
};

test.each(Object.entries(tests))(
'can check if url %p being valid is %p',
(url, expected) => expect(isValidUrl(url)).toBe(expected),
);
});
30 changes: 4 additions & 26 deletions src/pages/steps/AdditionalInformationStep/ContactInfoStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { ChangeEvent, FormEvent, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useQueryClient } from 'react-query';

import { EMAIL_REGEX, PHONE_REGEX, URL_REGEX } from '@/constants/Regex';
import { useAddContactPointMutation } from '@/hooks/api/offers';
import { useGetEntityByIdAndScope } from '@/hooks/api/scope';
import { Button, ButtonVariants } from '@/ui/Button';
Expand All @@ -12,6 +11,7 @@ import { Inline } from '@/ui/Inline';
import { Input } from '@/ui/Input';
import { Select } from '@/ui/Select';
import { getStackProps, Stack, StackProps } from '@/ui/Stack';
import { isValidInfo } from '@/utils/isValidInfo';
import { prefixUrlWithHttps } from '@/utils/url';

import { TabContentProps, ValidationStatus } from './AdditionalInformationStep';
Expand All @@ -33,29 +33,6 @@ type NewContactInfo = {
value: string;
};

const isValidEmail = (email: string) => {
return (
typeof email === 'undefined' || email === '' || EMAIL_REGEX.test(email)
);
};

const isValidUrl = (url: string) => {
return typeof url === 'undefined' || url === '' || URL_REGEX.test(url);
};

const isValidPhone = (phone: string) => {
return (
typeof phone === 'undefined' || phone === '' || PHONE_REGEX.test(phone)
);
};

const isValidInfo = (type: string, value: string): boolean => {
if (value === '') return true;
if (type === 'email') return isValidEmail(value);
if (type === 'url') return isValidUrl(value);
if (type === 'phone') return isValidPhone(value);
};

type Props = StackProps &
TabContentProps & {
isOrganizer?: boolean;
Expand Down Expand Up @@ -260,10 +237,12 @@ const ContactInfoStep = ({
))}
</Select>
<FormElement
id={`contact-info-value-${index}`}
alignSelf="flex-start"
width="55%"
Component={
<Input
data-testid="contact-info-value"
value={info.value}
onChange={(e) => {
const newContactInfoState = [...contactInfoState];
Expand All @@ -277,7 +256,6 @@ const ContactInfoStep = ({
}}
/>
}
id="contact-info-value"
error={
!isFieldFocused &&
!isValidInfo(info.type, info.value) &&
Expand Down Expand Up @@ -314,5 +292,5 @@ ContactInfoStep.defaultProps = {
isOrganizer: false,
};

export { ContactInfoStep, isValidEmail, isValidPhone, isValidUrl };
export { ContactInfoStep };
export type { ContactInfo };
2 changes: 1 addition & 1 deletion src/pages/steps/AdditionalInformationStep/LabelsStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { Typeahead } from '@/ui/Typeahead';

type LabelsStepProps = StackProps & TabContentProps;

const LABEL_PATTERN = /^[0-9a-zA-Z][0-9a-zA-Z-_\s]{1,49}$/;
const LABEL_PATTERN = /^[0-9a-zA-ZÀ-ÿ][0-9a-zA-ZÀ-ÿ\-_\s]{1,49}$/;

function LabelsStep({
offerId,
Expand Down
44 changes: 25 additions & 19 deletions src/pages/steps/AudienceStep.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { yupResolver } from '@hookform/resolvers/yup';
import { useEffect } from 'react';
import { Fragment, useEffect } from 'react';
import { useForm, useWatch } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import * as yup from 'yup';
Expand Down Expand Up @@ -87,25 +87,31 @@ const AudienceStep = ({
<Text fontWeight="bold">
{t('create.additionalInformation.audience.title')}
</Text>
{Object.values(AudienceType).map((type, index) => (
<FormElement
key={index}
id={`audience-${type}`}
Component={
<RadioButtonWithLabel
{...register(`audienceType`)}
label={t(`create.additionalInformation.audience.${type}`)}
checked={watchedAudienceType === type}
onChange={() => handleOnChangeAudience(type)}
{Object.values(AudienceType).map((type, index) => {
return (
<Fragment key={index}>
<FormElement
id={`audience-${type}`}
Component={
<RadioButtonWithLabel
{...register(`audienceType`)}
label={t(`create.additionalInformation.audience.${type}`)}
checked={watchedAudienceType === type}
onChange={() => handleOnChangeAudience(type)}
/>
}
/>
}
/>
))}
{watchedAudienceType === AudienceType.EDUCATION && (
<Text variant="muted" maxWidth="30%">
{t('create.additionalInformation.audience.help')}
</Text>
)}
{watchedAudienceType === type &&
watchedAudienceType !== AudienceType.EVERYONE && (
<Text variant="muted" maxWidth="30%">
{t(
`create.additionalInformation.audience.help.${watchedAudienceType}`,
)}
</Text>
)}
</Fragment>
);
})}
</Stack>
</Stack>
);
Expand Down
Loading

0 comments on commit 02db456

Please sign in to comment.