{
- session.remove('osc-resource-vote-pending');
+ if (props.votes.voteType === "countPerTag" || props.votes.voteType === "budgetingPerTag") {
+ session.remove('osc-resource-vote-pending-per-tag');
+
+ if (activeTagTab) {
+ const activeTag = tagCounter.find(tagObj => tagObj[activeTagTab]);
+ if (activeTag) {
+ const selectedResources = activeTag[activeTagTab].selectedResources;
+ const resourceInTagList = selectedResources.find((r) => r.id === resource.id);
+
+ if (resourceInTagList) {
+ activeTag[activeTagTab].selectedResources = selectedResources.filter((r) => r.id !== resource.id);
+ activeTag[activeTagTab].current -= props.votes.voteType === "budgetingPerTag" ? resource.budget : 1;
+ } else {
+ activeTag[activeTagTab].selectedResources.push(resource);
+ activeTag[activeTagTab].current += props.votes.voteType === "budgetingPerTag" ? resource.budget : 1;
+ }
- const resourceInBudgetList = selectedResources.find(
- (r) => r.id === resource.id
- );
+ setTagCounter([...tagCounter]);
+ }
+ }
+ } else {
+ session.remove('osc-resource-vote-pending');
- if (resourceInBudgetList) {
- setSelectedResources(
- selectedResources.filter((r) => r.id !== resource.id)
+ const resourceInBudgetList = selectedResources.find(
+ (r) => r.id === resource.id
);
- } else {
- setSelectedResources([...selectedResources, resource]);
+
+ if (resourceInBudgetList) {
+ setSelectedResources(
+ selectedResources.filter((r) => r.id !== resource.id)
+ );
+ } else {
+ setSelectedResources([...selectedResources, resource]);
+ }
}
}}
resourceDetailIndex={resourceDetailIndex}
@@ -353,7 +501,7 @@ function StemBegroot({
/>
- {props.votes.voteType === 'budgeting' ?
+ {(props.votes.voteType === 'budgeting' || props?.votes?.voteType === 'budgetingPerTag' ) ?
<>
{usedBudgetList}
@@ -396,32 +544,83 @@ function StemBegroot({
allResourceInList={resources?.records}
selectedResources={selectedResources}
maxNrOfResources={props.votes.maxResources || 0}
- typeIsBudgeting={props.votes.voteType === 'budgeting'}
- onSelectedResourceRemove={(r) => {
+ typeIsBudgeting={props.votes.voteType === 'budgeting' || props.votes.voteType === 'budgetingPerTag'}
+ tagsToDisplay={tagsToDisplay}
+ activeTagTab={activeTagTab}
+ setActiveTagTab={setActiveTagTab}
+ typeIsPerTag={props?.votes?.voteType === "countPerTag" || props?.votes?.voteType === "budgetingPerTag"}
+ onSelectedResourceRemove={(resource: {id: number, budget: number}) => {
session.remove('osc-resource-vote-pending');
+ session.remove('osc-resource-vote-pending-per-tag');
+
+ if (props?.votes?.voteType === "countPerTag" || props?.votes?.voteType === "budgetingPerTag") {
+ setTagCounter(prevTagCounter => {
+ return prevTagCounter.map(tagObj => {
+ if (tagObj[activeTagTab]) {
+ const updatedSelectedResources = tagObj[activeTagTab].selectedResources.filter((selectedResource: {id: number}) => selectedResource.id !== resource.id);
+ const updatedCurrentCount = tagObj[activeTagTab].current - (props.votes.voteType === "budgetingPerTag" ? resource.budget : 1);
+
+ return {
+ [activeTagTab]: {
+ ...tagObj[activeTagTab],
+ selectedResources: updatedSelectedResources,
+ current: updatedCurrentCount
+ }
+ };
+ }
+ return tagObj;
+ });
+ });
+ }
+
setSelectedResources(
- selectedResources.filter((resource) => resource.id !== r.id)
+ selectedResources.filter((r) => r.id !== resource.id)
);
}}
decideCanAddMore={() => {
- let notUsedResources = resources?.records.filter(
- (allR: { id: number }) =>
- !selectedResources.find(
- (selectedR) => allR.id === selectedR.id
- )
- );
+ if (props?.votes?.voteType === "countPerTag" || props?.votes?.voteType === "budgetingPerTag") {
+ const activeTagData = tagCounter.find(tagObj => tagObj[activeTagTab]);
+ if (!activeTagData) return false;
- const canAddMore =
- props.votes.voteType === 'budgeting'
+ const activeTag = activeTagData[activeTagTab];
+ const maxLimit = activeTag.max;
+ const currentCount = activeTag.current;
+
+ if (props.votes.voteType === "countPerTag") {
+ return currentCount < maxLimit;
+ }
+
+ if (props.votes.voteType === "budgetingPerTag") {
+ let notUsedResources = filteredResources.filter(
+ (allR: { id: number }) =>
+ !selectedResources.find(
+ (selectedR) => allR.id === selectedR.id
+ )
+ );
+
+ return notUsedResources.some(
+ (r: { budget: number }) =>
+ r.budget <= (maxLimit - currentCount)
+ );
+ }
+ } else {
+ let notUsedResources = resources?.records.filter(
+ (allR: { id: number }) =>
+ !selectedResources.find(
+ (selectedR) => allR.id === selectedR.id
+ )
+ );
+
+ return props.votes.voteType === 'budgeting'
? notUsedResources.some(
(r: { budget: number }) =>
r.budget < props.votes.maxBudget - budgetUsed
)
: Math.max(
- props.votes.maxResources - selectedResources.length,
- 0
- ) > 0;
- return canAddMore;
+ props.votes.maxResources - selectedResources.length,
+ 0
+ ) > 0;
+ }
}}
/>
>
@@ -440,7 +639,9 @@ function StemBegroot({
selectedResources={selectedResources}
maxBudget={props.votes.maxBudget}
maxNrOfResources={props.votes.maxResources || 0}
- typeIsBudgeting={props.votes.voteType === 'budgeting'}
+ typeIsBudgeting={props.votes.voteType === 'budgeting' || props.votes.voteType === 'budgetingPerTag'}
+ typeIsPerTag={props?.votes?.voteType === "countPerTag" || props?.votes?.voteType === "budgetingPerTag"}
+ tagCounter={tagCounter}
showInfoMenu={props.showInfoMenu}
/>
>
@@ -471,7 +672,7 @@ function StemBegroot({
) : null}
- {currentStep > 0 && currentStep < 4 ? (
+ {currentStep > 0 && currentStep < 3 ? (
) : null}
@@ -577,17 +850,34 @@ function StemBegroot({
resourceListColumns={resourceListColumns || 3}
onResourcePrimaryClicked={(resource) => {
session.remove('osc-resource-vote-pending');
+ session.remove('osc-resource-vote-pending-per-tag');
+
+ let newTagCounter = [...tagCounter];
+
+ if (props.votes.voteType === "countPerTag" || props.votes.voteType === "budgetingPerTag") {
+ newTagCounter = newTagCounter.map((tagObj) => {
+ if (tagObj[activeTagTab]) {
+ if (isInSelected(resource)) {
+ tagObj[activeTagTab].current -= props.votes.voteType === "budgetingPerTag" ? resource.budget : 1;
+ tagObj[activeTagTab].selectedResources = tagObj[activeTagTab].selectedResources.filter((selectedResource: {id: number}) => selectedResource.id !== resource.id);
+ } else {
+ tagObj[activeTagTab].current += props.votes.voteType === "budgetingPerTag" ? resource.budget : 1;
+ tagObj[activeTagTab].selectedResources.push(resource);
+ }
+ }
+ return tagObj;
+ });
- const resourceIndex = selectedResources.findIndex(
- (r) => r.id === resource.id
- );
-
- if (resourceIndex === -1) {
- setSelectedResources([...selectedResources, resource]);
+ setTagCounter(newTagCounter);
} else {
- const resources = [...selectedResources];
- resources.splice(resourceIndex, 1);
- setSelectedResources(resources);
+ const resourceIndex = selectedResources.findIndex((r) => r.id === resource.id);
+ if (resourceIndex === -1) {
+ setSelectedResources([...selectedResources, resource]);
+ } else {
+ const updatedResources = [...selectedResources];
+ updatedResources.splice(resourceIndex, 1);
+ setSelectedResources(updatedResources);
+ }
}
}}
statusIdsToLimitResourcesTo={statusIdsToLimitResourcesTo || []}
@@ -595,6 +885,11 @@ function StemBegroot({
sort={sort}
allTags={allTags}
tags={tags}
+ activeTagTab={activeTagTab}
+ setFilteredResources={setFilteredResources}
+ filteredResources={filteredResources}
+ voteType={props?.votes?.voteType || 'likes'}
+ typeSelector={typeSelector}
/>
diff --git a/packages/stem-begroot/src/step-1/begroot-budget-list/stem-begroot-budget-list.tsx b/packages/stem-begroot/src/step-1/begroot-budget-list/stem-begroot-budget-list.tsx
index cbd614c84..052481f4d 100644
--- a/packages/stem-begroot/src/step-1/begroot-budget-list/stem-begroot-budget-list.tsx
+++ b/packages/stem-begroot/src/step-1/begroot-budget-list/stem-begroot-budget-list.tsx
@@ -1,5 +1,5 @@
import './stem-begroot-budget-list.css';
-import React from 'react';
+import React, { Dispatch, SetStateAction } from 'react';
import { BudgetStatusPanel } from '../../reuseables/budget-status-panel';
import { IconButton, Image, Spacer } from '@openstad-headless/ui/src';
import "@utrecht/component-library-css";
@@ -21,6 +21,10 @@ export const StemBegrootBudgetList = ({
panelTitle,
budgetChosenTitle,
budgetRemainingTitle,
+ tagsToDisplay,
+ activeTagTab = '',
+ typeIsPerTag = false,
+ setActiveTagTab
}: {
allResourceInList: Array
selectedResources: Array;
@@ -30,12 +34,16 @@ export const StemBegrootBudgetList = ({
introText?: string;
showInfoMenu?: boolean;
decideCanAddMore: () => boolean;
- onSelectedResourceRemove: (resource: { id: number }) => void;
+ onSelectedResourceRemove: (resource: { id: number, budget: number }) => void;
step1Title: string;
resourceCardTitle: string;
panelTitle?: string;
budgetChosenTitle?: string;
budgetRemainingTitle?: string;
+ tagsToDisplay?: Array;
+ activeTagTab?: string;
+ typeIsPerTag?: boolean;
+ setActiveTagTab?: Dispatch>;
}) => {
const budgetUsed = selectedResources.reduce(
(total, cv) => total + cv.budget,
@@ -136,7 +144,27 @@ export const StemBegrootBudgetList = ({
) : null}
-
+
+ { (typeIsPerTag && !!tagsToDisplay) && (
+
+ {tagsToDisplay?.map((tag: string) => (
+
+
+
+ ))}
+
+ )}
+
>
);
diff --git a/packages/stem-begroot/src/step-1/begroot-detail-dialog/stem-begroot-detail-dialog.tsx b/packages/stem-begroot/src/step-1/begroot-detail-dialog/stem-begroot-detail-dialog.tsx
index 3e3fa78fd..c132613dd 100644
--- a/packages/stem-begroot/src/step-1/begroot-detail-dialog/stem-begroot-detail-dialog.tsx
+++ b/packages/stem-begroot/src/step-1/begroot-detail-dialog/stem-begroot-detail-dialog.tsx
@@ -60,13 +60,6 @@ export const StemBegrootResourceDetailDialog = ({
buttonText={{ next: 'Volgende inzending', previous: 'Vorige inzending' }}
items={resources && resources.length > 0 ? resources : []}
itemRenderer={(resource) => {
- const theme = resource.tags
- ?.filter((t: any) => t.type === 'theme')
- ?.at(0);
- const area = resource.tags
- ?.filter((t: any) => t.type === 'area')
- ?.at(0);
-
const canUseButton = resourceBtnEnabled(resource);
const primaryButtonText = resourceBtnTextHandler(resource);
const originalUrl = defineOriginalUrl(resource);
@@ -98,7 +91,10 @@ export const StemBegrootResourceDetailDialog = ({
if (resourceImages.length === 0) {
resourceImages = [{ url: defaultImage || '' }];
+
+ if (!defaultImage) {
hasImages = 'resource-has-no-images';
+ }
}
return (
@@ -112,7 +108,7 @@ export const StemBegrootResourceDetailDialog = ({
itemRenderer={(i) => {
if (i.url) {
return
- } else {
+ } else if (resource.location) {
return ;
tags?: Array;
header?: React.JSX.Element;
+ activeTagTab?: string;
+ typeSelector?: string;
+ voteType?: string;
+ setFilteredResources?: (resources: Array) => void;
+ filteredResources?: Array;
}) => {
// @ts-ignore
const intTags = tags.map(tag => parseInt(tag, 10));
@@ -79,6 +89,16 @@ export const StemBegrootResourceList = ({
});
})
)
+ ?.filter((resource: any) => {
+ if (voteType === 'countPerTag' || voteType === 'budgetingPerTag') {
+ if (typeSelector === 'tag') {
+ return resource.tags.some((tag: { name: string }) => tag.name === activeTagTab);
+ } else {
+ return resource.tags.some((tag: { type: string }) => tag.type === activeTagTab);
+ }
+ }
+ return true;
+ })
?.filter((resource: any) =>
(!statusIdsToLimitResourcesTo || statusIdsToLimitResourcesTo.length === 0) || statusIdsToLimitResourcesTo.some((statusId) => resource.statuses && Array.isArray(resource.statuses) && resource.statuses.some((o: { id: number }) => o.id === statusId))
)
@@ -101,6 +121,12 @@ export const StemBegrootResourceList = ({
return 0;
});
+ if ( (voteType === 'countPerTag' || voteType === 'budgetingPerTag') && setFilteredResources) {
+ if (JSON.stringify(filtered) !== JSON.stringify(filteredResources)) {
+ setFilteredResources(filtered);
+ }
+ }
+
return (
;
@@ -18,6 +19,8 @@ type Props = {
panelTitle?: string;
budgetChosenTitle?: string;
budgetRemainingTitle?: string;
+ typeIsPerTag?: boolean;
+ tagCounter?: Array;
};
export const BegrotenSelectedOverview = ({
@@ -32,69 +35,151 @@ export const BegrotenSelectedOverview = ({
panelTitle,
budgetChosenTitle,
budgetRemainingTitle,
+ typeIsPerTag = false,
+ tagCounter = []
}: Props) => {
+ let resourcesToShow = selectedResources;
+
+ if (typeIsPerTag) {
+ resourcesToShow = tagCounter.reduce((acc: Array, tagObj) => {
+ const tagKey = Object.keys(tagObj)[0];
+ const tagResources = tagObj[tagKey].selectedResources;
+ return [...acc, ...tagResources];
+ }, []);
+ }
+
return (
<>
-
-
{introText}
- {showInfoMenu && (
-
- )}
-
-
-
-
-
{step2Title}
-
-
- {selectedResources.map((resource) => {
- let defaultImage = '';
-
- interface Tag {
- name: string;
- defaultResourceImage?: string;
- }
-
- if (Array.isArray(resource?.tags)) {
- const sortedTags = resource.tags.sort((a: Tag, b: Tag) => a.name.localeCompare(b.name));
- const tagWithImage = sortedTags.find((tag: Tag) => tag.defaultResourceImage);
- defaultImage = tagWithImage?.defaultResourceImage || '';
- }
-
- const resourceImages = (Array.isArray(resource.images) && resource.images.length > 0) ? resource.images?.at(0)?.url : defaultImage;
- const hasImages = !!resourceImages ? '' : 'resource-has-no-images';
-
- return (
-
-
-
-
-
{resource.title}
- {typeIsBudgeting ? (
-
- €{resource.budget?.toLocaleString('nl-NL') || 0}
-
- ) : null}
+ {typeIsPerTag ? (
+
+
{introText}
+
+
+ {tagCounter.map((tagObj) => {
+ const tagName = Object.keys(tagObj)[0];
+ const tagData = tagObj[tagName];
+
+ return (
+
+
+
+
+
+
{tagName.charAt(0).toUpperCase() + tagName.slice(1)}
+
+ {tagData.selectedResources.map((resource) => {
+ let defaultImage = '';
+
+ interface Tag {
+ name: string;
+ defaultResourceImage?: string;
+ }
+
+ if (Array.isArray(resource?.tags)) {
+ const sortedTags = resource.tags.sort((a: Tag, b: Tag) => a.name.localeCompare(b.name));
+ const tagWithImage = sortedTags.find((tag: Tag) => tag.defaultResourceImage);
+ defaultImage = tagWithImage?.defaultResourceImage || '';
+ }
+
+ const resourceImages = (Array.isArray(resource.images) && resource.images.length > 0) ? resource.images?.at(0)?.url : defaultImage;
+ const hasImages = !!resourceImages ? '' : 'resource-has-no-images';
+
+ return (
+
+
+
+
+
{resource.title}
+ {typeIsBudgeting ? (
+
+ €{resource.budget?.toLocaleString('nl-NL') || 0}
+
+ ) : null}
+
+
+
+ );
+ })}
+
+
+
+ {showInfoMenu && (
+
+ )}
-
+
+ );
+ })}
+
+ ) : (
+
+
{introText}
+ {showInfoMenu && (
+
+ )}
+
+
+ {resourcesToShow.map((resource) => {
+ let defaultImage = '';
+
+ interface Tag {
+ name: string;
+ defaultResourceImage?: string;
+ }
+
+ if (Array.isArray(resource?.tags)) {
+ const sortedTags = resource.tags.sort((a: Tag, b: Tag) => a.name.localeCompare(b.name));
+ const tagWithImage = sortedTags.find((tag: Tag) => tag.defaultResourceImage);
+ defaultImage = tagWithImage?.defaultResourceImage || '';
+ }
+
+ const resourceImages = (Array.isArray(resource.images) && resource.images.length > 0) ? resource.images?.at(0)?.url : defaultImage;
+ const hasImages = !!resourceImages ? '' : 'resource-has-no-images';
-
- )
- })}
-
+ return (
+
+
+
+
+
{resource.title}
+ {typeIsBudgeting ? (
+
+ €{resource.budget?.toLocaleString('nl-NL') || 0}
+
+ ) : null}
+
+
+
+ );
+ })}
+
+ )}
>
);
};