diff --git a/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Bold.ttf b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Bold.ttf new file mode 100644 index 000000000..47e921e88 Binary files /dev/null and b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Bold.ttf differ diff --git a/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Bold.woff2 b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Bold.woff2 new file mode 100644 index 000000000..e8e2c95c2 Binary files /dev/null and b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Bold.woff2 differ diff --git a/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Medium.ttf b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Medium.ttf new file mode 100644 index 000000000..2a895f957 Binary files /dev/null and b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Medium.ttf differ diff --git a/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Medium.woff2 b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Medium.woff2 new file mode 100644 index 000000000..594028bd8 Binary files /dev/null and b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Medium.woff2 differ diff --git a/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Regular.ttf b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Regular.ttf new file mode 100644 index 000000000..3159f743b Binary files /dev/null and b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Regular.ttf differ diff --git a/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Regular.woff2 b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Regular.woff2 new file mode 100644 index 000000000..69459c987 Binary files /dev/null and b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Regular.woff2 differ diff --git a/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-SemiBold.ttf b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-SemiBold.ttf new file mode 100644 index 000000000..6a48bfe5e Binary files /dev/null and b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-SemiBold.ttf differ diff --git a/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-SemiBold.woff2 b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-SemiBold.woff2 new file mode 100644 index 000000000..ba86a5551 Binary files /dev/null and b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-SemiBold.woff2 differ diff --git a/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Thin.ttf b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Thin.ttf new file mode 100644 index 000000000..156b42853 Binary files /dev/null and b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Thin.ttf differ diff --git a/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Thin.woff2 b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Thin.woff2 new file mode 100644 index 000000000..229b99967 Binary files /dev/null and b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/Montserrat-Thin.woff2 differ diff --git a/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/OFL.txt b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/OFL.txt new file mode 100644 index 000000000..f435ed8b5 --- /dev/null +++ b/react/assets/forus-platform/resources/_platform-common/assets/fonts/montserrat/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2011 The Montserrat Project Authors (https://github.com/JulietaUla/Montserrat) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/react/assets/forus-platform/scss/_common/includes/fonts/montserrat.scss b/react/assets/forus-platform/scss/_common/includes/fonts/montserrat.scss new file mode 100644 index 000000000..69fdc92e1 --- /dev/null +++ b/react/assets/forus-platform/scss/_common/includes/fonts/montserrat.scss @@ -0,0 +1,44 @@ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 300; + src: + url('./assets/fonts/montserrat/Montserrat-Thin.woff2') format('woff2'), + url('./assets/fonts/montserrat/Montserrat-Thin.ttf') format('truetype'); +} + +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 400; + src: + url('./assets/fonts/montserrat/Montserrat-Regular.woff2') format('woff2'), + url('./assets/fonts/montserrat/Montserrat-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 500; + src: + url('./assets/fonts/montserrat/Montserrat-Medium.woff2') format('woff2'), + url('./assets/fonts/montserrat/Montserrat-Medium.ttf') format('truetype'); +} + +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 600; + src: + url('./assets/fonts/montserrat/Montserrat-SemiBold.woff2') format('woff2'), + url('./assets/fonts/montserrat/Montserrat-SemiBold.ttf') format('truetype'); +} + +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 700; + src: + url('./assets/fonts/montserrat/Montserrat-Bold.woff2') format('woff2'), + url('./assets/fonts/montserrat/Montserrat-Bold.ttf') format('truetype'); +} diff --git a/react/assets/forus-platform/scss/general/style-dashboard-general.scss b/react/assets/forus-platform/scss/general/style-dashboard-general.scss index bdfcfb3d0..3af6e6dbd 100644 --- a/react/assets/forus-platform/scss/general/style-dashboard-general.scss +++ b/react/assets/forus-platform/scss/general/style-dashboard-general.scss @@ -1,3 +1,4 @@ +@import '../_common/includes/fonts/montserrat'; @import './vars'; @import '../_common/dashboard'; diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Bold.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Bold.ttf new file mode 100644 index 000000000..1d23c7066 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Bold.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Bold.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Bold.woff2 new file mode 100644 index 000000000..a36ad7f88 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Bold.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Italic.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Italic.ttf new file mode 100644 index 000000000..70a870f40 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Italic.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Italic.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Italic.woff2 new file mode 100644 index 000000000..fed2fe58f Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Italic.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Medium.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Medium.ttf new file mode 100644 index 000000000..0648fb2d7 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Medium.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Medium.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Medium.woff2 new file mode 100644 index 000000000..2b66cd309 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Medium.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Regular.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Regular.ttf new file mode 100644 index 000000000..0f3d0f837 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Regular.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Regular.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Regular.woff2 new file mode 100644 index 000000000..3f07a5f88 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-Regular.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-SemiBold.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-SemiBold.ttf new file mode 100644 index 000000000..3b1bcccc3 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-SemiBold.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-SemiBold.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-SemiBold.woff2 new file mode 100644 index 000000000..223617e18 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/Lato-SemiBold.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/OFL.txt b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/OFL.txt new file mode 100755 index 000000000..6d2c4160b --- /dev/null +++ b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/lato/OFL.txt @@ -0,0 +1,94 @@ +Copyright (c) 2010-2015, Łukasz Dziedzic (dziedzic@typoland.com), +with Reserved Font Name Lato. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Bold.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Bold.ttf new file mode 100644 index 000000000..47e921e88 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Bold.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Bold.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Bold.woff2 new file mode 100644 index 000000000..e8e2c95c2 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Bold.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Medium.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Medium.ttf new file mode 100644 index 000000000..2a895f957 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Medium.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Medium.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Medium.woff2 new file mode 100644 index 000000000..594028bd8 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Medium.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Regular.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Regular.ttf new file mode 100644 index 000000000..3159f743b Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Regular.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Regular.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Regular.woff2 new file mode 100644 index 000000000..69459c987 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-Regular.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-SemiBold.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-SemiBold.ttf new file mode 100644 index 000000000..6a48bfe5e Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-SemiBold.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-SemiBold.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-SemiBold.woff2 new file mode 100644 index 000000000..ba86a5551 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/Montserrat-SemiBold.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/OFL.txt b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/OFL.txt new file mode 100644 index 000000000..f435ed8b5 --- /dev/null +++ b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/montserrat/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2011 The Montserrat Project Authors (https://github.com/JulietaUla/Montserrat) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OFL.txt b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OFL.txt new file mode 100644 index 000000000..2e76eefd4 --- /dev/null +++ b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OFL.txt @@ -0,0 +1,88 @@ +Copyright 2020 The Open Sans Project Authors (https://github.com/googlefonts/opensans) + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font +creation efforts of academic and linguistic communities, and to +provide a free and open framework in which fonts may be shared and +improved in partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply to +any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software +components as distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, +deleting, or substituting -- in part or in whole -- any of the +components of the Original Version, by changing formats or by porting +the Font Software to a new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, +modify, redistribute, and sell modified and unmodified copies of the +Font Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, in +Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the +corresponding Copyright Holder. This restriction only applies to the +primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created using +the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Bold.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Bold.ttf new file mode 100644 index 000000000..b7fadfa4a Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Bold.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Bold.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Bold.woff2 new file mode 100644 index 000000000..6d6a29967 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Bold.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-ExtraBold.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-ExtraBold.ttf new file mode 100644 index 000000000..6e5508a90 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-ExtraBold.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-ExtraBold.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-ExtraBold.woff2 new file mode 100644 index 000000000..1e444f7e5 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-ExtraBold.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Italic.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Italic.ttf new file mode 100644 index 000000000..e99cb92d4 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Italic.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Italic.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Italic.woff2 new file mode 100644 index 000000000..7f1be4c42 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Italic.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Light.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Light.ttf new file mode 100644 index 000000000..a0ba20432 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Light.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Light.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Light.woff2 new file mode 100644 index 000000000..2f5ee3925 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Light.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Medium.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Medium.ttf new file mode 100644 index 000000000..04d88fbf9 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Medium.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Medium.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Medium.woff2 new file mode 100644 index 000000000..f59af349c Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Medium.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Regular.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Regular.ttf new file mode 100644 index 000000000..8529c432c Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Regular.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Regular.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Regular.woff2 new file mode 100644 index 000000000..23eec574f Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-Regular.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-SemiBold.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-SemiBold.ttf new file mode 100644 index 000000000..f210dd955 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-SemiBold.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-SemiBold.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-SemiBold.woff2 new file mode 100644 index 000000000..13b0ac022 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/open-sans/OpenSans-SemiBold.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/OFL.txt b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/OFL.txt new file mode 100644 index 000000000..a417551aa --- /dev/null +++ b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2011 The Roboto Project Authors (https://github.com/googlefonts/roboto-classic) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Bold.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Bold.ttf new file mode 100644 index 000000000..4658f9a67 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Bold.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Bold.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Bold.woff2 new file mode 100644 index 000000000..a77461f6e Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Bold.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Italic.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Italic.ttf new file mode 100644 index 000000000..c3abaefb2 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Italic.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Italic.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Italic.woff2 new file mode 100644 index 000000000..435979e29 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Italic.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Medium.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Medium.ttf new file mode 100644 index 000000000..d629e9848 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Medium.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Medium.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Medium.woff2 new file mode 100644 index 000000000..8ee0c4bf8 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Medium.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Regular.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Regular.ttf new file mode 100644 index 000000000..7e3bb2f8c Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Regular.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Regular.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Regular.woff2 new file mode 100644 index 000000000..d07d0d931 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-Regular.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-SemiBold.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-SemiBold.ttf new file mode 100644 index 000000000..3f348341c Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-SemiBold.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-SemiBold.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-SemiBold.woff2 new file mode 100644 index 000000000..45fb782f4 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/roboto/Roboto-SemiBold.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/OFL.txt b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/OFL.txt new file mode 100644 index 000000000..22c601b82 --- /dev/null +++ b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2010-2024 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Bold.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Bold.ttf new file mode 100644 index 000000000..85693ccc8 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Bold.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Bold.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Bold.woff2 new file mode 100644 index 000000000..304960558 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Bold.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-It.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-It.ttf new file mode 100644 index 000000000..8e0576f24 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-It.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-It.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-It.woff2 new file mode 100644 index 000000000..14e9084da Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-It.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Medium.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Medium.ttf new file mode 100644 index 000000000..fbc97bf32 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Medium.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Medium.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Medium.woff2 new file mode 100644 index 000000000..37ad2e05d Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Medium.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Regular.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Regular.ttf new file mode 100644 index 000000000..c5dd0b88c Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Regular.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Regular.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Regular.woff2 new file mode 100644 index 000000000..a5ac52c63 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-Regular.woff2 differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-SemiBold.ttf b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-SemiBold.ttf new file mode 100644 index 000000000..4aff9a3ae Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-SemiBold.ttf differ diff --git a/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-SemiBold.woff2 b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-SemiBold.woff2 new file mode 100644 index 000000000..3bfbc08f5 Binary files /dev/null and b/react/assets/forus-webshop/resources/_webshop-common/assets/fonts/source-sans-pro/SourceSans3-SemiBold.woff2 differ diff --git a/react/assets/forus-webshop/scss/includes/fonts/lato.scss b/react/assets/forus-webshop/scss/includes/fonts/lato.scss new file mode 100644 index 000000000..c85a71123 --- /dev/null +++ b/react/assets/forus-webshop/scss/includes/fonts/lato.scss @@ -0,0 +1,44 @@ +@font-face { + font-family: 'Lato'; + font-style: normal; + font-weight: 400; + src: + url('./assets/fonts/lato/Lato-Regular.woff2') format('woff2'), + url('./assets/fonts/lato/Lato-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: 'Lato'; + font-style: italic; + font-weight: 400; + src: + url('./assets/fonts/lato/Lato-Italic.woff2') format('woff2'), + url('./assets/fonts/lato/Lato-Italic.ttf') format('truetype'); +} + +@font-face { + font-family: 'Lato'; + font-style: normal; + font-weight: 500; + src: + url('./assets/fonts/lato/Lato-Medium.woff2') format('woff2'), + url('./assets/fonts/lato/Lato-Medium.ttf') format('truetype'); +} + +@font-face { + font-family: 'Lato'; + font-style: normal; + font-weight: 600; + src: + url('./assets/fonts/lato/Lato-SemiBold.woff2') format('woff2'), + url('./assets/fonts/lato/Lato-SemiBold.ttf') format('truetype'); +} + +@font-face { + font-family: 'Lato'; + font-style: normal; + font-weight: 700; + src: + url('./assets/fonts/lato/Lato-Bold.woff2') format('woff2'), + url('./assets/fonts/lato/Lato-Bold.ttf') format('truetype'); +} diff --git a/react/assets/forus-webshop/scss/includes/fonts/montserrat.scss b/react/assets/forus-webshop/scss/includes/fonts/montserrat.scss new file mode 100644 index 000000000..c6f983d1b --- /dev/null +++ b/react/assets/forus-webshop/scss/includes/fonts/montserrat.scss @@ -0,0 +1,35 @@ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 400; + src: + url('./assets/fonts/montserrat/Montserrat-Regular.woff2') format('woff2'), + url('./assets/fonts/montserrat/Montserrat-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 500; + src: + url('./assets/fonts/montserrat/Montserrat-Medium.woff2') format('woff2'), + url('./assets/fonts/montserrat/Montserrat-Medium.ttf') format('truetype'); +} + +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 600; + src: + url('./assets/fonts/montserrat/Montserrat-SemiBold.woff2') format('woff2'), + url('./assets/fonts/montserrat/Montserrat-SemiBold.ttf') format('truetype'); +} + +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 700; + src: + url('./assets/fonts/montserrat/Montserrat-Bold.woff2') format('woff2'), + url('./assets/fonts/montserrat/Montserrat-Bold.ttf') format('truetype'); +} diff --git a/react/assets/forus-webshop/scss/includes/fonts/open-sans.scss b/react/assets/forus-webshop/scss/includes/fonts/open-sans.scss new file mode 100644 index 000000000..2e6fc3e70 --- /dev/null +++ b/react/assets/forus-webshop/scss/includes/fonts/open-sans.scss @@ -0,0 +1,44 @@ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: + url('./assets/fonts/open-sans/OpenSans-Regular.woff2') format('woff2'), + url('./assets/fonts/open-sans/OpenSans-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: + url('./assets/fonts/open-sans/OpenSans-Italic.woff2') format('woff2'), + url('./assets/fonts/open-sans/OpenSans-Italic.ttf') format('truetype'); +} + +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 500; + src: + url('./assets/fonts/open-sans/OpenSans-Medium.woff2') format('woff2'), + url('./assets/fonts/open-sans/OpenSans-Medium.ttf') format('truetype'); +} + +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 600; + src: + url('./assets/fonts/open-sans/OpenSans-SemiBold.woff2') format('woff2'), + url('./assets/fonts/open-sans/OpenSans-SemiBold.ttf') format('truetype'); +} + +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: + url('./assets/fonts/open-sans/OpenSans-Bold.woff2') format('woff2'), + url('./assets/fonts/open-sans/OpenSans-Bold.ttf') format('truetype'); +} diff --git a/react/assets/forus-webshop/scss/includes/fonts/roboto.scss b/react/assets/forus-webshop/scss/includes/fonts/roboto.scss new file mode 100644 index 000000000..e5e031426 --- /dev/null +++ b/react/assets/forus-webshop/scss/includes/fonts/roboto.scss @@ -0,0 +1,44 @@ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + src: + url('./assets/fonts/roboto/Roboto-Regular.woff2') format('woff2'), + url('./assets/fonts/roboto/Roboto-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + src: + url('./assets/fonts/roboto/Roboto-Italic.woff2') format('woff2'), + url('./assets/fonts/roboto/Roboto-Italic.ttf') format('truetype'); +} + +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 500; + src: + url('./assets/fonts/roboto/Roboto-Medium.woff2') format('woff2'), + url('./assets/fonts/roboto/Roboto-Medium.ttf') format('truetype'); +} + +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 600; + src: + url('./assets/fonts/roboto/Roboto-SemiBold.woff2') format('woff2'), + url('./assets/fonts/roboto/Roboto-SemiBold.ttf') format('truetype'); +} + +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + src: + url('./assets/fonts/roboto/Roboto-Bold.woff2') format('woff2'), + url('./assets/fonts/roboto/Roboto-Bold.ttf') format('truetype'); +} diff --git a/react/assets/forus-webshop/scss/includes/fonts/source-sans-pro.scss b/react/assets/forus-webshop/scss/includes/fonts/source-sans-pro.scss new file mode 100644 index 000000000..0173a7a8f --- /dev/null +++ b/react/assets/forus-webshop/scss/includes/fonts/source-sans-pro.scss @@ -0,0 +1,44 @@ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + src: + url('./assets/fonts/source-sans-pro/SourceSans3-Regular.woff2') format('woff2'), + url('./assets/fonts/source-sans-pro/SourceSans3-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: 'Source Sans Pro'; + font-style: italic; + font-weight: 400; + src: + url('./assets/fonts/source-sans-pro/SourceSans3-It.woff2') format('woff2'), + url('./assets/fonts/source-sans-pro/SourceSans3-It.ttf') format('truetype'); +} + +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 500; + src: + url('./assets/fonts/source-sans-pro/SourceSans3-Medium.woff2') format('woff2'), + url('./assets/fonts/source-sans-pro/SourceSans3-Medium.ttf') format('truetype'); +} + +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 600; + src: + url('./assets/fonts/source-sans-pro/SourceSans3-SemiBold.woff2') format('woff2'), + url('./assets/fonts/source-sans-pro/SourceSans3-SemiBold.ttf') format('truetype'); +} + +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 700; + src: + url('./assets/fonts/source-sans-pro/SourceSans3-Bold.woff2') format('woff2'), + url('./assets/fonts/source-sans-pro/SourceSans3-Bold.ttf') format('truetype'); +} diff --git a/react/assets/forus-webshop/scss/style-webshop-berg_en_dal-vars.scss b/react/assets/forus-webshop/scss/style-webshop-berg_en_dal-vars.scss index 13b24a493..d069375b4 100644 --- a/react/assets/forus-webshop/scss/style-webshop-berg_en_dal-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-berg_en_dal-vars.scss @@ -1,5 +1,5 @@ @import "style-webshop-general-vars"; -@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap'); +@import "./includes/fonts/open-sans"; // do not use these scss variables outside this file $primaryColor: #15694B; diff --git a/react/assets/forus-webshop/scss/style-webshop-berkelland-vars.scss b/react/assets/forus-webshop/scss/style-webshop-berkelland-vars.scss index 4a921cfb7..b522fe046 100644 --- a/react/assets/forus-webshop/scss/style-webshop-berkelland-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-berkelland-vars.scss @@ -1,5 +1,5 @@ @import "style-webshop-general-vars"; -@import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,700'); +@import "./includes/fonts/source-sans-pro"; /*========== Style Sheet - Vars ==========*/ $primaryColor: #041c37; diff --git a/react/assets/forus-webshop/scss/style-webshop-ede-vars.scss b/react/assets/forus-webshop/scss/style-webshop-ede-vars.scss index ffa8fb0e1..c9720aa2f 100644 --- a/react/assets/forus-webshop/scss/style-webshop-ede-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-ede-vars.scss @@ -1,5 +1,5 @@ @import "style-webshop-general-vars"; -@import url("https://fonts.googleapis.com/css?family=Open+Sans"); +@import "./includes/fonts/open-sans"; /*========== Style Sheet - Vars ==========*/ $primaryColor: #3558a2; diff --git a/react/assets/forus-webshop/scss/style-webshop-eemsdelta-vars.scss b/react/assets/forus-webshop/scss/style-webshop-eemsdelta-vars.scss index b5fc4aceb..da485b297 100644 --- a/react/assets/forus-webshop/scss/style-webshop-eemsdelta-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-eemsdelta-vars.scss @@ -1,5 +1,4 @@ @import "style-webshop-general-vars"; -@import url('https://fonts.googleapis.com/css?family=Verdana'); /*========== Style Sheet - Vars ==========*/ $primaryColor: #0d4379; diff --git a/react/assets/forus-webshop/scss/style-webshop-geertruidenberg-vars.scss b/react/assets/forus-webshop/scss/style-webshop-geertruidenberg-vars.scss index f5622b0db..5cbbf9f47 100644 --- a/react/assets/forus-webshop/scss/style-webshop-geertruidenberg-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-geertruidenberg-vars.scss @@ -1,5 +1,5 @@ @import "style-webshop-general-vars"; -@import url("https://fonts.googleapis.com/css?family=Roboto:400,900italic,900,700,700italic,500italic,500,400italic,300,100italic,100,300italic&subset=latin,cyrillic,latin-ext"); +@import "./includes/fonts/roboto"; /*========== Style Sheet - Vars ==========*/ $primaryColor: #666666; diff --git a/react/assets/forus-webshop/scss/style-webshop-general-vars.scss b/react/assets/forus-webshop/scss/style-webshop-general-vars.scss index cea0b28e8..eda66f956 100644 --- a/react/assets/forus-webshop/scss/style-webshop-general-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-general-vars.scss @@ -1,4 +1,4 @@ -@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap'); +@import "./includes/fonts/open-sans"; // do not use these scss variables outside this file $primaryColor: #305dfb; diff --git a/react/assets/forus-webshop/scss/style-webshop-goereeoverflakkee-vars.scss b/react/assets/forus-webshop/scss/style-webshop-goereeoverflakkee-vars.scss index 484e8e3ed..ced57c71c 100644 --- a/react/assets/forus-webshop/scss/style-webshop-goereeoverflakkee-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-goereeoverflakkee-vars.scss @@ -1,5 +1,5 @@ @import "style-webshop-general-vars"; -@import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,400;0,500;0,700;0,900;1,400;1,500;1,700;1,900&display=swap&subset=latin,cyrillic,latin-ext'); +@import "./includes/fonts/roboto"; // do not use these scss variables outside this file $primaryColor: #627c18; diff --git a/react/assets/forus-webshop/scss/style-webshop-hartvanwestbrabant-vars.scss b/react/assets/forus-webshop/scss/style-webshop-hartvanwestbrabant-vars.scss index 7a35217d7..03b098424 100644 --- a/react/assets/forus-webshop/scss/style-webshop-hartvanwestbrabant-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-hartvanwestbrabant-vars.scss @@ -1,5 +1,5 @@ @import "style-webshop-general-vars"; -@import url("https://fonts.googleapis.com/css?family=Montserrat:ital,wght@0,300;0,400;0,500;0,700;1,400"); +@import "./includes/fonts/montserrat"; /*========== Style Sheet - Vars ==========*/ $primaryColor: #1c7878; diff --git a/react/assets/forus-webshop/scss/style-webshop-heumen-vars.scss b/react/assets/forus-webshop/scss/style-webshop-heumen-vars.scss index 0208bdf6a..622315b41 100644 --- a/react/assets/forus-webshop/scss/style-webshop-heumen-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-heumen-vars.scss @@ -1,5 +1,4 @@ @import "style-webshop-general-vars"; -@import url("https://fonts.googleapis.com/css?family=Verdana"); /*========== Style Sheet - Vars ==========*/ $primaryColor: #22398e; diff --git a/react/assets/forus-webshop/scss/style-webshop-kerstpakket-vars.scss b/react/assets/forus-webshop/scss/style-webshop-kerstpakket-vars.scss index 6a9f6ffbb..713574dc5 100644 --- a/react/assets/forus-webshop/scss/style-webshop-kerstpakket-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-kerstpakket-vars.scss @@ -1,5 +1,5 @@ @import "style-webshop-general-vars"; -@import url("https://fonts.googleapis.com/css?family=Cherry+Swash&family=Montserrat:ital,wght@0,300;0,400;0,500;0,700;1,400&display=swap"); +@import "./includes/fonts/montserrat"; /*========== Style Sheet - Vars ==========*/ $primaryColor: #90191a; diff --git a/react/assets/forus-webshop/scss/style-webshop-midden_drenthe-vars.scss b/react/assets/forus-webshop/scss/style-webshop-midden_drenthe-vars.scss index 71519f0ce..abe2a233c 100644 --- a/react/assets/forus-webshop/scss/style-webshop-midden_drenthe-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-midden_drenthe-vars.scss @@ -1,5 +1,5 @@ @import "style-webshop-general-vars"; -@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap'); +@import "./includes/fonts/open-sans"; // do not use these scss variables outside this file $primaryColor: #8f1354; diff --git a/react/assets/forus-webshop/scss/style-webshop-oostgelre-vars.scss b/react/assets/forus-webshop/scss/style-webshop-oostgelre-vars.scss index 724a23f67..8a72c98db 100644 --- a/react/assets/forus-webshop/scss/style-webshop-oostgelre-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-oostgelre-vars.scss @@ -1,5 +1,4 @@ @import "style-webshop-general-vars"; -@import url("https://fonts.googleapis.com/css?family=Verdana"); /*========== Style Sheet - Vars ==========*/ $primaryColor: #3d013d; diff --git a/react/assets/forus-webshop/scss/style-webshop-schouwen_duiveland-vars.scss b/react/assets/forus-webshop/scss/style-webshop-schouwen_duiveland-vars.scss index 83aeeaf53..a35dc20cf 100644 --- a/react/assets/forus-webshop/scss/style-webshop-schouwen_duiveland-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-schouwen_duiveland-vars.scss @@ -1,5 +1,5 @@ @import "style-webshop-general-vars"; -@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap'); +@import "./includes/fonts/open-sans"; // do not use these scss variables outside this file $primaryColor: #1B7A00; diff --git a/react/assets/forus-webshop/scss/style-webshop-vergoedingen-vars.scss b/react/assets/forus-webshop/scss/style-webshop-vergoedingen-vars.scss index 8aeb2f2fe..afcd3a03d 100644 --- a/react/assets/forus-webshop/scss/style-webshop-vergoedingen-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-vergoedingen-vars.scss @@ -103,8 +103,7 @@ $primaryColorLight: #2f7f6b; font-display: swap; } -@import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,700'); -@import url('https://fonts.googleapis.com/css?family=Source+Serif+Pro:400,400i,600,700'); +@import "./includes/fonts/source-sans-pro"; :root { --zoom: 100%; diff --git a/react/assets/forus-webshop/scss/style-webshop-waalwijk-vars.scss b/react/assets/forus-webshop/scss/style-webshop-waalwijk-vars.scss index ce77fb8bb..0171da04c 100644 --- a/react/assets/forus-webshop/scss/style-webshop-waalwijk-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-waalwijk-vars.scss @@ -1,5 +1,5 @@ @import "style-webshop-general-vars"; -@import url("https://fonts.googleapis.com/css?family=Lato:300,300i,400,400i,700"); +@import "./includes/fonts/lato"; $primaryColor: #2a2a7f; $primaryColorLight: #2a2a7f; diff --git a/react/assets/forus-webshop/scss/style-webshop-wadenheuvel-vars.scss b/react/assets/forus-webshop/scss/style-webshop-wadenheuvel-vars.scss index 61d25431d..2a8c5da53 100644 --- a/react/assets/forus-webshop/scss/style-webshop-wadenheuvel-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-wadenheuvel-vars.scss @@ -1,5 +1,5 @@ @import "style-webshop-general-vars"; -@import url('https://fonts.googleapis.com/css2?family=Cantarell&family=Montserrat:ital,wght@0,300;0,400;0,500;0,700;1,400&display=swap'); +@import "./includes/fonts/open-sans"; $primaryColor: #2a2a7f; $primaryColorLight: #2a2a7f; diff --git a/react/public/index.ejs b/react/public/index.ejs index ae2a076da..02165a30d 100644 --- a/react/public/index.ejs +++ b/react/public/index.ejs @@ -9,7 +9,6 @@ <% if (disable_indexing) { %> <% } %> - <% if (['sponsor', 'provider', 'validator'].includes(type)) { %> diff --git a/react/src/dashboard/components/elements/block-card-emails/BlockCardEmails.tsx b/react/src/dashboard/components/elements/block-card-emails/BlockCardEmails.tsx index 2e44b7924..c4141c0f8 100644 --- a/react/src/dashboard/components/elements/block-card-emails/BlockCardEmails.tsx +++ b/react/src/dashboard/components/elements/block-card-emails/BlockCardEmails.tsx @@ -1,4 +1,3 @@ -import FilterModel from '../../../types/FilterModel'; import { useCallback, useEffect, useState } from 'react'; import React from 'react'; import useOpenModal from '../../../hooks/useOpenModal'; @@ -23,6 +22,7 @@ import { useFileService } from '../../../services/FileService'; import Organization from '../../../props/models/Organization'; import useConfigurableTable from '../../pages/vouchers/hooks/useConfigurableTable'; import TableTopScroller from '../tables/TableTopScroller'; +import { FilterModel } from '../../../modules/filter_next/types/FilterParams'; export default function BlockCardEmails({ organization, diff --git a/react/src/dashboard/components/elements/block-card-notes/BlockCardNotes.tsx b/react/src/dashboard/components/elements/block-card-notes/BlockCardNotes.tsx index ac5970592..f503045c2 100644 --- a/react/src/dashboard/components/elements/block-card-notes/BlockCardNotes.tsx +++ b/react/src/dashboard/components/elements/block-card-notes/BlockCardNotes.tsx @@ -1,9 +1,7 @@ -import FilterModel from '../../../types/FilterModel'; import FormValuesModel from '../../../types/FormValuesModel'; import { useCallback, useEffect, useState } from 'react'; import { ApiResponse, ApiResponseSingle, PaginationData } from '../../../props/ApiResponses'; import Paginator from '../../../modules/paginator/components/Paginator'; -import useFilter from '../../../hooks/useFilter'; import React from 'react'; import useOpenModal from '../../../hooks/useOpenModal'; import ModalDangerZone from '../../modals/ModalDangerZone'; @@ -21,6 +19,8 @@ import usePushApiError from '../../../hooks/usePushApiError'; import useConfigurableTable from '../../pages/vouchers/hooks/useConfigurableTable'; import { useOrganizationService } from '../../../services/OrganizationService'; import TableTopScroller from '../tables/TableTopScroller'; +import useFilterNext from '../../../modules/filter_next/useFilterNext'; +import { FilterModel } from '../../../modules/filter_next/types/FilterParams'; export default function BlockCardNotes({ showCreate, @@ -49,8 +49,7 @@ export default function BlockCardNotes({ const [notes, setNotes] = useState>(null); const [paginatorKey] = useState('fund_request_notes'); - const filter = useFilter({ - q: '', + const [filterValues, filterValuesActive, filterUpdate] = useFilterNext({ per_page: paginatorService.getPerPage(paginatorKey), }); @@ -59,10 +58,10 @@ export default function BlockCardNotes({ const updateNotes = useCallback(() => { setProgress(0); - fetchNotes(filter.activeValues) + fetchNotes(filterValuesActive) .then((res) => setNotes(res.data)) .finally(() => setProgress(100)); - }, [fetchNotes, filter.activeValues, setProgress]); + }, [fetchNotes, filterValuesActive, setProgress]); const onDeleteNote = useCallback( (note: Note) => { @@ -82,7 +81,7 @@ export default function BlockCardNotes({ deleteNote(note) .then(() => { - filter.touch(); + updateNotes(); pushSuccess('Gelukt!', 'Notitie verwijderd.'); }) .catch(pushApiError) @@ -93,7 +92,7 @@ export default function BlockCardNotes({ /> )); }, - [deleteNote, filter, openModal, pushApiError, pushSuccess, setProgress, translate], + [deleteNote, openModal, pushApiError, pushSuccess, setProgress, translate, updateNotes], ); const onAddNote = useCallback(() => { @@ -103,12 +102,12 @@ export default function BlockCardNotes({ storeNote={storeNote} description={'De notitie is alleen zichtbaar voor medewerkers met dezelfde rechten.'} onCreated={() => { - filter.touch(); + updateNotes(); pushSuccess('Gelukt!', 'Note created.'); }} /> )); - }, [filter, openModal, pushSuccess, storeNote]); + }, [openModal, pushSuccess, storeNote, updateNotes]); useEffect(() => { updateNotes(); @@ -196,8 +195,8 @@ export default function BlockCardNotes({
diff --git a/react/src/dashboard/components/elements/block-reimbursement-categories/BlockReimbursementCategories.tsx b/react/src/dashboard/components/elements/block-reimbursement-categories/BlockReimbursementCategories.tsx index 4d34427f4..920c47f6f 100644 --- a/react/src/dashboard/components/elements/block-reimbursement-categories/BlockReimbursementCategories.tsx +++ b/react/src/dashboard/components/elements/block-reimbursement-categories/BlockReimbursementCategories.tsx @@ -2,7 +2,6 @@ import React, { useCallback, useEffect, useState } from 'react'; import { PaginationData } from '../../../props/ApiResponses'; import ReimbursementCategory from '../../../props/models/ReimbursementCategory'; import Paginator from '../../../modules/paginator/components/Paginator'; -import useFilter from '../../../hooks/useFilter'; import usePaginatorService from '../../../modules/paginator/services/usePaginatorService'; import useOpenModal from '../../../hooks/useOpenModal'; import useActiveOrganization from '../../../hooks/useActiveOrganization'; @@ -19,6 +18,7 @@ import useConfigurableTable from '../../pages/vouchers/hooks/useConfigurableTabl import TableTopScroller from '../tables/TableTopScroller'; import TableRowActions from '../tables/TableRowActions'; import classNames from 'classnames'; +import useFilterNext from '../../../modules/filter_next/useFilterNext'; export default function BlockReimbursementCategories({ compact = false, @@ -44,8 +44,7 @@ export default function BlockReimbursementCategories({ const [categories, setCategories] = useState>(null); const [paginatorKey] = useState('reimbursement_categories'); - const filter = useFilter({ - q: '', + const [filterValues, filterValuesActive, filterUpdate] = useFilterNext({ per_page: paginatorService.getPerPage(paginatorKey), }); @@ -56,14 +55,14 @@ export default function BlockReimbursementCategories({ setProgress(0); reimbursementCategoryService - .list(activeOrganization.id, filter.activeValues) + .list(activeOrganization.id, filterValuesActive) .then((res) => setCategories(res.data)) .catch(pushApiError) .finally(() => { setLoading(false); setProgress(100); }); - }, [setProgress, activeOrganization.id, filter.activeValues, pushApiError, reimbursementCategoryService]); + }, [setProgress, activeOrganization.id, filterValuesActive, pushApiError, reimbursementCategoryService]); const editReimbursementCategory = useCallback( async (category: ReimbursementCategory = null): Promise => { @@ -209,8 +208,8 @@ export default function BlockReimbursementCategories({
diff --git a/react/src/dashboard/components/elements/tables/EventLogsTable.tsx b/react/src/dashboard/components/elements/tables/EventLogsTable.tsx index 851f05485..3cb773d36 100644 --- a/react/src/dashboard/components/elements/tables/EventLogsTable.tsx +++ b/react/src/dashboard/components/elements/tables/EventLogsTable.tsx @@ -12,7 +12,6 @@ import useAppConfigs from '../../../hooks/useAppConfigs'; import Organization from '../../../props/models/Organization'; import ClickOutside from '../click-outside/ClickOutside'; import { strLimit } from '../../../helpers/string'; -import useFilter from '../../../hooks/useFilter'; import usePaginatorService from '../../../modules/paginator/services/usePaginatorService'; import useTranslate from '../../../hooks/useTranslate'; import EmptyCard from '../empty-card/EmptyCard'; @@ -20,6 +19,8 @@ import useConfigurableTable from '../../pages/vouchers/hooks/useConfigurableTabl import TableTopScroller from './TableTopScroller'; import TableEmptyValue from '../table-empty-value/TableEmptyValue'; import useEventLogsExporter from '../../../services/exporters/useEventLogsExporter'; +import useFilterNext from '../../../modules/filter_next/useFilterNext'; +import { ArrayParam, NumberParam, StringParam } from 'use-query-params'; export default function EventLogsTable({ organization, @@ -66,14 +67,34 @@ export default function EventLogsTable({ const { headElement, configsElement } = useConfigurableTable(eventLogService.getColumns(hideEntity)); - const filter = useFilter({ - q: '', - loggable: loggable, - loggable_id: loggableId, - per_page: paginatorService.getPerPage(perPageKey), - order_by: 'created_at', - order_dir: 'desc', - }); + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext<{ + q: string; + loggable?: Array; + per_page?: number; + page?: number; + order_by?: string; + order_dir?: string; + }>( + { + q: '', + loggable: loggable, + per_page: paginatorService.getPerPage(perPageKey), + order_by: 'created_at', + order_dir: 'desc', + }, + { + queryParams: { + q: StringParam, + loggable: ArrayParam, + per_page: NumberParam, + page: NumberParam, + order_by: StringParam, + order_dir: StringParam, + }, + }, + ); + + const { resetFilters: resetFilters } = filter; const showNoteTooltip = useCallback((e: React.MouseEvent, log: EventLog) => { e.stopPropagation(); @@ -88,7 +109,7 @@ export default function EventLogsTable({ const selectLoggable = useCallback( (key: string, selected: boolean) => { - const values = filter.activeValues.loggable; + const values = [...filterValuesActive.loggable]; const index = values.indexOf(key); if (index !== -1 && !selected) { @@ -97,20 +118,20 @@ export default function EventLogsTable({ values.push(key); } - filter.update({ loggable: values }); + filterUpdate({ loggable: values }); }, - [filter], + [filterUpdate, filterValuesActive.loggable], ); const exportLogs = useCallback(() => { - eventLogsExporter.exportData(organization.id, filter.activeValues); - }, [organization.id, filter.activeValues, eventLogsExporter]); + eventLogsExporter.exportData(organization.id, { ...filterValuesActive, loggable_id: loggableId }); + }, [organization.id, filterValuesActive, eventLogsExporter, loggableId]); const fetchLogs = useCallback(() => { setProgress(0); eventLogService - .list(organization.id, filter.activeValues) + .list(organization.id, { ...filterValuesActive, loggable_id: loggableId }) .then((res) => { const logs = { ...res.data, @@ -123,7 +144,7 @@ export default function EventLogsTable({ setLogs(logs); }) .finally(() => setProgress(100)); - }, [organization.id, setProgress, eventLogService, filter.activeValues]); + }, [organization.id, setProgress, eventLogService, filterValuesActive, loggableId]); useEffect(() => { fetchLogs(); @@ -149,7 +170,7 @@ export default function EventLogsTable({ {!hideFilterForm && (
{filter.show && ( -
filter.resetFilters()}> +
resetFilters()}> Wis filters
@@ -160,9 +181,9 @@ export default function EventLogsTable({ filter.update({ q: e.target.value })} + onChange={(e) => filterUpdate({ q: e.target.value })} placeholder={translate('event_logs.labels.search')} />
@@ -174,35 +195,37 @@ export default function EventLogsTable({ filter.update({ q: e.target.value })} + value={filterValues.q} + onChange={(e) => filterUpdate({ q: e.target.value })} placeholder={translate('event_logs.labels.search')} /> - {loggables.map((loggable) => ( -
-
@@ -577,8 +615,8 @@ export default function ImplementationsNotificationsSend() {
diff --git a/react/src/dashboard/components/pages/implementations-view/ImplementationsView.tsx b/react/src/dashboard/components/pages/implementations-view/ImplementationsView.tsx index 6f175b0d5..5a5c0f512 100644 --- a/react/src/dashboard/components/pages/implementations-view/ImplementationsView.tsx +++ b/react/src/dashboard/components/pages/implementations-view/ImplementationsView.tsx @@ -7,7 +7,6 @@ import useAssetUrl from '../../../hooks/useAssetUrl'; import { hasPermission } from '../../../helpers/utils'; import StateNavLink from '../../../modules/state_router/StateNavLink'; import LoadingCard from '../../elements/loading-card/LoadingCard'; -import useFilter from '../../../hooks/useFilter'; import { useFundService } from '../../../services/FundService'; import Fund from '../../../props/models/Fund'; import { getStateRouteUrl } from '../../../modules/state_router/Router'; @@ -20,6 +19,7 @@ import TableTopScroller from '../../elements/tables/TableTopScroller'; import TableRowActions from '../../elements/tables/TableRowActions'; import usePushApiError from '../../../hooks/usePushApiError'; import { Permission } from '../../../props/models/Organization'; +import useFilterNext from '../../../modules/filter_next/useFilterNext'; export default function ImplementationsView() { const { id } = useParams(); @@ -37,7 +37,7 @@ export default function ImplementationsView() { const [implementation, setImplementation] = useState(null); const [funds, setFunds] = useState>(null); - const filter = useFilter({ q: '' }); + const [filterValues, filterValuesActive, filterUpdate] = useFilterNext<{ q: string }>({ q: '' }); const fetchImplementation = useCallback(() => { implementationService @@ -58,11 +58,11 @@ export default function ImplementationsView() { setProgress(0); fundService - .list(activeOrganization.id, { implementation_id: parseInt(id), ...filter.activeValues }) + .list(activeOrganization.id, { implementation_id: parseInt(id), ...filterValuesActive }) .then((res) => setFunds(res.data)) .catch(pushApiError) .finally(() => setProgress(100)); - }, [setProgress, fundService, activeOrganization.id, id, filter.activeValues, pushApiError]); + }, [setProgress, fundService, activeOrganization.id, id, filterValuesActive, pushApiError]); useEffect(() => { fetchImplementation(); @@ -176,10 +176,10 @@ export default function ImplementationsView() {
filter.update({ q: e.target.value })} + onChange={(e) => filterUpdate({ q: e.target.value })} />
diff --git a/react/src/dashboard/components/pages/implementations/Implementations.tsx b/react/src/dashboard/components/pages/implementations/Implementations.tsx index 591f4780a..2c362ecf3 100644 --- a/react/src/dashboard/components/pages/implementations/Implementations.tsx +++ b/react/src/dashboard/components/pages/implementations/Implementations.tsx @@ -3,7 +3,6 @@ import useImplementationService from '../../../services/ImplementationService'; import useActiveOrganization from '../../../hooks/useActiveOrganization'; import { PaginationData } from '../../../props/ApiResponses'; import { useNavigateState } from '../../../modules/state_router/Router'; -import useFilter from '../../../hooks/useFilter'; import usePaginatorService from '../../../modules/paginator/services/usePaginatorService'; import useAssetUrl from '../../../hooks/useAssetUrl'; import { hasPermission } from '../../../helpers/utils'; @@ -13,9 +12,13 @@ import LoadingCard from '../../elements/loading-card/LoadingCard'; import EmptyCard from '../../elements/empty-card/EmptyCard'; import usePushApiError from '../../../hooks/usePushApiError'; import { Permission } from '../../../props/models/Organization'; +import useFilterNext from '../../../modules/filter_next/useFilterNext'; +import { NumberParam, StringParam } from 'use-query-params'; +import useSetProgress from '../../../hooks/useSetProgress'; export default function Implementations() { const assetUrl = useAssetUrl(); + const setProgress = useSetProgress(); const pushApiError = usePushApiError(); const navigateState = useNavigateState(); const activeOrganization = useActiveOrganization(); @@ -26,10 +29,23 @@ export default function Implementations() { const [paginatorKey] = useState('implementations'); const [implementations, setImplementations] = useState>(null); - const filter = useFilter({ - q: '', - per_page: paginatorService.getPerPage(paginatorKey), - }); + const [filterValues, filterValuesActive, filterUpdate] = useFilterNext<{ + q: string; + per_page?: number; + page?: number; + }>( + { + q: '', + per_page: paginatorService.getPerPage(paginatorKey), + }, + { + queryParams: { + q: StringParam, + per_page: NumberParam, + page: NumberParam, + }, + }, + ); const goToImplementation = useCallback( (implementation: Implementation) => { @@ -42,11 +58,14 @@ export default function Implementations() { ); const fetchImplementations = useCallback(() => { + setProgress(0); + implementationService - .list(activeOrganization.id, filter.activeValues) + .list(activeOrganization.id, filterValuesActive) .then((res) => setImplementations(res.data)) + .finally(() => setProgress(100)) .catch(pushApiError); - }, [activeOrganization.id, filter.activeValues, implementationService, pushApiError]); + }, [activeOrganization.id, filterValuesActive, implementationService, pushApiError, setProgress]); useEffect(() => { fetchImplementations(); @@ -65,10 +84,10 @@ export default function Implementations() {
filter.update({ q: e.target.value })} + onChange={(e) => filterUpdate({ q: e.target.value })} />
diff --git a/react/src/dashboard/components/pages/offices/Offices.tsx b/react/src/dashboard/components/pages/offices/Offices.tsx index 11aafca8e..47dd48669 100644 --- a/react/src/dashboard/components/pages/offices/Offices.tsx +++ b/react/src/dashboard/components/pages/offices/Offices.tsx @@ -1,6 +1,5 @@ import React, { useCallback, useEffect, useState } from 'react'; import useActiveOrganization from '../../../hooks/useActiveOrganization'; -import useFilter from '../../../hooks/useFilter'; import LoadingCard from '../../elements/loading-card/LoadingCard'; import { NavLink, useNavigate } from 'react-router'; import { getStateRouteUrl } from '../../../modules/state_router/Router'; @@ -19,6 +18,7 @@ import usePushSuccess from '../../../hooks/usePushSuccess'; import useTranslate from '../../../hooks/useTranslate'; import usePushApiError from '../../../hooks/usePushApiError'; import { Permission } from '../../../props/models/Organization'; +import useFilterNext from '../../../modules/filter_next/useFilterNext'; interface OfficeLocal extends Office { scheduleByDay: { [key: string]: OfficeSchedule }; @@ -39,7 +39,7 @@ export default function Offices() { const [weekDays] = useState(officeService.scheduleWeekDays()); const [offices, setOffices] = useState>(null); - const filter = useFilter({ + const [filterValues, filterValuesActive, filterUpdate] = useFilterNext<{ q: string; per_page: number }>({ q: '', per_page: 100, }); @@ -48,7 +48,7 @@ export default function Offices() { setProgress(0); officeService - .list(organization.id, filter.activeValues) + .list(organization.id, filterValuesActive) .then((res) => { setOffices( res.data.data.map((office) => ({ @@ -61,7 +61,7 @@ export default function Offices() { ); }) .finally(() => setProgress(100)); - }, [setProgress, officeService, organization.id, filter.activeValues]); + }, [setProgress, officeService, organization.id, filterValuesActive]); const confirmDelete = useCallback( (office: Office) => { @@ -232,8 +232,8 @@ export default function Offices() { type="text" className="form-control" placeholder="Zoeken" - value={filter.values.q} - onChange={(e) => filter.update({ q: e.target.value })} + value={filterValues.q} + onChange={(e) => filterUpdate({ q: e.target.value })} /> diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowIdentitiesCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowIdentitiesCard.tsx index 599aa6f98..a0e29bb51 100644 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowIdentitiesCard.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowIdentitiesCard.tsx @@ -1,6 +1,5 @@ import React, { Fragment, useCallback, useEffect, useState } from 'react'; import Fund from '../../../../../props/models/Fund'; -import ClickOutside from '../../../../elements/click-outside/ClickOutside'; import FilterItemToggle from '../../../../elements/tables/elements/FilterItemToggle'; import EmptyCard from '../../../../elements/empty-card/EmptyCard'; import Paginator from '../../../../../modules/paginator/components/Paginator'; @@ -8,7 +7,6 @@ import useTranslate from '../../../../../hooks/useTranslate'; import useActiveOrganization from '../../../../../hooks/useActiveOrganization'; import usePaginatorService from '../../../../../modules/paginator/services/usePaginatorService'; import { PaginationData } from '../../../../../props/ApiResponses'; -import useFilter from '../../../../../hooks/useFilter'; import LoadingCard from '../../../../elements/loading-card/LoadingCard'; import StateNavLink from '../../../../../modules/state_router/StateNavLink'; import SponsorIdentity from '../../../../../props/models/Sponsor/SponsorIdentity'; @@ -20,6 +18,8 @@ import { Permission } from '../../../../../props/models/Organization'; import useConfigurableTable from '../../../vouchers/hooks/useConfigurableTable'; import TableTopScroller from '../../../../elements/tables/TableTopScroller'; import TableRowActions from '../../../../elements/tables/TableRowActions'; +import useFilterNext from '../../../../../modules/filter_next/useFilterNext'; +import CardHeaderFilter from '../../../../elements/tables/elements/CardHeaderFilter'; export default function OrganizationsFundsShowIdentitiesCard({ fund, @@ -48,7 +48,8 @@ export default function OrganizationsFundsShowIdentitiesCard({ const [paginationPerPageKey] = useState('fund_identities_per_page'); - const filter = useFilter({ + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext<{ q: string; per_page?: number }>({ + q: '', per_page: paginatorService.getPerPage(paginationPerPageKey), }); @@ -61,24 +62,28 @@ export default function OrganizationsFundsShowIdentitiesCard({ setProgress(0); fundService - .listIdentities(activeOrganization.id, fund.id, filter.activeValues) + .listIdentities(activeOrganization.id, fund.id, filterValuesActive) .then((res) => { setIdentities(res.data); setIdentitiesActive(res.data.meta.counts['active']); setIdentitiesWithoutEmail(res.data.meta.counts['without_email']); - setLastQueryIdentities(filter.activeValues.q); + setLastQueryIdentities(filterValuesActive.q); }) .finally(() => setProgress(100)); - }, [setProgress, fundService, activeOrganization.id, fund.id, filter.activeValues]); + }, [setProgress, fundService, activeOrganization.id, fund.id, filterValuesActive]); const exportIdentities = useCallback(() => { - fundIdentitiesExporter.exportData(activeOrganization.id, fund.id, filter.activeValues); - }, [activeOrganization.id, fund?.id, fundIdentitiesExporter, filter.activeValues]); + fundIdentitiesExporter.exportData(activeOrganization.id, fund.id, filterValuesActive); + }, [activeOrganization.id, fund?.id, fundIdentitiesExporter, filterValuesActive]); useEffect(() => { fetchIdentities(); }, [fetchIdentities]); + if (!identities) { + return ; + } + return (
@@ -118,11 +123,11 @@ export default function OrganizationsFundsShowIdentitiesCard({ - filter.update({ + filterUpdate({ q: e.target.value, }) } @@ -131,57 +136,36 @@ export default function OrganizationsFundsShowIdentitiesCard({
)} - filter.setShow(false)}> -
- {filter.show && ( -
-
-
-
- -
- - - filter.update({ - q: e.target.value, - }) - } - placeholder={translate( - 'funds_show.top_up_table.filters.search', - )} - /> - - -
- -
-
-
- )} + + + + filterUpdate({ + q: e.target.value, + }) + } + placeholder={translate('funds_show.top_up_table.filters.search')} + /> + -
filter.setShow(!filter.show)}> - -
+
+
- +
@@ -253,8 +237,8 @@ export default function OrganizationsFundsShowIdentitiesCard({ diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowImplementationsCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowImplementationsCard.tsx index b8209538f..c7d7af877 100644 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowImplementationsCard.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowImplementationsCard.tsx @@ -1,6 +1,5 @@ import React, { Fragment, useCallback, useEffect, useState } from 'react'; import Fund from '../../../../../props/models/Fund'; -import ClickOutside from '../../../../elements/click-outside/ClickOutside'; import FilterItemToggle from '../../../../elements/tables/elements/FilterItemToggle'; import EmptyCard from '../../../../elements/empty-card/EmptyCard'; import Paginator from '../../../../../modules/paginator/components/Paginator'; @@ -8,7 +7,6 @@ import useTranslate from '../../../../../hooks/useTranslate'; import useActiveOrganization from '../../../../../hooks/useActiveOrganization'; import usePaginatorService from '../../../../../modules/paginator/services/usePaginatorService'; import { PaginationData } from '../../../../../props/ApiResponses'; -import useFilter from '../../../../../hooks/useFilter'; import LoadingCard from '../../../../elements/loading-card/LoadingCard'; import TableRowActions from '../../../../elements/tables/TableRowActions'; import { hasPermission } from '../../../../../helpers/utils'; @@ -20,6 +18,8 @@ import { Permission } from '../../../../../props/models/Organization'; import useConfigurableTable from '../../../vouchers/hooks/useConfigurableTable'; import TableTopScroller from '../../../../elements/tables/TableTopScroller'; import { useFundService } from '../../../../../services/FundService'; +import useFilterNext from '../../../../../modules/filter_next/useFilterNext'; +import CardHeaderFilter from '../../../../elements/tables/elements/CardHeaderFilter'; export default function OrganizationsFundsShowImplementationsCard({ fund, @@ -43,15 +43,17 @@ export default function OrganizationsFundsShowImplementationsCard({ const [lastQueryImplementations, setLastQueryImplementations] = useState(''); const [implementations, setImplementations] = useState>(null); - const filter = useFilter({ + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext<{ q: string; per_page?: number }>({ q: '', per_page: paginatorService.getPerPage(paginationPerPageKey), }); + const { resetFilters: resetFilters } = filter; + const { headElement, configsElement } = useConfigurableTable(fundService.getImplementationsColumns()); const transformImplementations = useCallback(() => { - const { q = '', per_page } = filter.activeValues; + const { q = '', per_page } = filterValuesActive; const links = { active: false, label: '', url: '' }; setLastQueryImplementations(q); @@ -70,7 +72,7 @@ export default function OrganizationsFundsShowImplementationsCard({ meta: { total: 0, current_page: 1, per_page, from: 0, to: 0, last_page: 1, path: '', links }, }); } - }, [filter.activeValues, fund?.implementation]); + }, [filterValuesActive, fund?.implementation]); useEffect(() => { transformImplementations(); @@ -103,7 +105,7 @@ export default function OrganizationsFundsShowImplementationsCard({
{filter.show && ( -
filter.resetFilters()}> +
resetFilters()}> Wis filters
@@ -115,10 +117,10 @@ export default function OrganizationsFundsShowImplementationsCard({ - filter.update({ + filterUpdate({ q: e.target.value, }) } @@ -127,44 +129,22 @@ export default function OrganizationsFundsShowImplementationsCard({
)} - filter.setShow(false)}> -
- {filter.show && ( -
-
-
-
- -
- - - filter.update({ - q: e.target.value, - }) - } - placeholder={translate( - 'funds_show.implementations_table.filters.search', - )} - /> - -
-
- )} - -
filter.setShow(!filter.show)}> - -
-
- + + + + filterUpdate({ + q: e.target.value, + }) + } + placeholder={translate('funds_show.implementations_table.filters.search')} + /> + +
@@ -258,8 +238,8 @@ export default function OrganizationsFundsShowImplementationsCard({ diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowTopUpsCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowTopUpsCard.tsx index f8cbc3524..9ef054b1b 100644 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowTopUpsCard.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowTopUpsCard.tsx @@ -1,6 +1,5 @@ import React, { Fragment, useCallback, useEffect, useState } from 'react'; import Fund from '../../../../../props/models/Fund'; -import ClickOutside from '../../../../elements/click-outside/ClickOutside'; import FilterItemToggle from '../../../../elements/tables/elements/FilterItemToggle'; import DatePickerControl from '../../../../elements/forms/controls/DatePickerControl'; import { dateFormat, dateParse } from '../../../../../helpers/dates'; @@ -13,11 +12,12 @@ import useActiveOrganization from '../../../../../hooks/useActiveOrganization'; import { useFundService } from '../../../../../services/FundService'; import usePaginatorService from '../../../../../modules/paginator/services/usePaginatorService'; import { PaginationData } from '../../../../../props/ApiResponses'; -import useFilter from '../../../../../hooks/useFilter'; import LoadingCard from '../../../../elements/loading-card/LoadingCard'; import useConfigurableTable from '../../../vouchers/hooks/useConfigurableTable'; import TableTopScroller from '../../../../elements/tables/TableTopScroller'; import TableEmptyValue from '../../../../elements/table-empty-value/TableEmptyValue'; +import useFilterNext from '../../../../../modules/filter_next/useFilterNext'; +import CardHeaderFilter from '../../../../elements/tables/elements/CardHeaderFilter'; export default function OrganizationsFundsShowTopUpsCard({ fund, @@ -42,14 +42,28 @@ export default function OrganizationsFundsShowTopUpsCard({ const [paginationPerPageKey] = useState('fund_top_up_per_page'); - const filter = useFilter({ - q: '', - amount_min: null, - amount_max: null, - from: null, - to: null, - per_page: paginatorService.getPerPage(paginationPerPageKey), - }); + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext<{ + q: string; + per_page?: number; + amount_min?: string; + amount_max?: string; + from?: string; + to?: string; + }>( + { + q: '', + amount_min: null, + amount_max: null, + from: null, + to: null, + per_page: paginatorService.getPerPage(paginationPerPageKey), + }, + { + throttledValues: ['q', 'amount_min', 'amount_max'], + }, + ); + + const { resetFilters: resetFilters } = filter; const { headElement, configsElement } = useConfigurableTable(fundService.getTopUpColumns(), { filter, @@ -58,20 +72,20 @@ export default function OrganizationsFundsShowTopUpsCard({ const fetchTopUps = useCallback(() => { if (!fund?.is_configured) { - setLastQueryTopUpTransactions(filter.activeValues.q); + setLastQueryTopUpTransactions(filterValuesActive.q); return; } setProgress(0); fundService - .listTopUpTransactions(activeOrganization.id, fund.id, filter.activeValues) + .listTopUpTransactions(activeOrganization.id, fund.id, filterValuesActive) .then((res) => { setTopUpTransactions(res.data); - setLastQueryTopUpTransactions(filter.activeValues.q); + setLastQueryTopUpTransactions(filterValuesActive.q); }) .finally(() => setProgress(100)); - }, [fund?.is_configured, setProgress, fundService, activeOrganization.id, fund.id, filter.activeValues]); + }, [fund?.is_configured, setProgress, fundService, activeOrganization.id, fund.id, filterValuesActive]); useEffect(() => { fetchTopUps(); @@ -105,7 +119,7 @@ export default function OrganizationsFundsShowTopUpsCard({
{filter.show && ( -
filter.resetFilters()}> +
resetFilters()}> Wis filters
@@ -117,10 +131,10 @@ export default function OrganizationsFundsShowTopUpsCard({ - filter.update({ + filterUpdate({ q: e.target.value, }) } @@ -129,107 +143,80 @@ export default function OrganizationsFundsShowTopUpsCard({
)} - filter.setShow(false)}> -
- {filter.show && ( -
-
-
-
- -
- - - filter.update({ - q: e.target.value, - }) - } - placeholder={translate( - 'funds_show.top_up_table.filters.search', - )} - /> - - - -
-
- - filter.update({ - amount_min: e.target.value, - }) - } - placeholder={translate( - 'funds_show.top_up_table.filters.amount_min', - )} - /> -
- -
- - filter.update({ - amount_max: e.target.value, - }) - } - placeholder={translate( - 'transactions.labels.amount_max', - )} - /> -
-
-
+ + + + filterUpdate({ + q: e.target.value, + }) + } + placeholder={translate('funds_show.top_up_table.filters.search')} + /> + - - { - filter.update({ - from: dateFormat(from), - }); - }} - /> - - - - { - filter.update({ - to: dateFormat(to), - }); - }} - /> - -
+ +
+
+ + filterUpdate({ + amount_min: e.target.value, + }) + } + placeholder={translate('funds_show.top_up_table.filters.amount_min')} + />
- )} -
filter.setShow(!filter.show)}> - +
+ + filterUpdate({ + amount_max: e.target.value, + }) + } + placeholder={translate('transactions.labels.amount_max')} + /> +
-
- +
+ + + { + filterUpdate({ + from: dateFormat(from), + }); + }} + /> + + + + { + filterUpdate({ + to: dateFormat(to), + }); + }} + /> + +
@@ -278,8 +265,8 @@ export default function OrganizationsFundsShowTopUpsCard({ diff --git a/react/src/dashboard/components/pages/organizations-funds/OrganizationFunds.tsx b/react/src/dashboard/components/pages/organizations-funds/OrganizationFunds.tsx index d8709e77e..0ab2d2d31 100644 --- a/react/src/dashboard/components/pages/organizations-funds/OrganizationFunds.tsx +++ b/react/src/dashboard/components/pages/organizations-funds/OrganizationFunds.tsx @@ -8,7 +8,6 @@ import { useFundService } from '../../../services/FundService'; import usePaginatorService from '../../../modules/paginator/services/usePaginatorService'; import LoadingCard from '../../elements/loading-card/LoadingCard'; import useSetProgress from '../../../hooks/useSetProgress'; -import ClickOutside from '../../elements/click-outside/ClickOutside'; import FilterItemToggle from '../../elements/tables/elements/FilterItemToggle'; import SelectControl from '../../elements/select-control/SelectControl'; import useImplementationService from '../../../services/ImplementationService'; @@ -18,7 +17,7 @@ import TableRowActions from '../../elements/tables/TableRowActions'; import usePushSuccess from '../../../hooks/usePushSuccess'; import ModalDangerZone from '../../modals/ModalDangerZone'; import useOpenModal from '../../../hooks/useOpenModal'; -import { StringParam, useQueryParams, withDefault } from 'use-query-params'; +import { createEnumParam, NumberParam, StringParam } from 'use-query-params'; import Paginator from '../../../modules/paginator/components/Paginator'; import ModalFundTopUp from '../../modals/ModalFundTopUp'; import useTranslate from '../../../hooks/useTranslate'; @@ -32,6 +31,7 @@ import classNames from 'classnames'; import LoaderTableCard from '../../elements/loader-table-card/LoaderTableCard'; import useFilterNext from '../../../modules/filter_next/useFilterNext'; import { Permission } from '../../../props/models/Organization'; +import CardHeaderFilter from '../../elements/tables/elements/CardHeaderFilter'; export default function OrganizationFunds() { const translate = useTranslate(); @@ -59,22 +59,13 @@ export default function OrganizationFunds() { { key: 'closed', name: translate(`components.organization_funds.states.closed`) }, ]); - const [{ funds_type }, setQueryParams] = useQueryParams( - { funds_type: withDefault(StringParam, 'active') }, - { removeDefaultsFromUrl: true }, - ); - - const { headElement, configsElement } = useConfigurableTable( - fundService.getColumns(activeOrganization, funds_type), - ); - - const [filterValues, filterActiveValues, filterUpdate, filter] = useFilterNext<{ + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext<{ q: string; page: number; state: string; per_page: number; funds_type: string; - implementation_id: string; + implementation_id: number; physical_card_type_id?: number; }>( { @@ -82,38 +73,44 @@ export default function OrganizationFunds() { page: 1, state: null, per_page: paginatorService.getPerPage(paginatorKey), - funds_type: null, + funds_type: 'active', implementation_id: null, physical_card_type_id: null, }, { queryParams: { q: StringParam, - state: StringParam, - funds_type: StringParam, - implementation_id: StringParam, - page: StringParam, - per_page: StringParam, + page: NumberParam, + per_page: NumberParam, + state: createEnumParam(['active', 'paused', 'closed']), + funds_type: createEnumParam(['active', 'archived']), + implementation_id: NumberParam, }, }, ); + const { resetFilters: resetFilters } = filter; + + const { headElement, configsElement } = useConfigurableTable( + fundService.getColumns(activeOrganization, filterValues.funds_type), + ); + const fetchFunds = useCallback(() => { setProgress(0); fundService .list(activeOrganization.id, { - ...filterActiveValues, + ...filterValuesActive, with_archived: 1, with_external: 1, stats: 'min', - archived: funds_type == 'archived' ? 1 : 0, - per_page: filterActiveValues.per_page, + archived: filterValuesActive.funds_type == 'archived' ? 1 : 0, + per_page: filterValuesActive.per_page, }) .then((res) => setFunds(res.data)) .catch(pushApiError) .finally(() => setProgress(100)); - }, [activeOrganization.id, filterActiveValues, fundService, funds_type, pushApiError, setProgress]); + }, [activeOrganization.id, filterValuesActive, fundService, pushApiError, setProgress]); const fetchImplementations = useCallback(() => { setProgress(0); @@ -156,14 +153,14 @@ export default function OrganizationFunds() { fundService .archive(fund.organization_id, fund.id) .then(() => { - setQueryParams({ funds_type: 'archived' }); + filterUpdate({ funds_type: 'archived' }); pushSuccess('Opgeslagen!'); }) .catch(pushApiError) .finally(() => setProgress(100)); }); }, - [askConfirmation, fundService, pushApiError, pushSuccess, setProgress, setQueryParams], + [askConfirmation, fundService, pushApiError, pushSuccess, setProgress, filterUpdate], ); const restoreFund = useCallback( @@ -177,14 +174,14 @@ export default function OrganizationFunds() { fundService .unarchive(fund.organization_id, fund.id) .then(() => { - setQueryParams({ funds_type: 'active' }); + filterUpdate({ funds_type: 'active' }); pushSuccess('Opgeslagen!'); }) .catch(pushApiError) .finally(() => setProgress(100)); }); }, - [askConfirmation, fundService, pushApiError, pushSuccess, setProgress, setQueryParams], + [askConfirmation, fundService, pushApiError, pushSuccess, setProgress, filterUpdate], ); const topUpModal = useCallback( @@ -251,17 +248,17 @@ export default function OrganizationFunds() {
setQueryParams({ funds_type: 'active' })} + onClick={() => filterUpdate({ funds_type: 'active' })} className={`label-tab label-tab-sm ${ - funds_type == 'active' ? 'active' : '' + filterValues.funds_type == 'active' ? 'active' : '' }`}> Lopend ({funds.meta.unarchived_funds_total})
setQueryParams({ funds_type: 'archived' })} + onClick={() => filterUpdate({ funds_type: 'archived' })} className={`label-tab label-tab-sm ${ - funds_type == 'archived' ? 'active' : '' + filterValues.funds_type == 'archived' ? 'active' : '' }`}> Archief ({funds.meta.archived_funds_total})
@@ -273,7 +270,7 @@ export default function OrganizationFunds() {
{filter.show && ( -
+
resetFilters()}> Wis filters
@@ -286,73 +283,48 @@ export default function OrganizationFunds() { type="text" className="form-control" placeholder="Zoeken" - value={filter.values.q} - onChange={(e) => filter.update({ q: e.target.value })} + value={filterValues.q} + onChange={(e) => filterUpdate({ q: e.target.value })} />
)} - filter.setShow(false)}> -
- {filter.show && ( -
-
-
-
- -
- - filterUpdate({ q: e.target.value })} - placeholder={translate( - 'components.organization_funds.filters.search', - )} - /> - - - - filterUpdate({ state })} - /> - - - - - filterUpdate({ implementation_id }) - } - /> - -
-
- )} - -
filter.setShow(!filter.show)}> - -
-
- + + + filterUpdate({ q: e.target.value })} + placeholder={translate('components.organization_funds.filters.search')} + /> + + + + filterUpdate({ state })} + /> + + + + filterUpdate({ implementation_id })} + /> + +
@@ -392,7 +364,7 @@ export default function OrganizationFunds() { {fund?.implementation?.name || } - {funds_type == 'active' && ( + {filterValues.funds_type == 'active' && ( {hasPermission(activeOrganization, Permission.VIEW_FINANCES) && ( {fund.budget?.left_locale} diff --git a/react/src/dashboard/components/pages/organizations-notifications/OrganizationsNotifications.tsx b/react/src/dashboard/components/pages/organizations-notifications/OrganizationsNotifications.tsx index 98374623f..d8979ef3e 100644 --- a/react/src/dashboard/components/pages/organizations-notifications/OrganizationsNotifications.tsx +++ b/react/src/dashboard/components/pages/organizations-notifications/OrganizationsNotifications.tsx @@ -4,11 +4,11 @@ import Notification from '../../../props/models/Notification'; import { useNotificationService } from '../../../services/NotificationService'; import LoadingCard from '../../elements/loading-card/LoadingCard'; import Paginator from '../../../modules/paginator/components/Paginator'; -import useFilter from '../../../hooks/useFilter'; import EmptyCard from '../../elements/empty-card/EmptyCard'; import useSetProgress from '../../../hooks/useSetProgress'; import useActiveOrganization from '../../../hooks/useActiveOrganization'; import usePaginatorService from '../../../modules/paginator/services/usePaginatorService'; +import useFilterNext from '../../../modules/filter_next/useFilterNext'; export default function OrganizationsNotifications() { const setProgress = useSetProgress(); @@ -20,7 +20,7 @@ export default function OrganizationsNotifications() { const [notifications, setNotifications] = useState>(null); const [timeoutThreshold] = useState(2500); - const filter = useFilter({ + const [filterValues, filterValuesActive, filterUpdate] = useFilterNext({ per_page: paginatorService.getPerPage(paginatorKey), }); @@ -30,7 +30,7 @@ export default function OrganizationsNotifications() { notificationsService .list({ - ...filter.activeValues, + ...filterValuesActive, organization_id: activeOrganization?.id, mark_read: mark_read ? 1 : 0, }) @@ -40,7 +40,7 @@ export default function OrganizationsNotifications() { }) .finally(() => setProgress(100)); }, - [notificationsService, filter?.activeValues, setProgress, activeOrganization], + [notificationsService, filterValuesActive, setProgress, activeOrganization], ); useEffect(() => { @@ -107,8 +107,8 @@ export default function OrganizationsNotifications() {
diff --git a/react/src/dashboard/components/pages/payouts/Payouts.tsx b/react/src/dashboard/components/pages/payouts/Payouts.tsx index cee5c001c..fe3a327df 100644 --- a/react/src/dashboard/components/pages/payouts/Payouts.tsx +++ b/react/src/dashboard/components/pages/payouts/Payouts.tsx @@ -21,6 +21,7 @@ import usePayoutTransactionService from '../../../services/PayoutTransactionServ import PayoutTransaction from '../../../props/models/PayoutTransaction'; import usePushApiError from '../../../hooks/usePushApiError'; import PayoutsTable from './elements/PayoutsTable'; +import { createEnumParam, NumberParam, StringParam } from 'use-query-params'; export default function Payouts() { const openModal = useOpenModal(); @@ -70,6 +71,7 @@ export default function Payouts() { per_page?: number; order_by?: string; order_dir?: string; + page?: number; }>( { q: '', @@ -87,6 +89,22 @@ export default function Payouts() { order_dir: 'desc', }, { + queryParams: { + q: StringParam, + to: StringParam, + from: StringParam, + state: createEnumParam(['pending', 'success']), + fund_id: NumberParam, + fund_state: createEnumParam(['closed', 'active']), + amount_min: NumberParam, + amount_max: NumberParam, + non_cancelable_from: StringParam, + non_cancelable_to: StringParam, + order_by: StringParam, + order_dir: StringParam, + per_page: NumberParam, + page: NumberParam, + }, throttledValues: ['q', 'amount_min', 'amount_max'], }, ); diff --git a/react/src/dashboard/components/pages/payouts/elements/PayoutsTable.tsx b/react/src/dashboard/components/pages/payouts/elements/PayoutsTable.tsx index 002a53da8..b9fa75e1a 100644 --- a/react/src/dashboard/components/pages/payouts/elements/PayoutsTable.tsx +++ b/react/src/dashboard/components/pages/payouts/elements/PayoutsTable.tsx @@ -3,12 +3,11 @@ import Organization from '../../../../props/models/Organization'; import TableTopScroller from '../../../elements/tables/TableTopScroller'; import Paginator from '../../../../modules/paginator/components/Paginator'; import { PaginationData } from '../../../../props/ApiResponses'; -import { FilterModel, FilterSetter } from '../../../../modules/filter_next/types/FilterParams'; +import { FilterModel, FilterScope, FilterSetter } from '../../../../modules/filter_next/types/FilterParams'; import StateNavLink from '../../../../modules/state_router/StateNavLink'; import { strLimit } from '../../../../helpers/string'; import TableRowActions from '../../../elements/tables/TableRowActions'; import useConfigurableTable from '../../vouchers/hooks/useConfigurableTable'; -import FilterScope from '../../../../types/FilterScope'; import TableDateTime from '../../../elements/tables/elements/TableDateTime'; import TableEmptyValue from '../../../elements/table-empty-value/TableEmptyValue'; import TransactionStateLabel from '../../../elements/resource-states/TransactionStateLabel'; diff --git a/react/src/dashboard/components/pages/products-view/ProductView.tsx b/react/src/dashboard/components/pages/products-view/ProductView.tsx index cc1c63c34..c0587f98c 100644 --- a/react/src/dashboard/components/pages/products-view/ProductView.tsx +++ b/react/src/dashboard/components/pages/products-view/ProductView.tsx @@ -10,7 +10,6 @@ import useOpenModal from '../../../hooks/useOpenModal'; import Product from '../../../props/models/Product'; import { PaginationData, ResponseError } from '../../../props/ApiResponses'; import usePushSuccess from '../../../hooks/usePushSuccess'; -import useFilter from '../../../hooks/useFilter'; import ModalNotification from '../../modals/ModalNotification'; import FundProviderChat from '../../../props/models/FundProviderChat'; import ModalFundProviderChatProvider from '../../modals/ModalFundProviderChatProvider'; @@ -27,6 +26,8 @@ import useConfigurableTable from '../vouchers/hooks/useConfigurableTable'; import TableTopScroller from '../../elements/tables/TableTopScroller'; import TableRowActions from '../../elements/tables/TableRowActions'; import classNames from 'classnames'; +import useFilterNext from '../../../modules/filter_next/useFilterNext'; +import { NumberParam, StringParam } from 'use-query-params'; type ProductFundLocal = ProductFund & { chat?: FundProviderChat; @@ -53,10 +54,24 @@ export default function ProductView() { const pushSuccess = usePushSuccess(); const pushApiError = usePushApiError(); - const filter = useFilter({ - q: '', - per_page: paginatorService.getPerPage(paginatorKey), - }); + const [filterValues, filterValuesActive, filterUpdate] = useFilterNext<{ + q: string; + page?: number; + per_page?: number; + }>( + { + q: '', + page: 1, + per_page: paginatorService.getPerPage(paginatorKey), + }, + { + queryParams: { + q: StringParam, + page: NumberParam, + per_page: NumberParam, + }, + }, + ); const { headElement, configsElement } = useConfigurableTable(productService.getFundsColumns(product)); @@ -132,10 +147,10 @@ export default function ProductView() { } productService - .listProductFunds(product.organization_id, product.id, { ...filter.activeValues, organization_id: null }) + .listProductFunds(product.organization_id, product.id, { ...filterValuesActive, organization_id: null }) .then(async (res) => setFunds(mapFundsWithChats(res.data, await fetchChats(product)))) .catch(console.error); - }, [fetchChats, filter.activeValues, mapFundsWithChats, product, productService]); + }, [fetchChats, filterValuesActive, mapFundsWithChats, product, productService]); const showTheChat = (fund: ProductFundLocal) => { if (!fund.chat) { @@ -226,8 +241,8 @@ export default function ProductView() { className="form-control" type="text" placeholder="Zoeken" - value={filter.values.q} - onChange={(e) => filter.update({ q: e.target.value })} + value={filterValues.q} + onChange={(e) => filterUpdate({ q: e.target.value })} />
@@ -361,8 +376,8 @@ export default function ProductView() {
diff --git a/react/src/dashboard/components/pages/products/Products.tsx b/react/src/dashboard/components/pages/products/Products.tsx index df2e41164..bfb963057 100644 --- a/react/src/dashboard/components/pages/products/Products.tsx +++ b/react/src/dashboard/components/pages/products/Products.tsx @@ -6,7 +6,6 @@ import useProductService from '../../../services/ProductService'; import Product from '../../../props/models/Product'; import { PaginationData } from '../../../props/ApiResponses'; import useAppConfigs from '../../../hooks/useAppConfigs'; -import useFilter from '../../../hooks/useFilter'; import useOpenModal from '../../../hooks/useOpenModal'; import StateNavLink from '../../../modules/state_router/StateNavLink'; import Paginator from '../../../modules/paginator/components/Paginator'; @@ -20,6 +19,8 @@ import classNames from 'classnames'; import BlockLabelTabs from '../../elements/block-label-tabs/BlockLabelTabs'; import TableEntityMain from '../../elements/tables/elements/TableEntityMain'; import TableEmptyValue from '../../elements/table-empty-value/TableEmptyValue'; +import useFilterNext from '../../../modules/filter_next/useFilterNext'; +import { createEnumParam, NumberParam, StringParam } from 'use-query-params'; type ProductsDataLocal = PaginationData< Product, @@ -53,11 +54,27 @@ export default function Products() { return maxProductSoftLimit > 0 && products?.meta?.total_provider >= maxProductSoftLimit; }, [maxProductSoftLimit, products?.meta?.total_provider]); - const filter = useFilter({ - q: '', - source: 'provider', - per_page: paginatorService.getPerPage(paginatorKey), - }); + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext<{ + q: string; + source: 'provider' | 'sponsor' | 'archive'; + page?: number; + per_page?: number; + }>( + { + q: '', + source: 'provider', + page: 1, + per_page: paginatorService.getPerPage(paginatorKey), + }, + { + queryParams: { + q: StringParam, + source: createEnumParam(['provider', 'sponsor', 'archive']), + per_page: NumberParam, + page: NumberParam, + }, + }, + ); const { headElement, configsElement } = useConfigurableTable(productService.getColumns(), { sortable: true, @@ -91,13 +108,13 @@ export default function Products() { setLoading(true); productService - .list(activeOrganization.id, filter.activeValues) + .list(activeOrganization.id, filterValuesActive) .then((res) => setProducts(res.data)) .finally(() => { setLoading(false); setProgress(100); }); - }, [productService, activeOrganization.id, setProgress, filter?.activeValues]); + }, [productService, activeOrganization.id, setProgress, filterValuesActive]); useEffect(() => { fetchProducts(); @@ -130,8 +147,8 @@ export default function Products() { filter.update({ source: value })} + value={filterValues.source} + setValue={(value: 'provider' | 'sponsor' | 'archive') => filterUpdate({ source: value })} tabs={[ { value: 'provider', label: `In uw beheer (${products?.meta?.total_provider})` }, { value: 'sponsor', label: `In beheer van sponsor (${products?.meta?.total_sponsor})` }, @@ -143,8 +160,8 @@ export default function Products() { filter.update({ q: e.target.value })} + value={filterValues.q} + onChange={(e) => filterUpdate({ q: e.target.value })} data-dusk="searchTransaction" placeholder={translate('transactions.labels.search')} /> @@ -216,7 +233,7 @@ export default function Products() { - {filter.values.source != 'archive' ? ( + {filterValues.source != 'archive' ? ( (
@@ -284,7 +301,7 @@ export default function Products() {
)} - {!loading && filter.values.source == 'provider' && products.meta.total == 0 && !filter.activeValues.q && ( + {!loading && filterValues.source == 'provider' && products.meta.total == 0 && !filterValuesActive.q && (
Er zijn momenteel geen aanbiedingen.

@@ -298,19 +315,19 @@ export default function Products() {
)} - {!loading && filter.values.source == 'provider' && products.meta.total == 0 && filter.activeValues.q && ( + {!loading && filterValues.source == 'provider' && products.meta.total == 0 && filterValuesActive.q && (
Er zijn geen aanbiedingen gevonden voor de zoekopdracht.
)} - {!loading && filter.values.source == 'sponsor' && products.meta.total == 0 && ( + {!loading && filterValues.source == 'sponsor' && products.meta.total == 0 && (
Er zijn momenteel geen aanbiedingen.
)} - {!loading && filter.values.source == 'archive' && products.meta.total == 0 && ( + {!loading && filterValues.source == 'archive' && products.meta.total == 0 && (
Er zijn momenteel geen aanbiedingen.
@@ -320,8 +337,8 @@ export default function Products() {
diff --git a/react/src/dashboard/components/pages/provider-funds/ProviderFunds.tsx b/react/src/dashboard/components/pages/provider-funds/ProviderFunds.tsx index 6b7670e96..f73a513df 100644 --- a/react/src/dashboard/components/pages/provider-funds/ProviderFunds.tsx +++ b/react/src/dashboard/components/pages/provider-funds/ProviderFunds.tsx @@ -8,6 +8,7 @@ import ProviderFundsAvailableTable from './elements/ProviderFundsAvailableTable' import ProviderFundInvitationsTable from './elements/ProviderFundInvitationsTable'; import useTranslate from '../../../hooks/useTranslate'; import usePushApiError from '../../../hooks/usePushApiError'; +import { StringParam, useQueryParam } from 'use-query-params'; export default function ProviderFunds() { const translate = useTranslate(); @@ -15,7 +16,22 @@ export default function ProviderFunds() { const activeOrganization = useActiveOrganization(); const providerFundService = useProviderFundService(); - const [tab, setTab] = useState('active'); + const [tabQuery = 'active', setTabQuery] = useQueryParam('tab', StringParam, { + removeDefaultsFromUrl: true, + }); + + const setTab = useCallback( + (item: string) => { + setTabQuery('none'); + + // added timeout to wait while components clear filter query params and avoid reset 'tab' param + setTimeout(() => { + setTabQuery(item); + }, 100); + }, + [setTabQuery], + ); + const [fundsAvailable, setFundsAvailable] = useState(null); const fetchFunds = useCallback(() => { @@ -41,13 +57,13 @@ export default function ProviderFunds() {
setTab('active')}> {translate('provider_funds.tabs.active')} ({fundsAvailable.meta.totals.active})
setTab('pending_rejected')}> {translate('provider_funds.tabs.pending_rejected')} ( @@ -55,14 +71,14 @@ export default function ProviderFunds() {
setTab('available')}> {translate('provider_funds.tabs.available')} ({fundsAvailable.meta.totals.available})
setTab('archived')}> {translate('provider_funds.tabs.archived')} ({fundsAvailable.meta.totals.archived}) @@ -74,14 +90,14 @@ export default function ProviderFunds() {
setTab('invitations')}> {translate('provider_funds.tabs.invitations')} ({fundsAvailable.meta.totals.invitations} )
setTab('invitations_archived')}> {translate('provider_funds.tabs.invitations_archived')} ( {fundsAvailable.meta.totals.invitations_archived}) @@ -93,7 +109,7 @@ export default function ProviderFunds() {
setTab('unsubscriptions')}> {translate('provider_funds.tabs.unsubscriptions')} ( @@ -104,28 +120,30 @@ export default function ProviderFunds() {
+ {tabQuery == 'none' && } + {/* Active funds */} - {tab == 'active' && ( + {tabQuery == 'active' && ( )} {/* Pending and rejected funds */} - {tab == 'pending_rejected' && ( + {tabQuery == 'pending_rejected' && ( )} {/* Archived funds */} - {tab == 'archived' && ( + {tabQuery == 'archived' && ( )} {/* Fund unsubscription requests */} - {tab == 'unsubscriptions' && ( + {tabQuery == 'unsubscriptions' && ( )} {/* Available funds */} - {tab == 'available' && ( + {tabQuery == 'available' && ( { @@ -136,7 +154,7 @@ export default function ProviderFunds() { )} {/* Fund invitations */} - {tab == 'invitations' && ( + {tabQuery == 'invitations' && ( >(null); const [paginatorKey] = useState(`provider_fund_${type}`); - const filter = useFilter({ - q: '', - from: '', - to: '', - state: null, - per_page: paginatorService.getPerPage(paginatorKey), - }); + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext<{ + q: string; + from?: string; + to?: string; + state?: string; + per_page?: number; + }>( + { + q: '', + from: '', + to: '', + state: null, + per_page: paginatorService.getPerPage(paginatorKey), + }, + { + queryParams: { + q: StringParam, + from: StringParam, + to: StringParam, + state: StringParam, + per_page: NumberParam, + }, + }, + ); + + const { resetFilters: resetFilters } = filter; const { selected, setSelected, toggleAll, toggle } = useTableToggles(); const selectedMeta = useMemo(() => { @@ -69,7 +89,7 @@ export default function ProviderFundInvitationsTable({ const { headElement, configsElement } = useConfigurableTable(fundProviderInvitationsService.getColumns(), { trPrepend: ( - {[null, 'pending'].includes(filter.values.state) && ( + {[null, 'pending'].includes(filterValues.state) && ( = []) => { - const promises = invitations.map((item) => { - return fundProviderInvitationsService.acceptInvitationById(organization.id, item.id); - }); - - Promise.all(promises) - .then(() => pushSuccess('Uitnodiging succesvol geaccepteerd!')) - .catch(pushApiError) - .finally(() => { - filter.touch(); - onChange?.(); - }); - }, - [filter, fundProviderInvitationsService, onChange, organization.id, pushApiError, pushSuccess], - ); - const mapProviderFunds = useCallback( ( items: Array, @@ -122,33 +125,64 @@ export default function ProviderFundInvitationsTable({ [translate], ); - const fetchInvitations = useCallback( - async (filters: object) => { - setLoading(true); - setProgress(0); - - return fundProviderInvitationsService - .listInvitations(organization.id, { ...filters, expired: type == 'invitations_archived' ? 1 : 0 }) - .finally(() => { - setLoading(false); - setProgress(100); - }); - }, - [organization.id, fundProviderInvitationsService, setProgress, type], - ); - - useEffect(() => { + const fetchInvitations = useCallback(() => { setSelected([]); + setLoading(true); + setProgress(0); - fetchInvitations(filter.activeValues) + fundProviderInvitationsService + .listInvitations(organization.id, { + ...filterValuesActive, + expired: type == 'invitations_archived' ? 1 : 0, + }) .then((res) => setInvitations({ data: mapProviderFunds(res.data.data), meta: res.data.meta, }), ) - .catch(pushApiError); - }, [fetchInvitations, filter.activeValues, mapProviderFunds, pushApiError, setSelected]); + .catch(pushApiError) + .finally(() => { + setLoading(false); + setProgress(100); + }); + }, [ + setSelected, + setProgress, + fundProviderInvitationsService, + organization.id, + filterValuesActive, + type, + pushApiError, + mapProviderFunds, + ]); + + const acceptInvitations = useCallback( + (invitations: Array = []) => { + const promises = invitations.map((item) => { + return fundProviderInvitationsService.acceptInvitationById(organization.id, item.id); + }); + + Promise.all(promises) + .then(() => pushSuccess('Uitnodiging succesvol geaccepteerd!')) + .catch(pushApiError) + .finally(() => { + fetchInvitations(); + onChange?.(); + }); + }, + [fetchInvitations, fundProviderInvitationsService, onChange, organization.id, pushApiError, pushSuccess], + ); + + useEffect(() => { + fetchInvitations(); + }, [fetchInvitations]); + + useEffect(() => { + return () => { + resetFilters(); + }; + }, [resetFilters]); return (
@@ -176,8 +210,8 @@ export default function ProviderFundInvitationsTable({
filter.update({ q: e.target.value })} + value={filterValues.q} + onChange={(e) => filterUpdate({ q: e.target.value })} placeholder="Zoeken" />
@@ -200,7 +234,7 @@ export default function ProviderFundInvitationsTable({ - {[null, 'pending'].includes(filter.values.state) && ( + {[null, 'pending'].includes(filterValues.state) && (
diff --git a/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundUnsubscriptionsTable.tsx b/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundUnsubscriptionsTable.tsx index bc55cf680..9dcf7340d 100644 --- a/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundUnsubscriptionsTable.tsx +++ b/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundUnsubscriptionsTable.tsx @@ -1,5 +1,4 @@ import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'react'; -import useFilter from '../../../../hooks/useFilter'; import { PaginationData } from '../../../../props/ApiResponses'; import Organization from '../../../../props/models/Organization'; import useSetProgress from '../../../../hooks/useSetProgress'; @@ -27,6 +26,8 @@ import TableRowActions from '../../../elements/tables/TableRowActions'; import TableEmptyValue from '../../../elements/table-empty-value/TableEmptyValue'; import usePushApiError from '../../../../hooks/usePushApiError'; import Label from '../../../elements/image_cropper/Label'; +import useFilterNext from '../../../../modules/filter_next/useFilterNext'; +import { NumberParam, StringParam } from 'use-query-params'; type FundProviderUnsubscribeLocal = FundProviderUnsubscribe & { showTooltip?: boolean; @@ -60,13 +61,34 @@ export default function ProviderFundUnsubscriptionsTable({ { key: 'canceled', label: 'Geannuleerd' }, ]); - const filter = useFilter({ - q: '', - state: null, - per_page: paginatorService.getPerPage(paginatorKey), - from: '', - to: '', - }); + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext<{ + q: string; + state?: string; + from?: string; + to?: string; + page?: number; + per_page?: number; + }>( + { + q: '', + state: null, + from: '', + to: '', + per_page: paginatorService.getPerPage(paginatorKey), + }, + { + queryParams: { + q: StringParam, + state: StringParam, + from: StringParam, + to: StringParam, + page: NumberParam, + per_page: NumberParam, + }, + }, + ); + + const { resetFilters: resetFilters } = filter; const [fundUnsubscriptions, setFundUnsubscriptions] = useState>(null); @@ -84,7 +106,7 @@ export default function ProviderFundUnsubscriptionsTable({ const { headElement, configsElement } = useConfigurableTable(fundUnsubscribeService.getColumns(), { trPrepend: ( - {[null, 'pending'].includes(filter.values.state) && ( + {[null, 'pending'].includes(filterValues.state) && ( { + setSelected([]); + setLoading(true); + setProgress(0); + + fundUnsubscribeService + .listProvider(organization.id, filterValuesActive) + .then((res) => setFundUnsubscriptions(res.data)) + .catch(pushApiError) + .finally(() => { + setLoading(false); + setProgress(100); + }); + }, [setSelected, setProgress, fundUnsubscribeService, organization.id, filterValuesActive, pushApiError]); + const cancelUnsubscriptions = useCallback( (unsubscriptions: Array) => { openModal((modal) => ( @@ -114,7 +151,7 @@ export default function ProviderFundUnsubscriptionsTable({ .then(() => pushSuccess('Opgeslagen!')) .catch(pushApiError) .finally(() => { - filter.touch(); + fetchUnsubscriptions(); modal.close(); onChange?.(); }); @@ -127,29 +164,27 @@ export default function ProviderFundUnsubscriptionsTable({ /> )); }, - [filter, fundUnsubscribeService, onChange, openModal, organization.id, pushApiError, pushSuccess, translate], - ); - - const fetchUnsubscriptions = useCallback( - async (filters: object) => { - setLoading(true); - setProgress(0); - - return fundUnsubscribeService.listProvider(organization.id, filters).finally(() => { - setLoading(false); - setProgress(100); - }); - }, - [organization.id, fundUnsubscribeService, setProgress], + [ + fetchUnsubscriptions, + fundUnsubscribeService, + onChange, + openModal, + organization.id, + pushApiError, + pushSuccess, + translate, + ], ); useEffect(() => { - setSelected([]); + fetchUnsubscriptions(); + }, [fetchUnsubscriptions]); - fetchUnsubscriptions(filter.activeValues) - .then((res) => setFundUnsubscriptions(res.data)) - .catch(pushApiError); - }, [fetchUnsubscriptions, filter.activeValues, pushApiError, setSelected]); + useEffect(() => { + return () => { + resetFilters(); + }; + }, [resetFilters]); return (
@@ -180,9 +215,9 @@ export default function ProviderFundUnsubscriptionsTable({
filter.update({ state: state.key })}> + onClick={() => filterUpdate({ state: state.key })}> {state.label}
))} @@ -191,7 +226,7 @@ export default function ProviderFundUnsubscriptionsTable({
{filter.show && ( -
+
Wis filters
@@ -202,8 +237,8 @@ export default function ProviderFundUnsubscriptionsTable({
filter.update({ q: e.target.value })} + value={filterValues.q} + onChange={(e) => filterUpdate({ q: e.target.value })} placeholder="Zoeken" />
@@ -213,28 +248,28 @@ export default function ProviderFundUnsubscriptionsTable({ filter.update({ q: e.target.value })} + value={filterValues.q} + onChange={(e) => filterUpdate({ q: e.target.value })} placeholder="Zoeken" /> { - filter.update({ from: dateFormat(from) }); + filterUpdate({ from: dateFormat(from) }); }} /> { - filter.update({ to: dateFormat(to) }); + filterUpdate({ to: dateFormat(to) }); }} /> @@ -256,7 +291,7 @@ export default function ProviderFundUnsubscriptionsTable({ - {[null, 'pending'].includes(filter.values.state) && ( + {[null, 'pending'].includes(filterValues.state) && (
diff --git a/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundsAvailableTable.tsx b/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundsAvailableTable.tsx index 18ed0e90f..b83beca41 100644 --- a/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundsAvailableTable.tsx +++ b/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundsAvailableTable.tsx @@ -1,5 +1,4 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import useFilter from '../../../../hooks/useFilter'; import { PaginationData } from '../../../../props/ApiResponses'; import Organization from '../../../../props/models/Organization'; import useProviderFundService from '../../../../services/ProviderFundService'; @@ -23,6 +22,8 @@ import useTranslate from '../../../../hooks/useTranslate'; import useConfigurableTable from '../../vouchers/hooks/useConfigurableTable'; import TableTopScroller from '../../../elements/tables/TableTopScroller'; import usePushApiError from '../../../../hooks/usePushApiError'; +import useFilterNext from '../../../../modules/filter_next/useFilterNext'; +import { NumberParam, StringParam } from 'use-query-params'; export default function ProviderFundsAvailableTable({ organization, @@ -55,16 +56,41 @@ export default function ProviderFundsAvailableTable({ return { selected: funds?.data?.filter((item) => selected?.includes(item.id)) }; }, [funds?.data, selected]); - const filter = useFilter({ - q: '', - tag: null, - page: 1, - per_page: paginatorService.getPerPage(paginatorKey), - organization_id: null, - implementation_id: null, - order_by: 'organization_name', - order_dir: 'asc', - }); + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext<{ + q: string; + tag?: string; + organization_id?: number; + implementation_id?: number; + page?: number; + per_page?: number; + order_by?: string; + order_dir?: string; + }>( + { + q: '', + tag: null, + page: 1, + per_page: paginatorService.getPerPage(paginatorKey), + organization_id: null, + implementation_id: null, + order_by: 'organization_name', + order_dir: 'asc', + }, + { + queryParams: { + q: StringParam, + tag: StringParam, + organization_id: NumberParam, + implementation_id: NumberParam, + page: NumberParam, + per_page: NumberParam, + order_by: StringParam, + order_dir: StringParam, + }, + }, + ); + + const { resetFilters: resetFilters } = filter; const { headElement, configsElement } = useConfigurableTable(providerFundService.getColumnsAvailable(), { filter: filter, @@ -108,61 +134,15 @@ export default function ProviderFundsAvailableTable({ )); }, [openModal, translate]); - const applyFunds = useCallback( - (funds) => { - if (organization.offices_count == 0) { - return failOfficesCheck(); - } - - const promises = funds.map((fund: Fund) => { - return providerFundService.applyForFund(organization.id, fund.id); - }); - - Promise.all(promises) - .then(() => { - successApplying(); - setSelected([]); - }) - .catch(pushApiError) - .finally(() => { - filter.touch(); - onChange?.(); - }); - }, - [ - failOfficesCheck, - filter, - onChange, - organization.id, - organization.offices_count, - providerFundService, - pushApiError, - setSelected, - successApplying, - ], - ); - - const fetchFunds = useCallback( - async (filters: object) => { - setLoading(true); - setProgress(0); - - try { - return await providerFundService.listAvailableFunds(organization.id, { - ...filters, - }); - } finally { - setLoading(false); - setProgress(100); - } - }, - [organization.id, providerFundService, setProgress], - ); - - useEffect(() => { + const fetchFunds = useCallback(() => { setSelected([]); + setLoading(true); + setProgress(0); - fetchFunds(filter.activeValues) + providerFundService + .listAvailableFunds(organization.id, { + ...filterValuesActive, + }) .then((res) => { setFunds(res.data); @@ -199,8 +179,56 @@ export default function ProviderFundsAvailableTable({ ]; }); }) - .catch(pushApiError); - }, [fetchFunds, filter.activeValues, organization, pushApiError, setSelected, translate]); + .catch(pushApiError) + .finally(() => { + setLoading(false); + setProgress(100); + }); + }, [filterValuesActive, organization.id, providerFundService, pushApiError, setProgress, setSelected, translate]); + + const applyFunds = useCallback( + (funds: Array) => { + if (organization.offices_count == 0) { + return failOfficesCheck(); + } + + const promises = funds.map((fund: Fund) => { + return providerFundService.applyForFund(organization.id, fund.id); + }); + + Promise.all(promises) + .then(() => { + successApplying(); + setSelected([]); + }) + .catch(pushApiError) + .finally(() => { + fetchFunds(); + onChange?.(); + }); + }, + [ + failOfficesCheck, + fetchFunds, + onChange, + organization.id, + organization.offices_count, + providerFundService, + pushApiError, + setSelected, + successApplying, + ], + ); + + useEffect(() => { + fetchFunds(); + }, [fetchFunds]); + + useEffect(() => { + return () => { + resetFilters(); + }; + }, [resetFilters]); return (
@@ -224,7 +252,7 @@ export default function ProviderFundsAvailableTable({ )} {filter.show && ( -
+
resetFilters()}> Wis filters
@@ -235,9 +263,9 @@ export default function ProviderFundsAvailableTable({
filter.update({ q: e.target.value })} + onChange={(e) => filterUpdate({ q: e.target.value })} placeholder="Zoeken" />
@@ -248,8 +276,8 @@ export default function ProviderFundsAvailableTable({ filter.update({ q: e.target.value })} + value={filterValues.q} + onChange={(e) => filterUpdate({ q: e.target.value })} placeholder="Zoeken" /> @@ -258,12 +286,12 @@ export default function ProviderFundsAvailableTable({ dusk="selectControlImplementationsToggle" label={translate('provider_funds.filters.labels.implementations')}> filter.update({ implementation_id })} + onChange={(implementation_id?: number) => filterUpdate({ implementation_id })} /> @@ -271,12 +299,12 @@ export default function ProviderFundsAvailableTable({ dusk="selectControlOrganizationsToggle" label={translate('provider_funds.filters.labels.organizations')}> filter.update({ organization_id })} + onChange={(organization_id?: number) => filterUpdate({ organization_id })} /> @@ -284,12 +312,12 @@ export default function ProviderFundsAvailableTable({ dusk="selectControlTagsToggle" label={translate('provider_funds.filters.labels.tags')}> filter.update({ tag })} + onChange={(tag?: string) => filterUpdate({ tag })} /> @@ -399,8 +427,8 @@ export default function ProviderFundsAvailableTable({
diff --git a/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundsTable.tsx b/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundsTable.tsx index 99c0527c1..9bbb9983d 100644 --- a/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundsTable.tsx +++ b/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundsTable.tsx @@ -1,5 +1,4 @@ import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'react'; -import useFilter from '../../../../hooks/useFilter'; import { PaginationData } from '../../../../props/ApiResponses'; import FundProvider from '../../../../props/models/FundProvider'; import Organization from '../../../../props/models/Organization'; @@ -25,6 +24,8 @@ import TableRowActions from '../../../elements/tables/TableRowActions'; import classNames from 'classnames'; import usePushApiError from '../../../../hooks/usePushApiError'; import Label from '../../../elements/image_cropper/Label'; +import useFilterNext from '../../../../modules/filter_next/useFilterNext'; +import { NumberParam, StringParam } from 'use-query-params'; export default function ProviderFundsTable({ type, @@ -50,10 +51,12 @@ export default function ProviderFundsTable({ const [paginatorKey] = useState(`provider_funds_${type}`); const [providerFunds, setProviderFunds] = useState>(null); - const filter = useFilter({ - q: '', - per_page: paginatorService.getPerPage(paginatorKey), - }); + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext<{ q: string; per_page?: number }>( + { q: '', per_page: paginatorService.getPerPage(paginatorKey) }, + { queryParams: { q: StringParam, per_page: NumberParam } }, + ); + + const { resetFilters: resetFilters } = filter; const { selected, setSelected, toggleAll, toggle } = useTableToggles(); @@ -91,6 +94,26 @@ export default function ProviderFundsTable({ [openModal, organization], ); + const fetchFunds = useCallback(() => { + setSelected([]); + setLoading(true); + setProgress(0); + + providerFundService + .listFunds(organization.id, { + active: type == 'active' ? 1 : 0, + pending: type == 'pending_rejected' ? 1 : 0, + archived: type == 'archived' ? 1 : 0, + ...filterValuesActive, + }) + .then((res) => setProviderFunds(res.data)) + .catch(pushApiError) + .finally(() => { + setLoading(false); + setProgress(100); + }); + }, [filterValuesActive, organization.id, providerFundService, pushApiError, setProgress, setSelected, type]); + const cancelApplications = useCallback( (providerFunds: Array) => { const sponsor_organization_name = @@ -123,7 +146,7 @@ export default function ProviderFundsTable({ .catch(pushApiError) .finally(() => { setProgress(100); - filter.touch(); + fetchFunds(); onChange?.(); }); }, @@ -133,7 +156,7 @@ export default function ProviderFundsTable({ }); }, [ - filter, + fetchFunds, onChange, openModal, organization.id, @@ -153,42 +176,24 @@ export default function ProviderFundsTable({ providerFund={providerFund} organization={organization} onUnsubscribe={() => { - filter.touch(); + fetchFunds(); onChange?.(); }} /> )); }, - [filter, onChange, openModal, organization], - ); - - const fetchFunds = useCallback( - async (filters: object) => { - setLoading(true); - setProgress(0); - - try { - return await providerFundService.listFunds(organization.id, { - active: type == 'active' ? 1 : 0, - pending: type == 'pending_rejected' ? 1 : 0, - archived: type == 'archived' ? 1 : 0, - ...filters, - }); - } finally { - setLoading(false); - setProgress(100); - } - }, - [organization.id, providerFundService, setProgress, type], + [fetchFunds, onChange, openModal, organization], ); useEffect(() => { - setSelected([]); + fetchFunds(); + }, [fetchFunds]); - fetchFunds(filter.activeValues) - .then((res) => setProviderFunds(res.data)) - .catch(pushApiError); - }, [fetchFunds, filter.activeValues, pushApiError, setSelected]); + useEffect(() => { + return () => { + resetFilters(); + }; + }, [resetFilters]); return (
@@ -216,8 +221,8 @@ export default function ProviderFundsTable({
filter.update({ q: e.target.value })} + value={filterValues.q} + onChange={(e) => filterUpdate({ q: e.target.value })} placeholder="Zoeken" />
@@ -402,8 +407,8 @@ export default function ProviderFundsTable({
diff --git a/react/src/dashboard/components/pages/sponsor-provider-organization/SponsorProviderOrganization.tsx b/react/src/dashboard/components/pages/sponsor-provider-organization/SponsorProviderOrganization.tsx index a01c09206..b9f79b0db 100644 --- a/react/src/dashboard/components/pages/sponsor-provider-organization/SponsorProviderOrganization.tsx +++ b/react/src/dashboard/components/pages/sponsor-provider-organization/SponsorProviderOrganization.tsx @@ -1,6 +1,5 @@ import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react'; import useActiveOrganization from '../../../hooks/useActiveOrganization'; -import useFilter from '../../../hooks/useFilter'; import { PaginationData } from '../../../props/ApiResponses'; import { useParams } from 'react-router'; import useSetProgress from '../../../hooks/useSetProgress'; @@ -20,6 +19,8 @@ import useConfigurableTable from '../vouchers/hooks/useConfigurableTable'; import { useFundService } from '../../../services/FundService'; import SponsorProviderOffices from './elements/SponsorProviderOffices'; import SponsorProviderEmployees from './elements/SponsorProviderEmployees'; +import useFilterNext from '../../../modules/filter_next/useFilterNext'; +import { NumberParam, StringParam } from 'use-query-params'; export default function SponsorProviderOrganization() { const { id } = useParams(); @@ -35,7 +36,24 @@ export default function SponsorProviderOrganization() { const [fundProviders, setFundProviders] = useState>(null); const [providerOrganization, setProviderOrganization] = useState(null); - const filter = useFilter({ q: '', per_page: 10 }); + const [filterValues, filterValuesActive, filterUpdate] = useFilterNext<{ + q: string; + page?: number; + per_page?: number; + }>( + { + q: '', + page: 1, + per_page: 10, + }, + { + queryParams: { + q: StringParam, + page: NumberParam, + }, + }, + ); + const tableRef = useRef(null); const { headElement, configsElement } = useConfigurableTable(fundService.getProviderFundColumns()); @@ -53,11 +71,11 @@ export default function SponsorProviderOrganization() { setProgress(0); organizationService - .listProviders(activeOrganization.id, { ...filter.activeValues, organization_id: id }) + .listProviders(activeOrganization.id, { ...filterValuesActive, organization_id: id }) .then((res) => setFundProviders(res.data)) .catch(pushApiError) .finally(() => setProgress(100)); - }, [setProgress, organizationService, activeOrganization.id, filter.activeValues, id, pushApiError]); + }, [setProgress, organizationService, activeOrganization.id, filterValuesActive, id, pushApiError]); const fetchProviderOrganization = useCallback(() => { setProgress(0); @@ -105,8 +123,8 @@ export default function SponsorProviderOrganization() {
filter.update({ q: e.target.value })} + value={filterValues.q} + onChange={(e) => filterUpdate({ q: e.target.value })} placeholder="Zoeken" />
@@ -139,7 +157,7 @@ export default function SponsorProviderOrganization() { {fundProviders.meta && (
- +
)}
diff --git a/react/src/dashboard/components/pages/sponsor-provider-organizations/elements/ProvidersTableItem.tsx b/react/src/dashboard/components/pages/sponsor-provider-organizations/elements/ProvidersTableItem.tsx index 393aca97e..c0631cc8a 100644 --- a/react/src/dashboard/components/pages/sponsor-provider-organizations/elements/ProvidersTableItem.tsx +++ b/react/src/dashboard/components/pages/sponsor-provider-organizations/elements/ProvidersTableItem.tsx @@ -4,7 +4,6 @@ import { PaginationData } from '../../../../props/ApiResponses'; import Organization, { SponsorProviderOrganization } from '../../../../props/models/Organization'; import ProvidersTableItemFunds from './ProvidersTableItemFunds'; import { useOrganizationService } from '../../../../services/OrganizationService'; -import useFilter from '../../../../hooks/useFilter'; import FundProvider from '../../../../props/models/FundProvider'; import useSetProgress from '../../../../hooks/useSetProgress'; import useTranslate from '../../../../hooks/useTranslate'; @@ -12,6 +11,7 @@ import StateNavLink from '../../../../modules/state_router/StateNavLink'; import TableRowActions from '../../../elements/tables/TableRowActions'; import usePushApiError from '../../../../hooks/usePushApiError'; import classNames from 'classnames'; +import useFilterNext from '../../../../modules/filter_next/useFilterNext'; export default function ProvidersTableItem({ organization, @@ -29,17 +29,23 @@ export default function ProvidersTableItem({ const [fundProviders, setFundProviders] = useState>(null); const [showFundProviders, setShowFundProviders] = useState(false); - const filter = useFilter({ q: '', per_page: 10, organization_id: providerOrganization.id }); + const [filterValues, filterValuesActive, filterUpdate] = useFilterNext<{ + per_page?: number; + organization_id?: number; + }>({ + per_page: 10, + organization_id: providerOrganization.id, + }); const fetchFundProviders = useCallback(() => { setProgress(0); organizationService - .listProviders(organization.id, filter.activeValues) + .listProviders(organization.id, filterValuesActive) .then((res) => setFundProviders(res.data)) .catch(pushApiError) .finally(() => setProgress(100)); - }, [filter.activeValues, organization.id, organizationService, pushApiError, setProgress]); + }, [filterValuesActive, organization.id, organizationService, pushApiError, setProgress]); useEffect(() => { if (showFundProviders) { @@ -115,7 +121,12 @@ export default function ProvidersTableItem({ {showFundProviders && fundProviders && ( - + )} ); diff --git a/react/src/dashboard/components/pages/sponsor-provider-organizations/elements/ProvidersTableItemFunds.tsx b/react/src/dashboard/components/pages/sponsor-provider-organizations/elements/ProvidersTableItemFunds.tsx index c62349e88..dad533dcf 100644 --- a/react/src/dashboard/components/pages/sponsor-provider-organizations/elements/ProvidersTableItemFunds.tsx +++ b/react/src/dashboard/components/pages/sponsor-provider-organizations/elements/ProvidersTableItemFunds.tsx @@ -3,21 +3,22 @@ import { strLimit } from '../../../../helpers/string'; import Paginator from '../../../../modules/paginator/components/Paginator'; import { PaginationData } from '../../../../props/ApiResponses'; import Organization from '../../../../props/models/Organization'; -import FilterScope from '../../../../types/FilterScope'; -import FilterModel from '../../../../types/FilterModel'; import FundProvider from '../../../../props/models/FundProvider'; import StateNavLink from '../../../../modules/state_router/StateNavLink'; import FundStateLabels from '../../../elements/resource-states/FundStateLabels'; import TableRowActions from '../../../elements/tables/TableRowActions'; import useConfigurableTable from '../../vouchers/hooks/useConfigurableTable'; import { useOrganizationService } from '../../../../services/OrganizationService'; +import { FilterModel, FilterSetter } from '../../../../modules/filter_next/types/FilterParams'; export default function ProvidersTableItemFunds({ - filter, + filterValues, + filterUpdate, organization, fundProviders, }: { - filter: FilterScope; + filterValues: FilterModel; + filterUpdate: FilterSetter; organization: Organization; fundProviders: PaginationData; }) { @@ -114,8 +115,8 @@ export default function ProvidersTableItemFunds({ diff --git a/react/src/dashboard/components/pages/transaction-bulks-view/elements/TransactionBulkTransactionsTable.tsx b/react/src/dashboard/components/pages/transaction-bulks-view/elements/TransactionBulkTransactionsTable.tsx index 79a3372c8..949c9cdd8 100644 --- a/react/src/dashboard/components/pages/transaction-bulks-view/elements/TransactionBulkTransactionsTable.tsx +++ b/react/src/dashboard/components/pages/transaction-bulks-view/elements/TransactionBulkTransactionsTable.tsx @@ -8,7 +8,6 @@ import useTransactionExporter from '../../../../services/exporters/useTransactio import Organization from '../../../../props/models/Organization'; import TransactionBulk from '../../../../props/models/TransactionBulk'; import useTransactionService from '../../../../services/TransactionService'; -import useFilter from '../../../../hooks/useFilter'; import usePaginatorService from '../../../../modules/paginator/services/usePaginatorService'; import useSetProgress from '../../../../hooks/useSetProgress'; import useEnvData from '../../../../hooks/useEnvData'; @@ -18,6 +17,8 @@ import usePushApiError from '../../../../hooks/usePushApiError'; import Label from '../../../elements/image_cropper/Label'; import useConfigurableTable from '../../vouchers/hooks/useConfigurableTable'; import TableTopScroller from '../../../elements/tables/TableTopScroller'; +import useFilterNext from '../../../../modules/filter_next/useFilterNext'; +import { NumberParam, StringParam } from 'use-query-params'; export default function TransactionBulkTransactionsTable({ organization, @@ -40,11 +41,24 @@ export default function TransactionBulkTransactionsTable({ const [transactions, setTransactions] = useState>(null); const [perPageKey] = useState('transaction_bulks_transactions'); - const filter = useFilter({ - per_page: paginationService.getPerPage(perPageKey), - order_by: 'created_at', - order_dir: 'desc', - }); + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext<{ + per_page?: number; + order_by: string; + order_dir: string; + }>( + { + per_page: paginationService.getPerPage(perPageKey), + order_by: 'created_at', + order_dir: 'desc', + }, + { + queryParams: { + per_page: NumberParam, + order_by: StringParam, + order_dir: StringParam, + }, + }, + ); const { headElement, configsElement } = useConfigurableTable(transactionService.getBulkTransactionsColumns(), { filter, @@ -53,11 +67,11 @@ export default function TransactionBulkTransactionsTable({ const exportTransactions = useCallback(() => { transactionExporter.exportData(organization.id, { - ...filter.activeValues, + ...filterValuesActive, voucher_transaction_bulk_id: transactionBulk.id, per_page: null, }); - }, [organization.id, filter.activeValues, transactionBulk?.id, transactionExporter]); + }, [organization.id, filterValuesActive, transactionBulk?.id, transactionExporter]); const fetchTransactions = useCallback( (id: number) => { @@ -65,14 +79,14 @@ export default function TransactionBulkTransactionsTable({ transactionService .list(envData.client_type, organization.id, { - ...filter.activeValues, + ...filterValuesActive, voucher_transaction_bulk_id: id, }) .then((res) => setTransactions(res.data)) .catch(pushApiError) .finally(() => setProgress(100)); }, - [setProgress, transactionService, envData.client_type, organization.id, filter.activeValues, pushApiError], + [setProgress, transactionService, envData.client_type, organization.id, filterValuesActive, pushApiError], ); useEffect(() => { @@ -172,8 +186,8 @@ export default function TransactionBulkTransactionsTable({
diff --git a/react/src/dashboard/components/pages/transactions/Transactions.tsx b/react/src/dashboard/components/pages/transactions/Transactions.tsx index 3c229c9f3..b382f574e 100644 --- a/react/src/dashboard/components/pages/transactions/Transactions.tsx +++ b/react/src/dashboard/components/pages/transactions/Transactions.tsx @@ -1,4 +1,4 @@ -import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'react'; +import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import useActiveOrganization from '../../../hooks/useActiveOrganization'; import { useNavigateState } from '../../../modules/state_router/Router'; import Transaction from '../../../props/models/Transaction'; @@ -6,7 +6,6 @@ import useOpenModal from '../../../hooks/useOpenModal'; import useTransactionService from '../../../services/TransactionService'; import useSetProgress from '../../../hooks/useSetProgress'; import useEnvData from '../../../hooks/useEnvData'; -import useFilter from '../../../hooks/useFilter'; import useTransactionBulkService from '../../../services/TransactionBulkService'; import { PaginationData } from '../../../props/ApiResponses'; import { strLimit } from '../../../helpers/string'; @@ -41,6 +40,8 @@ import Label from '../../elements/image_cropper/Label'; import useConfirmDangerAction from '../../../hooks/useConfirmDangerAction'; import { Permission } from '../../../props/models/Organization'; import TransactionBulksCard from './elements/TransactionBulksCard'; +import useFilterNext from '../../../modules/filter_next/useFilterNext'; +import { createEnumParam, NumberParam, StringParam } from 'use-query-params'; export default function Transactions() { const envData = useEnvData(); @@ -109,10 +110,31 @@ export default function Transactions() { ]); const [viewType, setViewType] = useState(viewTypes[0]); + const prevViewType = useRef(null); const [paginatorTransactionsKey] = useState('transactions'); const [paginatorTransactionBulkKey] = useState('transaction_bulks'); - const filter = useFilter( + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext<{ + q: string; + state: string; + fund_id?: number; + fund_state?: string; + from?: string; + to?: string; + amount_min?: string; + amount_max?: string; + transfer_in_min?: string; + transfer_in_max?: string; + non_cancelable_from?: string; + non_cancelable_to?: string; + execution_date_from?: string; + execution_date_to?: string; + bulk_state?: string; + per_page?: number; + order_by?: string; + order_dir?: string; + page?: number; + }>( { q: '', state: states[0].key, @@ -133,7 +155,30 @@ export default function Transactions() { order_by: 'created_at', order_dir: 'desc', }, - ['q', 'amount_min', 'amount_max', 'transfer_in_min', 'transfer_in_max'], + { + queryParams: { + q: StringParam, + to: StringParam, + from: StringParam, + state: createEnumParam(['pending', 'success']), + fund_id: NumberParam, + fund_state: createEnumParam(['closed', 'active']), + amount_min: NumberParam, + amount_max: NumberParam, + transfer_in_min: NumberParam, + transfer_in_max: NumberParam, + non_cancelable_from: StringParam, + non_cancelable_to: StringParam, + execution_date_from: StringParam, + execution_date_to: StringParam, + bulk_state: createEnumParam(['draft', 'error', 'pending', 'accepted', 'rejected']), + order_by: StringParam, + order_dir: StringParam, + per_page: NumberParam, + page: NumberParam, + }, + throttledValues: ['q', 'amount_min', 'amount_max', 'transfer_in_min', 'transfer_in_max'], + }, ); const { headElement, configsElement } = useConfigurableTable(transactionService.getColumns(isSponsor, isProvider), { @@ -142,7 +187,19 @@ export default function Transactions() { sortableExclude: ['method', 'branch_name', 'branch_number', 'amount_extra'], }); - const bulkFilter = useFilter( + const [bulkFilterValues, bulkFilterValuesActive, bulkFilterUpdate, bulkFilter] = useFilterNext<{ + from?: string; + to?: string; + amount_min?: string; + amount_max?: string; + quantity_min?: string; + quantity_max?: string; + state?: string; + page?: number; + per_page?: number; + order_by?: string; + order_dir?: string; + }>( { from: null, to: null, @@ -155,7 +212,22 @@ export default function Transactions() { order_by: 'created_at', order_dir: 'desc', }, - ['q', 'amount_min', 'amount_max', 'quantity_min', 'quantity_max'], + { + queryParams: { + to: StringParam, + from: StringParam, + state: createEnumParam(['pending', 'success']), + amount_min: NumberParam, + amount_max: NumberParam, + quantity_min: NumberParam, + quantity_max: NumberParam, + order_by: StringParam, + order_dir: StringParam, + per_page: NumberParam, + page: NumberParam, + }, + throttledValues: ['amount_min', 'amount_max', 'quantity_min', 'quantity_max'], + }, ); const fetchFunds = useCallback( @@ -204,27 +276,27 @@ export default function Transactions() { setShow(false); transactionExporter.exportData(activeOrganization.id, { - ...filter.activeValues, + ...filterValuesActive, per_page: null, }); - }, [activeOrganization.id, filter.activeValues, setShow, transactionExporter]); + }, [activeOrganization.id, filterValuesActive, setShow, transactionExporter]); const exportTransactionBulks = useCallback(() => { setShowBulk(false); transactionBulkExporter.exportData(activeOrganization.id, { - ...bulkFilter.activeValues, + ...bulkFilterValuesActive, per_page: null, }); - }, [activeOrganization.id, bulkFilter.activeValues, setShowBulk, transactionBulkExporter]); + }, [activeOrganization.id, bulkFilterValuesActive, setShowBulk, transactionBulkExporter]); const updateHasPendingBulking = useCallback(() => { fetchTransactions({ - ...filter.activeValues, + ...filterValuesActive, pending_bulking: 1, per_page: 1, }).then((res) => setPendingBulkingMeta(res.data.meta)); - }, [fetchTransactions, filter.activeValues]); + }, [fetchTransactions, filterValuesActive]); const uploadTransactions = useCallback(() => { openModal((modal) => ( @@ -232,7 +304,7 @@ export default function Transactions() { modal={modal} organization={activeOrganization} onCreated={() => { - fetchTransactions(filter.activeValues).then((res) => setTransactions(res.data)); + fetchTransactions(filterValuesActive).then((res) => setTransactions(res.data)); if (isSponsor && activeOrganization?.has_bank_connection) { updateHasPendingBulking(); @@ -240,7 +312,7 @@ export default function Transactions() { }} /> )); - }, [activeOrganization, fetchTransactions, filter.activeValues, isSponsor, openModal, updateHasPendingBulking]); + }, [activeOrganization, fetchTransactions, filterValuesActive, isSponsor, openModal, updateHasPendingBulking]); const confirmBulkNow = useCallback(() => { const total = pendingBulkingMeta.total; @@ -266,7 +338,7 @@ export default function Transactions() { setProgress(0); transactionBulkService - .bulkNow(activeOrganization.id, filter.activeValues) + .bulkNow(activeOrganization.id, filterValuesActive) .then((res) => { const bulks = res.data.data; @@ -296,7 +368,7 @@ export default function Transactions() { }, [ activeOrganization.id, confirmBulkNow, - filter.activeValues, + filterValuesActive, navigateState, pushApiError, pushSuccess, @@ -308,9 +380,9 @@ export default function Transactions() { useEffect(() => { if (viewType.key === 'bulks') { - fetchTransactionBulks(bulkFilter.activeValues).then((res) => setTransactionBulks(res.data)); + fetchTransactionBulks(bulkFilterValuesActive).then((res) => setTransactionBulks(res.data)); } else { - fetchTransactions(filter.activeValues).then((res) => setTransactions(res.data)); + fetchTransactions(filterValuesActive).then((res) => setTransactions(res.data)); if (isSponsor && activeOrganization?.has_bank_connection) { updateHasPendingBulking(); @@ -320,8 +392,8 @@ export default function Transactions() { isSponsor, fetchTransactionBulks, fetchTransactions, - bulkFilter.activeValues, - filter.activeValues, + bulkFilterValuesActive, + filterValuesActive, viewType.key, activeOrganization?.has_bank_connection, updateHasPendingBulking, @@ -331,6 +403,18 @@ export default function Transactions() { fetchFunds({ per_page: 100 }).then((funds) => setFunds(funds)); }, [fetchFunds]); + useEffect(() => { + if (prevViewType.current === 'bulks') { + resetBulkFilters(); + } + + if (prevViewType.current === 'transactions') { + resetFilters(); + } + + prevViewType.current = viewType?.key; + }, [resetFilters, resetBulkFilters, viewType?.key]); + if ( (viewType.key === 'transactions' && !transactions) || (viewType.key === 'bulks' && !transactionBulks) || @@ -419,8 +503,8 @@ export default function Transactions() {
filter.update({ q: e.target.value })} + value={filterValues.q} + onChange={(e) => filterUpdate({ q: e.target.value })} data-dusk="tableTransactionSearch" placeholder={translate('transactions.labels.search')} /> @@ -433,8 +517,8 @@ export default function Transactions() { filter.update({ q: e.target.value })} + value={filterValues.q} + onChange={(e) => filterUpdate({ q: e.target.value })} placeholder={translate('transactions.labels.search')} /> @@ -446,9 +530,9 @@ export default function Transactions() { className="form-control" min={0} type="number" - value={filter.values.amount_min || ''} + value={filterValues.amount_min || ''} onChange={(e) => - filter.update({ + filterUpdate({ amount_min: e.target.value, }) } @@ -460,9 +544,9 @@ export default function Transactions() { className="form-control" min={0} type="number" - value={filter.values.amount_max || ''} + value={filterValues.amount_max || ''} onChange={(e) => - filter.update({ + filterUpdate({ amount_max: e.target.value, }) } @@ -477,9 +561,9 @@ export default function Transactions() { className="form-control" propKey={'key'} allowSearch={false} - value={filter.values.state} + value={filterValues.state} options={states} - onChange={(state: string) => filter.update({ state })} + onChange={(state: string) => filterUpdate({ state })} /> @@ -493,27 +577,28 @@ export default function Transactions() { allowSearch={false} options={[{ id: null, name: 'Selecteer fonds' }, ...funds]} dusk="fundSelect" - onChange={(fund_id: number) => filter.update({ fund_id })} + value={filterValues.fund_id} + onChange={(fund_id: number) => filterUpdate({ fund_id })} /> )} { - filter.update({ from: dateFormat(from) }); + filterUpdate({ from: dateFormat(from) }); }} /> { - filter.update({ to: dateFormat(to) }); + filterUpdate({ to: dateFormat(to) }); }} /> @@ -525,10 +610,10 @@ export default function Transactions() { className="form-control" min={0} type="number" - value={filter.values.transfer_in_min || ''} + value={filterValues.transfer_in_min || ''} onChange={(e) => { if (!e.target.value || parseInt(e.target.value) >= 0) { - filter.update({ transfer_in_min: e.target.value }); + filterUpdate({ transfer_in_min: e.target.value }); } }} placeholder={translate('transactions.labels.transfer_in_min')} @@ -539,10 +624,10 @@ export default function Transactions() { className="form-control" min={0} type="number" - value={filter.values.transfer_in_max || ''} + value={filterValues.transfer_in_max || ''} onChange={(e) => { if (!e.target.value || parseInt(e.target.value) <= 14) { - filter.update({ transfer_in_max: e.target.value }); + filterUpdate({ transfer_in_max: e.target.value }); } }} placeholder={translate('transactions.labels.transfer_in_max')} @@ -555,40 +640,40 @@ export default function Transactions() { { - filter.update({ non_cancelable_from: dateFormat(from) }); + filterUpdate({ non_cancelable_from: dateFormat(from) }); }} /> { - filter.update({ non_cancelable_to: dateFormat(to) }); + filterUpdate({ non_cancelable_to: dateFormat(to) }); }} /> { - filter.update({ execution_date_from: dateFormat(from) }); + filterUpdate({ execution_date_from: dateFormat(from) }); }} /> { - filter.update({ execution_date_to: dateFormat(to) }); + filterUpdate({ execution_date_to: dateFormat(to) }); }} /> @@ -598,9 +683,9 @@ export default function Transactions() { className="form-control" propKey={'key'} allowSearch={false} - value={filter.values.bulk_state} + value={filterValues.bulk_state} options={bulkStates} - onChange={(bulk_state: string) => filter.update({ bulk_state })} + onChange={(bulk_state: string) => filterUpdate({ bulk_state })} /> @@ -611,9 +696,9 @@ export default function Transactions() { className="form-control" propKey={'key'} allowSearch={false} - value={filter.values.fund_state} + value={filterValues.fund_state} options={fundStates} - onChange={(fund_state: string) => filter.update({ fund_state })} + onChange={(fund_state: string) => filterUpdate({ fund_state })} /> @@ -640,9 +725,9 @@ export default function Transactions() { className="form-control" min={0} type="number" - value={bulkFilter.values.amount_min || ''} + value={bulkFilterValues.amount_min || ''} onChange={(e) => - bulkFilter.update({ + bulkFilterUpdate({ amount_min: e.target.value, }) } @@ -654,9 +739,9 @@ export default function Transactions() { className="form-control" min={0} type="number" - value={bulkFilter.values.amount_max || ''} + value={bulkFilterValues.amount_max || ''} onChange={(e) => - bulkFilter.update({ + bulkFilterUpdate({ amount_max: e.target.value, }) } @@ -673,9 +758,9 @@ export default function Transactions() { className="form-control" min={0} type="number" - value={bulkFilter.values.quantity_min || ''} + value={bulkFilterValues.quantity_min || ''} onChange={(e) => - bulkFilter.update({ + bulkFilterUpdate({ quantity_min: e.target.value, }) } @@ -687,9 +772,9 @@ export default function Transactions() { className="form-control" min={0} type="number" - value={bulkFilter.values.quantity_max || ''} + value={bulkFilterValues.quantity_max || ''} onChange={(e) => - bulkFilter.update({ + bulkFilterUpdate({ quantity_max: e.target.value, }) } @@ -704,28 +789,28 @@ export default function Transactions() { className="form-control" propKey={'key'} allowSearch={false} - value={bulkFilter.values.state} + value={bulkFilterValues.state} options={bulkStates} - onChange={(state: string) => bulkFilter.update({ state })} + onChange={(state: string) => bulkFilterUpdate({ state })} /> { - bulkFilter.update({ from: dateFormat(from) }); + bulkFilterUpdate({ from: dateFormat(from) }); }} /> { - bulkFilter.update({ to: dateFormat(to) }); + bulkFilterUpdate({ to: dateFormat(to) }); }} /> @@ -1035,8 +1120,8 @@ export default function Transactions() { @@ -1065,8 +1150,8 @@ export default function Transactions() { diff --git a/react/src/dashboard/components/pages/vouchers-view/VouchersViewComponent.tsx b/react/src/dashboard/components/pages/vouchers-view/VouchersViewComponent.tsx index 71b68d94f..2701ba35f 100644 --- a/react/src/dashboard/components/pages/vouchers-view/VouchersViewComponent.tsx +++ b/react/src/dashboard/components/pages/vouchers-view/VouchersViewComponent.tsx @@ -22,7 +22,6 @@ import usePushDanger from '../../../hooks/usePushDanger'; import { ApiResponseSingle, ResponseError } from '../../../props/ApiResponses'; import VoucherRecordsCard from './elements/VoucherRecordsCard'; import VoucherTransactionsCard from './elements/VoucherTransactionsCard'; -import useFilter from '../../../hooks/useFilter'; import EventLogsTable from '../../elements/tables/EventLogsTable'; import ModalOrderPhysicalCard from '../../modals/ModalOrderPhysicalCard'; import useTranslate from '../../../hooks/useTranslate'; @@ -31,6 +30,7 @@ import usePushApiError from '../../../hooks/usePushApiError'; import Label from '../../elements/image_cropper/Label'; import { Permission } from '../../../props/models/Organization'; import VoucherReservationsCard from './elements/VoucherReservationsCard'; +import useFilterNext from '../../../modules/filter_next/useFilterNext'; export default function VouchersViewComponent() { const { id } = useParams(); @@ -70,7 +70,12 @@ export default function VouchersViewComponent() { ); }, [activeOrganization, fund?.state, voucher]); - const transactionsFilters = useFilter({ + const [, transactionsFilterValuesActive] = useFilterNext<{ + per_page?: number; + order_by: string; + order_dir: string; + voucher_id: number; + }>({ per_page: 20, order_by: 'created_at', order_dir: 'desc', @@ -630,7 +635,7 @@ export default function VouchersViewComponent() { diff --git a/react/src/dashboard/components/pages/vouchers-view/elements/VoucherRecordsCard.tsx b/react/src/dashboard/components/pages/vouchers-view/elements/VoucherRecordsCard.tsx index 012086613..74355a102 100644 --- a/react/src/dashboard/components/pages/vouchers-view/elements/VoucherRecordsCard.tsx +++ b/react/src/dashboard/components/pages/vouchers-view/elements/VoucherRecordsCard.tsx @@ -8,7 +8,6 @@ import useVoucherRecordService from '../../../../services/VoucherRecordService'; import { PaginationData } from '../../../../props/ApiResponses'; import VoucherRecord from '../../../../props/models/VoucherRecord'; import LoadingCard from '../../../elements/loading-card/LoadingCard'; -import useFilter from '../../../../hooks/useFilter'; import usePaginatorService from '../../../../modules/paginator/services/usePaginatorService'; import ModalDangerZone from '../../../modals/ModalDangerZone'; import usePushSuccess from '../../../../hooks/usePushSuccess'; @@ -21,6 +20,7 @@ import useConfigurableTable from '../../vouchers/hooks/useConfigurableTable'; import TableTopScroller from '../../../elements/tables/TableTopScroller'; import TableRowActions from '../../../elements/tables/TableRowActions'; import TableEmptyValue from '../../../elements/table-empty-value/TableEmptyValue'; +import useFilterNext from '../../../../modules/filter_next/useFilterNext'; export default function VoucherRecordsCard({ voucher, @@ -42,11 +42,16 @@ export default function VoucherRecordsCard({ const [paginatorKey] = useState('voucher-records'); const [records, setRecords] = useState>(null); - const filter = useFilter({ + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext<{ + q: string; + per_page?: number; + order_by?: string; + order_dir?: string; + }>({ q: '', + per_page: paginatorService.getPerPage(paginatorKey), order_by: 'created_at', order_dir: 'asc', - per_page: paginatorService.getPerPage(paginatorKey, 10), }); const { headElement, configsElement } = useConfigurableTable(voucherRecordService.getColumns(), { @@ -58,11 +63,11 @@ export default function VoucherRecordsCard({ setProgress(0); voucherRecordService - .list(organization.id, voucher.id, filter.activeValues) + .list(organization.id, voucher.id, filterValuesActive) .then((res) => setRecords(res.data)) .catch(pushApiError) .finally(() => setProgress(100)); - }, [filter.activeValues, organization.id, setProgress, voucher.id, voucherRecordService, pushApiError]); + }, [filterValuesActive, organization.id, setProgress, voucher.id, voucherRecordService, pushApiError]); const editRecord = useCallback( (record: VoucherRecord = null) => { @@ -127,9 +132,9 @@ export default function VoucherRecordsCard({ filter.update({ q: e.target.value })} + onChange={(e) => filterUpdate({ q: e.target.value })} />
{hasPermission(organization, Permission.MANAGE_VOUCHERS) && ( @@ -201,9 +206,9 @@ export default function VoucherRecordsCard({
)} diff --git a/react/src/dashboard/components/pages/vouchers-view/elements/VoucherTransactionsCard.tsx b/react/src/dashboard/components/pages/vouchers-view/elements/VoucherTransactionsCard.tsx index fac9ac43e..70c71190d 100644 --- a/react/src/dashboard/components/pages/vouchers-view/elements/VoucherTransactionsCard.tsx +++ b/react/src/dashboard/components/pages/vouchers-view/elements/VoucherTransactionsCard.tsx @@ -2,10 +2,8 @@ import Transaction from '../../../../props/models/Transaction'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import useEnvData from '../../../../hooks/useEnvData'; import Paginator from '../../../../modules/paginator/components/Paginator'; -import useFilter from '../../../../hooks/useFilter'; import { currencyFormat, strLimit } from '../../../../helpers/string'; import StateNavLink from '../../../../modules/state_router/StateNavLink'; -import FilterModel from '../../../../types/FilterModel'; import useTransactionService from '../../../../services/TransactionService'; import Organization from '../../../../props/models/Organization'; import { PaginationData } from '../../../../props/ApiResponses'; @@ -16,16 +14,18 @@ import Label from '../../../elements/image_cropper/Label'; import useConfigurableTable from '../../vouchers/hooks/useConfigurableTable'; import TableTopScroller from '../../../elements/tables/TableTopScroller'; import TableRowActions from '../../../elements/tables/TableRowActions'; +import useFilterNext from '../../../../modules/filter_next/useFilterNext'; +import { FilterModel } from '../../../../modules/filter_next/types/FilterParams'; export default function VoucherTransactionsCard({ blockTitle, organization, - filterValues, + filters, fetchTransactionsRef = null, }: { blockTitle: string; organization: Organization; - filterValues: FilterModel; + filters: FilterModel; fetchTransactionsRef?: React.MutableRefObject<() => void>; }) { const envData = useEnvData(); @@ -38,7 +38,7 @@ export default function VoucherTransactionsCard({ return envData.client_type == 'sponsor'; }, [envData.client_type]); - const filter = useFilter(filterValues); + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext(filters); const { headElement, configsElement } = useConfigurableTable(transactionService.getColumnsForVoucher(isSponsor), { filter, @@ -49,10 +49,10 @@ export default function VoucherTransactionsCard({ setProgress(100); transactionService - .list(envData.client_type, organization.id, filter.activeValues) + .list(envData.client_type, organization.id, filterValuesActive) .then((res) => setTransactions(res.data)) .finally(() => setProgress(100)); - }, [envData.client_type, filter.activeValues, organization.id, transactionService, setProgress]); + }, [envData.client_type, filterValuesActive, organization.id, transactionService, setProgress]); useEffect(() => { fetchTransactions(); @@ -164,7 +164,7 @@ export default function VoucherTransactionsCard({ ) : (
- +
)}
diff --git a/react/src/dashboard/components/pages/vouchers/elements/VouchersTableFilters.tsx b/react/src/dashboard/components/pages/vouchers/elements/VouchersTableFilters.tsx index 5f8a21cd9..317ba4c73 100644 --- a/react/src/dashboard/components/pages/vouchers/elements/VouchersTableFilters.tsx +++ b/react/src/dashboard/components/pages/vouchers/elements/VouchersTableFilters.tsx @@ -6,7 +6,6 @@ import ClickOutside from '../../../elements/click-outside/ClickOutside'; import FilterItemToggle from '../../../elements/tables/elements/FilterItemToggle'; import DatePickerControl from '../../../elements/forms/controls/DatePickerControl'; import { dateFormat, dateParse } from '../../../../helpers/dates'; -import FilterScope from '../../../../types/FilterScope'; import useTranslate from '../../../../hooks/useTranslate'; import useVoucherService from '../../../../services/VoucherService'; import useVoucherTableOptions from '../hooks/useVoucherTableOptions'; @@ -15,6 +14,7 @@ import { PaginationData } from '../../../../props/ApiResponses'; import SponsorVoucher from '../../../../props/models/Sponsor/SponsorVoucher'; import Fund from '../../../../props/models/Fund'; import { keyBy } from 'lodash'; +import { FilterScope } from '../../../../modules/filter_next/types/FilterParams'; export type VouchersTableFiltersProps = { q?: string; diff --git a/react/src/dashboard/i18n/nl/pages/extra-payments.js b/react/src/dashboard/i18n/nl/pages/extra-payments.js index f7be890ca..2224d5eed 100644 --- a/react/src/dashboard/i18n/nl/pages/extra-payments.js +++ b/react/src/dashboard/i18n/nl/pages/extra-payments.js @@ -13,7 +13,7 @@ export default { }, labels: { id: 'ID', - fund_name: 'Fonds', + fund: 'Fonds', product_name: 'Aanbod', provider_name: 'Aanbieder', price: 'Bedrag', diff --git a/react/src/dashboard/modules/paginator/components/Paginator.tsx b/react/src/dashboard/modules/paginator/components/Paginator.tsx index 26e007dda..777ae8645 100644 --- a/react/src/dashboard/modules/paginator/components/Paginator.tsx +++ b/react/src/dashboard/modules/paginator/components/Paginator.tsx @@ -1,6 +1,4 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import FilterModel from '../../../types/FilterModel'; -import FilterSetter from '../../../types/FilterSetter'; import { ApiPaginationMetaProp } from '../../../props/ApiResponses'; import usePaginatorService from '../services/usePaginatorService'; import SelectControl from '../../../components/elements/select-control/SelectControl'; @@ -8,6 +6,7 @@ import { clickOnKeyEnter } from '../../../helpers/wcag'; import useTranslate from '../../../hooks/useTranslate'; import classNames from 'classnames'; import useProgress from '../../../hooks/useProgress'; +import { FilterModel, FilterSetter } from '../../filter_next/types/FilterParams'; export default function Paginator({ meta, diff --git a/react/src/webshop/components/elements/top-navbar/TopNavbarSearch.tsx b/react/src/webshop/components/elements/top-navbar/TopNavbarSearch.tsx index 66ded11a1..1ff2367df 100644 --- a/react/src/webshop/components/elements/top-navbar/TopNavbarSearch.tsx +++ b/react/src/webshop/components/elements/top-navbar/TopNavbarSearch.tsx @@ -10,7 +10,6 @@ import { useSearchService, } from '../../../services/SearchService'; import useTranslate from '../../../../dashboard/hooks/useTranslate'; -import useFilter from '../../../../dashboard/hooks/useFilter'; import StateNavLink from '../../../modules/state_router/StateNavLink'; import IconSearchAll from '../../../../../assets/forus-webshop/resources/_webshop-common/assets/img/icon-search/all.svg'; import IconSearchFunds from '../../../../../assets/forus-webshop/resources/_webshop-common/assets/img/icon-search/funds.svg'; @@ -23,6 +22,7 @@ import { clickOnKeyEnter } from '../../../../dashboard/helpers/wcag'; import classNames from 'classnames'; import { ResponseError } from '../../../../dashboard/props/ApiResponses'; import usePushDanger from '../../../../dashboard/hooks/usePushDanger'; +import useFilterNext from '../../../../dashboard/modules/filter_next/useFilterNext'; export type SearchResultGroupLocal = SearchResultGroup & { shown?: boolean; @@ -61,11 +61,11 @@ export default function TopNavbarSearch({ autoFocus = false }: { autoFocus?: boo const [lastQuery, setLastQuery] = useState(''); - const filters = useFilter({ + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext<{ q: string }>({ q: '', }); - const { resetFilters } = filters; + const { resetFilters } = filter; const hideDropDown = useCallback(() => { setDropdown(false); @@ -120,9 +120,9 @@ export default function TopNavbarSearch({ autoFocus = false }: { autoFocus?: boo }, [setShowSearchBox, hideDropDown]); useEffect(() => { - setLastQuery(filters.activeValues.q); + setLastQuery(filterValuesActive.q); - if (!filters.activeValues.q || filters.activeValues.q?.length == 0) { + if (!filterValuesActive.q || filterValuesActive.q?.length == 0) { return clearSearch(); } @@ -130,7 +130,7 @@ export default function TopNavbarSearch({ autoFocus = false }: { autoFocus?: boo searchingForDropdown.current = true; searchService - .searchWithOverview({ q: filters.activeValues.q, with_external: 1, take: 9 }) + .searchWithOverview({ q: filterValuesActive.q, with_external: 1, take: 9 }) .then((res) => { updateResults(res.data.data); @@ -147,7 +147,7 @@ export default function TopNavbarSearch({ autoFocus = false }: { autoFocus?: boo searchingForDropdown.current = false; }); }, [ - filters.activeValues.q, + filterValuesActive.q, searchService, clearSearch, updateResults, @@ -173,7 +173,7 @@ export default function TopNavbarSearch({ autoFocus = false }: { autoFocus?: boo hideSearchDropdown.current = true; } - navigateState('search-result', {}, { q: filters.values.q }); + navigateState('search-result', {}, { q: filterValues.q }); document.querySelector('#main_search')?.focus(); }} className={`search-form form ${resultsAll?.length > 0 ? 'search-form-found' : ''}`}> @@ -199,18 +199,18 @@ export default function TopNavbarSearch({ autoFocus = false }: { autoFocus?: boo )} autoFocus={autoFocus} autoComplete={'off'} - value={filters.values.q} - onChange={(e) => filters.update({ q: e.target.value })} + value={filterValues.q} + onChange={(e) => filterUpdate({ q: e.target.value })} onKeyDown={cancelSearch} aria-labelledby="search-label" aria-haspopup={true} /> - {filters.values.q && ( + {filterValues.q && (
{ e?.stopPropagation(); - filters.update({ q: '' }); + filterUpdate({ q: '' }); inputRef?.current?.focus(); }} onKeyDown={(e) => { @@ -352,7 +352,7 @@ export default function TopNavbarSearch({ autoFocus = false }: { autoFocus?: boo params={{ id: value.id }} className="search-result-item"> diff --git a/react/src/webshop/components/pages/funds-pre-check/FundsPreCheck.tsx b/react/src/webshop/components/pages/funds-pre-check/FundsPreCheck.tsx index 835796037..ed936e49c 100644 --- a/react/src/webshop/components/pages/funds-pre-check/FundsPreCheck.tsx +++ b/react/src/webshop/components/pages/funds-pre-check/FundsPreCheck.tsx @@ -27,9 +27,9 @@ import UIControlNumber from '../../../../dashboard/components/elements/forms/ui- import UIControlText from '../../../../dashboard/components/elements/forms/ui-controls/UIControlText'; import EmptyBlock from '../../elements/empty-block/EmptyBlock'; import FundsListItemPreCheck from '../../elements/lists/funds-list/templates/FundsListItemPreCheck'; -import useFilter from '../../../../dashboard/hooks/useFilter'; import BlockShowcase from '../../elements/block-showcase/BlockShowcase'; import classNames from 'classnames'; +import useFilterNext from '../../../../dashboard/modules/filter_next/useFilterNext'; type PreCheckLocal = PreCheck<{ label?: string; @@ -70,7 +70,11 @@ export default function FundsPreCheck() { return recordTypes?.reduce((acc, type) => ({ ...acc, [type.key]: type }), {}); }, [recordTypes]); - const filter = useFilter({ + const [filterValues, filterValuesActive, filterUpdate] = useFilterNext<{ + q: string; + tag_id?: number; + organization_id?: number; + }>({ q: '', tag_id: null, organization_id: null, @@ -138,11 +142,11 @@ export default function FundsPreCheck() { setProgress(0); preCheckService - .calculateTotals({ ...filter.activeValues, records }) + .calculateTotals({ ...filterValuesActive, records }) .then((res) => setTotals(res.data)) .catch((res) => pushDanger(translate('push.error'), res.data.message)) .finally(() => setProgress(100)); - }, [setProgress, filter.activeValues, preCheckService, preChecks, pushDanger, translate]); + }, [setProgress, filterValuesActive, preCheckService, preChecks, pushDanger, translate]); const changeAnswers = useCallback(() => { setTotals(null); @@ -155,7 +159,7 @@ export default function FundsPreCheck() { setProgress(0); preCheckService - .downloadPDF({ ...filter.values, records }) + .downloadPDF({ ...filterValuesActive, records }) .then((res) => { pushSuccess(translate('push.success'), translate('push.pre_check.downloaded')); @@ -167,7 +171,7 @@ export default function FundsPreCheck() { }) .catch((err: ResponseError) => pushDanger(translate('push.error'), err.data.message)) .finally(() => setProgress(100)); - }, [fileService, filter.values, preCheckService, preChecks, pushDanger, pushSuccess, setProgress, translate]); + }, [fileService, filterValuesActive, preCheckService, preChecks, pushDanger, pushSuccess, setProgress, translate]); const prev = useCallback(() => { setActiveStepIndex(Math.max(activeStepIndex - 1, 0)); @@ -441,8 +445,8 @@ export default function FundsPreCheck() { {translate('funds.labels.search')} filter.update({ q })} + value={filterValues.q} + onChangeValue={(q) => filterUpdate({ q })} ariaLabel={translate('pre_check.search')} dataDusk="listFundsPreCheckSearch" /> @@ -455,10 +459,10 @@ export default function FundsPreCheck() { - filter.update({ organization_id }) + filterUpdate({ organization_id }) } multiline={true} dusk="selectControlOrganizations" @@ -472,8 +476,8 @@ export default function FundsPreCheck() { filter.update({ tag_id })} + value={filterValues.tag_id} + onChange={(tag_id: number) => filterUpdate({ tag_id })} options={tags} multiline={true} dusk="selectControlTags" diff --git a/react/src/webshop/components/pages/funds/Funds.tsx b/react/src/webshop/components/pages/funds/Funds.tsx index 3116fa5db..85c15b761 100644 --- a/react/src/webshop/components/pages/funds/Funds.tsx +++ b/react/src/webshop/components/pages/funds/Funds.tsx @@ -10,7 +10,6 @@ import Organization from '../../../../dashboard/props/models/Organization'; import SelectControl from '../../../../dashboard/components/elements/select-control/SelectControl'; import { useFundService } from '../../../services/FundService'; import { useTagService } from '../../../../dashboard/services/TagService'; -import useFilter from '../../../../dashboard/hooks/useFilter'; import { PaginationData } from '../../../../dashboard/props/ApiResponses'; import CmsBlocks from '../../elements/cms-blocks/CmsBlocks'; import EmptyBlock from '../../elements/empty-block/EmptyBlock'; @@ -25,6 +24,8 @@ import useSetProgress from '../../../../dashboard/hooks/useSetProgress'; import UIControlText from '../../../../dashboard/components/elements/forms/ui-controls/UIControlText'; import usePayoutTransactionService from '../../../services/PayoutTransactionService'; import PayoutTransaction from '../../../../dashboard/props/models/PayoutTransaction'; +import useFilterNext from '../../../../dashboard/modules/filter_next/useFilterNext'; +import { NumberParam, StringParam } from 'use-query-params'; export default function Funds() { const envData = useEnvData(); @@ -48,43 +49,62 @@ export default function Funds() { const [vouchers, setVouchers] = useState>(null); const [organizations, setOrganizations] = useState>>(null); - const filter = useFilter({ - q: '', - tag_id: null, - organization_id: null, - per_page: 10, - with_external: 1, - check_criteria: 1, - order_by: 'order', - order_dir: 'asc', - }); + const [filterValues, filterValuesActive, filterUpdate] = useFilterNext<{ + q: string; + tag_id?: number; + organization_id?: number; + page?: number; + per_page?: number; + order_by?: string; + order_dir?: string; + }>( + { + q: '', + tag_id: null, + organization_id: null, + per_page: 10, + order_by: 'order', + order_dir: 'asc', + }, + { + queryParams: { + q: StringParam, + tag_id: NumberParam, + organization_id: NumberParam, + page: NumberParam, + per_page: NumberParam, + order_by: StringParam, + order_dir: StringParam, + }, + }, + ); const countFiltersApplied = useMemo(() => { let count = 0; - if (filter.values.q) { + if (filterValues.q) { count++; } - if (filter.values.tag_id) { + if (filterValues.tag_id) { count++; } - if (filter.values.organization_id) { + if (filterValues.organization_id) { count++; } return count; - }, [filter.values.organization_id, filter.values.q, filter.values.tag_id]); + }, [filterValues.organization_id, filterValues.q, filterValues.tag_id]); const fetchFunds = useCallback(() => { setProgress(0); fundService - .list(filter.activeValues) + .list({ ...filterValuesActive, with_external: 1, check_criteria: 1 }) .then((res) => setFunds(res.data)) .finally(() => setProgress(100)); - }, [filter.activeValues, fundService, setProgress]); + }, [filterValuesActive, fundService, setProgress]); const fetchTags = useCallback(() => { setProgress(0); @@ -173,8 +193,8 @@ export default function Funds() { filter.update({ q })} + value={filterValues.q} + onChangeValue={(q) => filterUpdate({ q })} ariaLabel="Zoeken" dataDusk="listFundsSearch" /> @@ -186,9 +206,9 @@ export default function Funds() { filter.update({ organization_id })} + onChange={(organization_id: number) => filterUpdate({ organization_id })} options={organizations || []} multiline={true} ariaLabelledby="select_organization_label" @@ -202,9 +222,9 @@ export default function Funds() { filter.update({ tag_id })} + onChange={(tag_id: number) => filterUpdate({ tag_id })} options={tags || []} multiline={true} ariaLabelledby="select_category_label" @@ -255,9 +275,9 @@ export default function Funds() {
diff --git a/react/src/webshop/components/pages/identity-security/SecuritySessions.tsx b/react/src/webshop/components/pages/identity-security/SecuritySessions.tsx index d57af8fef..3a58db495 100644 --- a/react/src/webshop/components/pages/identity-security/SecuritySessions.tsx +++ b/react/src/webshop/components/pages/identity-security/SecuritySessions.tsx @@ -9,13 +9,13 @@ import { authContext } from '../../../contexts/AuthContext'; import { PaginationData, ResponseError } from '../../../../dashboard/props/ApiResponses'; import SessionModel from '../../../../dashboard/props/models/Session'; import { useSessionService } from '../../../../dashboard/services/SessionService'; -import useFilter from '../../../../dashboard/hooks/useFilter'; import { ModalState } from '../../../../dashboard/modules/modals/context/ModalContext'; import BlockShowcaseProfile from '../../elements/block-showcase/BlockShowcaseProfile'; import ModalNotification from '../../modals/ModalNotification'; import Auth2FARestriction from '../../../components/elements/auth2fa-restriction/Auth2FARestriction'; import { clickOnKeyEnter } from '../../../../dashboard/helpers/wcag'; import useTranslate from '../../../../dashboard/hooks/useTranslate'; +import useFilterNext from '../../../../dashboard/modules/filter_next/useFilterNext'; export default function SecuritySessions() { const openModal = useOpenModal(); @@ -29,7 +29,7 @@ export default function SecuritySessions() { const { signOut } = useContext(authContext); - const filter = useFilter({ per_page: 100 }); + const [, filterValuesActive] = useFilterNext<{ per_page?: number }>({ per_page: 100 }); const sessionService = useSessionService(); const [sessions, setSessions] = useState>(null); const [shownLocations, setShownLocations] = useState({}); @@ -51,10 +51,10 @@ export default function SecuritySessions() { setProgress(0); sessionService - .list(filter?.activeValues) + .list(filterValuesActive) .then((res) => setSessions(res.data)) .finally(() => setProgress(100)); - }, [setProgress, sessionService, filter?.activeValues]); + }, [setProgress, sessionService, filterValuesActive]); const findIcon = useCallback((session: SessionModel) => { const device = session.last_request.device?.device; diff --git a/react/src/webshop/components/pages/notifications/Notifications.tsx b/react/src/webshop/components/pages/notifications/Notifications.tsx index 8784f9fbf..f6d73ac93 100644 --- a/react/src/webshop/components/pages/notifications/Notifications.tsx +++ b/react/src/webshop/components/pages/notifications/Notifications.tsx @@ -4,11 +4,11 @@ import useSetProgress from '../../../../dashboard/hooks/useSetProgress'; import { useNotificationService } from '../../../../dashboard/services/NotificationService'; import { PaginationData } from '../../../../dashboard/props/ApiResponses'; import Notification from '../../../../dashboard/props/models/Notification'; -import useFilter from '../../../../dashboard/hooks/useFilter'; import EmptyBlock from '../../elements/empty-block/EmptyBlock'; import Paginator from '../../../../dashboard/modules/paginator/components/Paginator'; import BlockShowcaseProfile from '../../elements/block-showcase/BlockShowcaseProfile'; import classNames from 'classnames'; +import useFilterNext from '../../../../dashboard/modules/filter_next/useFilterNext'; export default function Notifications() { const translate = useTranslate(); @@ -19,23 +19,21 @@ export default function Notifications() { const [notifications, setNotifications] = useState>(null); const [timeoutThreshold] = useState(2500); - const filter = useFilter({ - per_page: 10, - }); + const [filterValues, filterValuesActive, filterUpdate] = useFilterNext<{ per_page?: number }>({ per_page: 10 }); const fetchNotifications = useCallback( (mark_read = false) => { setProgress(0); notificationsService - .list({ ...filter.activeValues, mark_read: mark_read ? 1 : 0 }) + .list({ ...filterValuesActive, mark_read: mark_read ? 1 : 0 }) .then((res) => { res.data.data = res.data.data.map((item) => ({ ...item, seen: item.seen || mark_read })); setNotifications(res.data); }) .finally(() => setProgress(100)); }, - [notificationsService, filter?.activeValues, setProgress], + [notificationsService, filterValuesActive, setProgress], ); useEffect(() => { @@ -124,11 +122,7 @@ export default function Notifications() { diff --git a/react/src/webshop/components/pages/products/elements/ProductsFilterGroupPrice.tsx b/react/src/webshop/components/pages/products/elements/ProductsFilterGroupPrice.tsx index 3c7441b77..e54811fa7 100644 --- a/react/src/webshop/components/pages/products/elements/ProductsFilterGroupPrice.tsx +++ b/react/src/webshop/components/pages/products/elements/ProductsFilterGroupPrice.tsx @@ -32,7 +32,7 @@ export default function ProductsFilterGroupPrice({ return ( ( diff --git a/react/src/webshop/components/pages/reimbursements/Reimbursements.tsx b/react/src/webshop/components/pages/reimbursements/Reimbursements.tsx index b13d1a28f..41aabc536 100644 --- a/react/src/webshop/components/pages/reimbursements/Reimbursements.tsx +++ b/react/src/webshop/components/pages/reimbursements/Reimbursements.tsx @@ -2,7 +2,6 @@ import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'reac import StateNavLink from '../../../modules/state_router/StateNavLink'; import useTranslate from '../../../../dashboard/hooks/useTranslate'; import Paginator from '../../../../dashboard/modules/paginator/components/Paginator'; -import useFilter from '../../../../dashboard/hooks/useFilter'; import useSetProgress from '../../../../dashboard/hooks/useSetProgress'; import { PaginationData } from '../../../../dashboard/props/ApiResponses'; import { useFundService } from '../../../services/FundService'; @@ -22,6 +21,8 @@ import IconReimbursement from '../../../../../assets/forus-webshop/resources/_we import Auth2FARestriction from '../../elements/auth2fa-restriction/Auth2FARestriction'; import { clickOnKeyEnter } from '../../../../dashboard/helpers/wcag'; import classNames from 'classnames'; +import useFilterNext from '../../../../dashboard/modules/filter_next/useFilterNext'; +import { createEnumParam, NumberParam, StringParam } from 'use-query-params'; export default function Reimbursements() { const envData = useEnvData(); @@ -40,11 +41,33 @@ export default function Reimbursements() { const [vouchers, setVouchers] = useState>(null); const [reimbursements, setReimbursements] = useState>(null); - const filters = useFilter({ - fund_id: null, - archived: 0, - state: 'all', - }); + const [filterValues, filterValuesActive, filterUpdate] = useFilterNext<{ + q: string; + state: string; + fund_id?: number; + archived: 0 | 1; + page?: number; + per_page?: number; + }>( + { + q: '', + state: 'all', + fund_id: null, + archived: 0, + page: 1, + per_page: 15, + }, + { + queryParams: { + q: StringParam, + state: StringParam, + fund_id: NumberParam, + archived: createEnumParam(['0', '1']), + page: NumberParam, + per_page: NumberParam, + }, + }, + ); const states = useMemo(() => { return [ @@ -79,16 +102,16 @@ export default function Reimbursements() { reimbursementService .list({ - ...filters.activeValues, - state: filters.activeValues.archived + ...filterValuesActive, + state: filterValuesActive.archived ? null - : filters.activeValues.state === 'all' + : filterValuesActive.state === 'all' ? null - : filters.activeValues.state, + : filterValuesActive.state, }) .then((res) => setReimbursements(res.data)) .finally(() => setProgress(100)); - }, [setProgress, reimbursementService, filters.activeValues]); + }, [setProgress, reimbursementService, filterValuesActive]); useEffect(() => { fetchFunds(); @@ -122,12 +145,12 @@ export default function Reimbursements() { filters.update({ fund_id })} + onChange={(fund_id?: number) => filterUpdate({ fund_id })} />
@@ -147,7 +170,7 @@ export default function Reimbursements() {
- {!filters.values.archived && ( + {!filterValues.archived && (
{states?.map((state) => (
filters.update({ state: state.key })} + onClick={() => filterUpdate({ state: state.key })} onKeyDown={clickOnKeyEnter} tabIndex={0} data-dusk={`reimbursementsFilterState${state.key}`} - aria-pressed={filters.values.state == state.key}> + aria-pressed={filterValues.state == state.key}> {state.name}
))} @@ -170,19 +193,19 @@ export default function Reimbursements() {
filters.update({ archived: 0 })} - aria-pressed={!filters.values.archived}> + onClick={() => filterUpdate({ archived: 0 })} + aria-pressed={!filterValues.archived}> {translate('reimbursements.types.active')}
filters.update({ archived: 1 })} + className={`label-tab label-tab-sm ${filterValues.archived ? 'active' : ''}`} + onClick={() => filterUpdate({ archived: 1 })} role="button" data-dusk="reimbursementsFilterArchived" - aria-pressed={!!filters.values.archived}> + aria-pressed={!!filterValues.archived}> {translate('reimbursements.types.archived')}
@@ -262,8 +285,8 @@ export default function Reimbursements() {
diff --git a/react/src/webshop/components/pages/reservations/Reservations.tsx b/react/src/webshop/components/pages/reservations/Reservations.tsx index 8ca43dada..0051373f8 100644 --- a/react/src/webshop/components/pages/reservations/Reservations.tsx +++ b/react/src/webshop/components/pages/reservations/Reservations.tsx @@ -6,7 +6,6 @@ import useSetProgress from '../../../../dashboard/hooks/useSetProgress'; import { useFundService } from '../../../services/FundService'; import Fund from '../../../props/models/Fund'; import { PaginationData } from '../../../../dashboard/props/ApiResponses'; -import useFilter from '../../../../dashboard/hooks/useFilter'; import Organization from '../../../../dashboard/props/models/Organization'; import { useOrganizationService } from '../../../../dashboard/services/OrganizationService'; import Reservation from '../../../../dashboard/props/models/Reservation'; @@ -15,6 +14,8 @@ import Paginator from '../../../../dashboard/modules/paginator/components/Pagina import ReservationCard from './elements/ReservationCard'; import { useProductReservationService } from '../../../services/ProductReservationService'; import UIControlText from '../../../../dashboard/components/elements/forms/ui-controls/UIControlText'; +import useFilterNext from '../../../../dashboard/modules/filter_next/useFilterNext'; +import { createEnumParam, NumberParam, StringParam } from 'use-query-params'; export default function Reservations() { const translate = useTranslate(); @@ -38,12 +39,36 @@ export default function Reservations() { ]; }, [translate]); - const filters = useFilter({ - state: 'all', - fund_id: null, - organization_id: null, - archived: 0, - }); + const [filterValues, filterValuesActive, filterUpdate] = useFilterNext<{ + q: string; + state: string; + fund_id?: number; + organization_id?: number; + archived: 0 | 1; + page?: number; + per_page?: number; + }>( + { + q: '', + state: 'all', + fund_id: null, + organization_id: null, + archived: 0, + page: 1, + per_page: 15, + }, + { + queryParams: { + q: StringParam, + state: StringParam, + fund_id: NumberParam, + organization_id: NumberParam, + archived: createEnumParam(['0', '1']), + page: NumberParam, + per_page: NumberParam, + }, + }, + ); const fetchFunds = useCallback(() => { setProgress(0); @@ -75,12 +100,12 @@ export default function Reservations() { productReservationService .list({ - ...filters.activeValues, - state: filters.activeValues?.state === 'all' ? null : filters.activeValues?.state, + ...filterValuesActive, + state: filterValuesActive?.state === 'all' ? null : filterValuesActive?.state, }) .then((res) => setReservations(res.data)) .finally(() => setProgress(100)); - }, [filters.activeValues, productReservationService, setProgress]); + }, [filterValuesActive, productReservationService, setProgress]); useEffect(() => { fetchFunds(); @@ -111,8 +136,8 @@ export default function Reservations() { filters.update({ q })} + value={filterValues.q} + onChangeValue={(q) => filterUpdate({ q })} dataDusk="listReservationsSearch" ariaLabel={translate('reservations.filters.search_aria_label')} /> @@ -125,12 +150,12 @@ export default function Reservations() { filters.update({ fund_id })} + onChange={(fund_id?: number) => filterUpdate({ fund_id })} />
@@ -140,10 +165,10 @@ export default function Reservations() { filters.update({ organization_id })} + onChange={(organization_id?: number) => filterUpdate({ organization_id })} multiline={true} allowSearch={true} dusk="selectControlOrganizations" @@ -156,10 +181,10 @@ export default function Reservations() { filters.update({ state })} + onChange={(state?: string) => filterUpdate({ state })} multiline={true} allowSearch={true} dusk="selectControlStates" @@ -184,17 +209,17 @@ export default function Reservations() {
filters.update({ archived: 0 })} - aria-pressed={!filters.values.archived} + className={`label-tab label-tab-sm ${!filterValues.archived ? 'active' : ''}`} + onClick={() => filterUpdate({ archived: 0 })} + aria-pressed={!filterValues.archived} data-dusk="reservationsFilterActive" role="button"> {translate('reservations.types.active')}
filters.update({ archived: 1 })} - aria-pressed={!!filters.values.archived} + className={`label-tab label-tab-sm ${filterValues.archived ? 'active' : ''}`} + onClick={() => filterUpdate({ archived: 1 })} + aria-pressed={!!filterValues.archived} data-dusk="reservationsFilterArchived" role="button"> {translate('reservations.types.archived')} @@ -234,11 +259,7 @@ export default function Reservations() { diff --git a/react/src/webshop/components/pages/vouchers/Vouchers.tsx b/react/src/webshop/components/pages/vouchers/Vouchers.tsx index 202a9d145..5d31f3fa5 100644 --- a/react/src/webshop/components/pages/vouchers/Vouchers.tsx +++ b/react/src/webshop/components/pages/vouchers/Vouchers.tsx @@ -2,7 +2,6 @@ import React, { Fragment, useCallback, useEffect, useState } from 'react'; import BlockShowcaseProfile from '../../elements/block-showcase/BlockShowcaseProfile'; import StateNavLink from '../../../modules/state_router/StateNavLink'; import useTranslate from '../../../../dashboard/hooks/useTranslate'; -import useFilter from '../../../../dashboard/hooks/useFilter'; import IconReimbursement from '../../../../../assets/forus-webshop/resources/_webshop-common/assets/img/icon-reimbursement.svg'; import Paginator from '../../../../dashboard/modules/paginator/components/Paginator'; import EmptyBlock from '../../elements/empty-block/EmptyBlock'; @@ -14,6 +13,8 @@ import useSetProgress from '../../../../dashboard/hooks/useSetProgress'; import VoucherCard from './elements/VoucherCard'; import useEnvData from '../../../hooks/useEnvData'; import { clickOnKeyEnter } from '../../../../dashboard/helpers/wcag'; +import useFilterNext from '../../../../dashboard/modules/filter_next/useFilterNext'; +import { createEnumParam, NumberParam, StringParam } from 'use-query-params'; export default function Vouchers() { const envData = useEnvData(); @@ -27,23 +28,39 @@ export default function Vouchers() { const [vouchers, setVouchers] = useState>(null); const [reimbursementVouchers, setReimbursementVouchers] = useState>(null); - const filter = useFilter<{ + const [filterValues, filterValuesActive, filterUpdate] = useFilterNext<{ archived: 0 | 1; - }>({ - per_page: 15, - archived: 0, - order_by: 'voucher_type', - order_dir: 'desc', - }); + page?: number; + per_page?: number; + order_by?: string; + order_dir?: string; + }>( + { + page: 1, + per_page: 15, + archived: 0, + order_by: 'voucher_type', + order_dir: 'desc', + }, + { + queryParams: { + archived: createEnumParam(['0', '1']), + page: NumberParam, + per_page: NumberParam, + order_by: StringParam, + order_dir: StringParam, + }, + }, + ); const fetchVouchers = useCallback(() => { setProgress(0); voucherService - .list(filter.activeValues) + .list(filterValuesActive) .then((res) => setVouchers(res.data)) .finally(() => setProgress(100)); - }, [filter.activeValues, setProgress, voucherService]); + }, [filterValuesActive, setProgress, voucherService]); const fetchReimbursementVouchers = useCallback(() => { setProgress(0); @@ -86,21 +103,21 @@ export default function Vouchers() {
filter.update({ archived: 0 })} + className={`label-tab label-tab-sm ${filterValues.archived ? '' : 'active'}`} + onClick={() => filterUpdate({ archived: 0 })} onKeyDown={clickOnKeyEnter} tabIndex={0} - aria-pressed={!filter.values.archived} + aria-pressed={!filterValues.archived} data-dusk="vouchersFilterActive" role="button"> {translate('vouchers.filters.active')}
filter.update({ archived: 1 })} + className={`label-tab label-tab-sm ${filterValues.archived ? 'active' : ''}`} + onClick={() => filterUpdate({ archived: 1 })} onKeyDown={clickOnKeyEnter} tabIndex={0} - aria-pressed={!!filter.values.archived} + aria-pressed={!!filterValues.archived} data-dusk="vouchersFilterArchived" role="button"> {translate('vouchers.filters.archive')} @@ -126,8 +143,8 @@ export default function Vouchers() {
diff --git a/react/src/webshop/i18n/nl/pages/products.mjs b/react/src/webshop/i18n/nl/pages/products.mjs index 3261644ba..c43fe3e6b 100644 --- a/react/src/webshop/i18n/nl/pages/products.mjs +++ b/react/src/webshop/i18n/nl/pages/products.mjs @@ -14,10 +14,10 @@ export default { postcode: 'Postcode', distance: 'Afstand', price_from: 'Van', - price_to: 'Naar', + price_to: 'Tot', price: 'Prijs (€)', - payment_options: 'Betalingsmogelijkheden', - payment_options_info: 'Lees meer over de betalingsopties', + payment_options: 'Betaalopties', + payment_options_info: 'Lees meer over de betaalopties', payment_option_qr: 'QR-code tonen bij de aanbieder', payment_option_reservation: 'Online reserveren', payment_option_extra_payment: 'Online bijbetalen met iDeal',