diff --git a/src/components/BarcodeScannerDialog.vue b/src/components/BarcodeScannerDialog.vue
index 4e96fdae5a9..7baa7d9830d 100644
--- a/src/components/BarcodeScannerDialog.vue
+++ b/src/components/BarcodeScannerDialog.vue
@@ -46,7 +46,7 @@
persistent-hint
>
-
+
diff --git a/src/components/ChallengeTakePicturesCard.vue b/src/components/ChallengeTakePicturesCard.vue
new file mode 100644
index 00000000000..de8abbe785b
--- /dev/null
+++ b/src/components/ChallengeTakePicturesCard.vue
@@ -0,0 +1,40 @@
+
+
+
+ {{ $t('Challenge.StepTakePictures.Title') }}
+
+
+
+ {{ $t('Challenge.StepTakePictures.line1') }}
+
+
+
+ {{ $t('Challenge.StepTakePictures.line2') }}
+
+
+
+
+
+
+ {{ $t('Challenge.StepTakePictures.AddPictures') }}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/ChallengeTimeline.vue b/src/components/ChallengeTimeline.vue
new file mode 100644
index 00000000000..4260dc0e0a0
--- /dev/null
+++ b/src/components/ChallengeTimeline.vue
@@ -0,0 +1,58 @@
+
+
+
+
+ Start
+
+
+ {{ challenge.startDate }}
+
+
+
+
+
+ End
+
+
+ {{ challenge.endDate }}
+
+
+
+ {{ daysLeftText }}
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/ChallengeValidateCard.vue b/src/components/ChallengeValidateCard.vue
new file mode 100644
index 00000000000..3a995c9ae30
--- /dev/null
+++ b/src/components/ChallengeValidateCard.vue
@@ -0,0 +1,35 @@
+
+
+
+ {{ $t('Challenge.StepValidate.Title') }}
+
+
+
+ {{ $t('Challenge.StepValidate.line1') }}
+
+
+ {{ $t('Challenge.StepValidate.line2') }}
+
+
+ {{ $t('Challenge.StepValidate.line3') }}
+
+
+ {{ $t('Challenge.StepValidate.line4') }}
+
+
+
+
+
+
+ {{ $t('Challenge.StepValidate.ValidatePrices') }}
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/ContributionAssistantPriceFormCard.vue b/src/components/ContributionAssistantPriceFormCard.vue
index 4307eb1cf30..135cc37e417 100644
--- a/src/components/ContributionAssistantPriceFormCard.vue
+++ b/src/components/ContributionAssistantPriceFormCard.vue
@@ -41,7 +41,7 @@
diff --git a/src/components/Header.vue b/src/components/Header.vue
index ebada306470..0028c201961 100644
--- a/src/components/Header.vue
+++ b/src/components/Header.vue
@@ -12,8 +12,8 @@
{{ $t('Common.Search') }}
-
-
+
+
{{ $t('Common.AddPrices') }}
@@ -38,7 +38,6 @@
:slim="true"
:title="item.title"
:prepend-icon="item.props['prepend-icon']"
- :base-color="item.props['base-color']"
:to="item.props.to"
/>
@@ -74,7 +73,7 @@ export default {
.filter(r => r.meta && r.meta.drawerMenu)
.filter(r => this.username ? r.meta.requiresAuth !== false : !r.meta.requiresAuth)
.filter(r => !r.meta.drawerMenuConditionalDisplay || this.appStore.user[r.meta.drawerMenuConditionalDisplay])
- .map((r => ({ title: this.$t(`Router.${r.meta.title}.Title`), props: { 'prepend-icon': r.meta.icon, 'base-color': r.meta.color, to: r.path }})))
+ .map((r => ({ title: this.$t(`Router.${r.meta.title}.Title`), props: { 'prepend-icon': r.meta.icon, to: r.path }})))
}
},
methods: {
diff --git a/src/components/LocationSelectorDialog.vue b/src/components/LocationSelectorDialog.vue
index 49624b3afa7..2fb3a549d7d 100644
--- a/src/components/LocationSelectorDialog.vue
+++ b/src/components/LocationSelectorDialog.vue
@@ -46,7 +46,7 @@
persistent-hint
>
-
+
@@ -106,7 +106,7 @@
persistent-hint
>
-
+
diff --git a/src/components/PriceDeleteConfirmationDialog.vue b/src/components/PriceDeleteConfirmationDialog.vue
index 860f1afd675..51d88253e7b 100644
--- a/src/components/PriceDeleteConfirmationDialog.vue
+++ b/src/components/PriceDeleteConfirmationDialog.vue
@@ -21,10 +21,11 @@
+
+
diff --git a/src/components/ProofDeleteConfirmationDialog.vue b/src/components/ProofDeleteConfirmationDialog.vue
index d28d1ca8eec..f2cc9aca3fe 100644
--- a/src/components/ProofDeleteConfirmationDialog.vue
+++ b/src/components/ProofDeleteConfirmationDialog.vue
@@ -17,10 +17,11 @@
+
+
-
+
import('./views/UserSettings.vue'), meta: { title: 'Settings', requiresAuth: true, breadcrumbs: [{title: 'Settings', disabled: true }] } }, // not used anymore
{ path: '/prices/add', name: 'add-price', component: () => import('./views/PriceAddHome.vue'), meta: { title: 'AddPrice', requiresAuth: true, breadcrumbs: [{title: 'AddPrice', disabled: true }] }}, // not used anymore
{ path: '/prices/add/single', name: 'price-add-single', component: () => import('./views/PriceAddSingle.vue'), meta: { title: 'Add a single price (price tag)', icon: 'mdi-tag-plus-outline', requiresAuth: true, breadcrumbs: [{title: 'Experiments', disabled: false, to: '/experiments' }, {title: 'PriceAddSingle', disabled: true }] }},
- { path: '/prices/add/multiple', name: 'price-add-multiple', component: () => import('./views/PriceAddMultiple.vue'), meta: { title: 'AddPrices', icon: 'mdi-tag-plus-outline', drawerMenu: true, color: 'primary', requiresAuth: true, breadcrumbs: [{title: 'AddPrices', disabled: true }] }},
+ { path: '/prices/add/multiple', name: 'price-add-multiple', component: () => import('./views/PriceAddMultiple.vue'), meta: { title: 'AddPrices', icon: 'mdi-tag-plus-outline', drawerMenu: true, requiresAuth: true, breadcrumbs: [{title: 'AddPrices', disabled: true }] }},
{ path: '/prices/add/multiple/price-tag', name: 'price-add-multiple-price-tag', redirect: () => { return { path: '/prices/add/multiple' }}},
{ path: '/prices/add/multiple/receipt', name: 'price-add-multiple-receipt', redirect: () => { return { path: '/prices/add/multiple' }}},
{ path: '/proofs/add/single', name: 'proof-add-single', component: () => import('./views/ProofAddSingle.vue'), meta: { title: 'AddProofSingle', icon: 'mdi-image-plus', requiresAuth: true, breadcrumbs: [{title: 'Experiments', disabled: false, to: '/experiments' }, {title: 'AddProofSingle', disabled: true }] }},
- { path: '/proofs/add/multiple', name: 'proof-add-multiple', component: () => import('./views/ProofAddMultiple.vue'), meta: { title: 'AddProofs', icon: 'mdi-image-plus', drawerMenu: true, color: 'primary', requiresAuth: true, breadcrumbs: [{title: 'AddProofs', disabled: true }] }},
+ { path: '/proofs/add/multiple', name: 'proof-add-multiple', component: () => import('./views/ProofAddMultiple.vue'), meta: { title: 'AddProofs', icon: 'mdi-image-plus', drawerMenu: true, requiresAuth: true, breadcrumbs: [{title: 'AddProofs', disabled: true }] }},
{ path: '/search', name: 'search', component: () => import('./views/Search.vue'), meta: { title: 'Search', icon: 'mdi-magnify', drawerMenu: true, breadcrumbs: [{title: 'Search', disabled: true }] }},
{ path: '/prices/:id', name: 'prices-detail', component: () => import('./views/PriceDetail.vue'), meta: { title: 'Price detail' }},
{ path: '/prices', name: 'prices', component: () => import('./views/PriceList.vue'), meta: { title: 'LatestPrices', icon: 'mdi-tag-multiple-outline', drawerMenu: true, breadcrumbs: [{title: 'LatestPrices', disabled: true }] }},
@@ -45,6 +45,7 @@ const routes = [
{ path: '/stats', name: 'stats', component: () => import('./views/Stats.vue'), meta: { title: 'Stats', icon: 'mdi-chart-box-outline', drawerMenu: true, breadcrumbs: [{title: 'Stats', disabled: true }] }},
{ path: '/settings', name: 'settings', component: () => import('./views/Settings.vue'), meta: { title: 'Settings', icon: 'mdi-cog-outline', drawerMenu: true, breadcrumbs: [{title: 'Settings', disabled: true }] }},
{ path: '/about', name: 'about', component: () => import('./views/About.vue'), meta: { title: 'About', icon: 'mdi-information-outline', drawerMenu: true, breadcrumbs: [{title: 'About', disabled: true }] }},
+ { path: '/experiments/challenge', name: 'challenge', component: () => import('./views/CurrentChallenge.vue'), meta: { title: 'Community Challenge', icon: 'mdi-medal-outline', breadcrumbs: [{title: 'Experiments', disabled: false, to: '/experiments' }, {title: 'Challenge', disabled: true }] }},
// Why this redirect?
// The app used to be available at https://prices.openfoodfacts.org/app
// It is now available at https://prices.openfoodfacts.org
diff --git a/src/services/api.js b/src/services/api.js
index 2af79fac1d6..390570ea92c 100644
--- a/src/services/api.js
+++ b/src/services/api.js
@@ -321,6 +321,15 @@ export default {
.then((response) => response.json())
},
+ getPriceStats(params = {}) {
+ const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/prices/stats?${buildURLParams({...params})}`
+ return fetch(url, {
+ method: 'GET',
+ headers: OP_DEFAULT_HEADERS,
+ })
+ .then((response) => response.json())
+ },
+
openfoodfactsProductSearch(code) {
const url = `${constants.OFF_API_URL}/${code}.json`
return fetch(url, {
diff --git a/src/views/ContributionAssistant.vue b/src/views/ContributionAssistant.vue
index 7d08d35e0ab..211748b582e 100644
--- a/src/views/ContributionAssistant.vue
+++ b/src/views/ContributionAssistant.vue
@@ -61,7 +61,7 @@
{{ $t('ContributionAssistant.LabelsExtractionSteps.SendLabels') }}
-
+
{{ $t('ContributionAssistant.LabelsExtractionSteps.SendLabelsButton') }}
@@ -106,7 +106,7 @@
{{ $t('ContributionAssistant.PriceAddConfirmationMessage', { numberOfPricesAdded: productPriceFormsWithoutPriceId.length, date: proofObject.date, locationName: locationName }) }}
-
+
{{ $t('Common.UploadMultiplePrices', productPriceFormsWithoutPriceId.length) }}
@@ -129,16 +129,16 @@
>
{{ $t('ContributionAssistant.PriceAddProgress', { numberOfPricesAdded: numberOfPricesAdded, totalNumberOfPrices: productPriceFormsWithoutPriceId.length }) }}
-
+
{{ $t('ContributionAssistant.GoToDashboard') }}
-
+
{{ $t('ContributionAssistant.GoToProof') }}
-
+
{{ $t('ContributionAssistant.AddNewProof') }}
-
+
{{ $t('ContributionAssistant.NextProof') }}
diff --git a/src/views/CurrentChallenge.vue b/src/views/CurrentChallenge.vue
new file mode 100644
index 00000000000..d1f82fd8abf
--- /dev/null
+++ b/src/views/CurrentChallenge.vue
@@ -0,0 +1,150 @@
+
+
+ {{ $t('Challenge.Title') }} {{ challenge.icon }} {{ challenge.title }} {{ challenge.icon }}
+
+
+
+
+
+ {{ $t('Challenge.Subtitle', {challenge_title: challenge.title, challenge_subtitle: challenge.subtitle}) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('Challenge.Stats') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('Challenge.MyStats') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('Challenge.MostRecentContributions') }}
+
+
+
+
+
+
+
+
+
diff --git a/src/views/Experiments.vue b/src/views/Experiments.vue
index 69ad7b5acf8..9f507b84cc8 100644
--- a/src/views/Experiments.vue
+++ b/src/views/Experiments.vue
@@ -21,6 +21,13 @@
to="/experiments/price-validation-assistant"
/>
+
+
+
diff --git a/src/views/PriceAddMultiple.vue b/src/views/PriceAddMultiple.vue
index 87953f7c0c4..f8d1b047f83 100644
--- a/src/views/PriceAddMultiple.vue
+++ b/src/views/PriceAddMultiple.vue
@@ -75,7 +75,7 @@
-
+
-
+
{{ $t('Common.AddNewPrices') }}
-
+
diff --git a/src/views/PriceAddSingle.vue b/src/views/PriceAddSingle.vue
index 822c3f868cc..a9f2fb31bff 100644
--- a/src/views/PriceAddSingle.vue
+++ b/src/views/PriceAddSingle.vue
@@ -48,7 +48,7 @@
diff --git a/src/views/ProofAddMultiple.vue b/src/views/ProofAddMultiple.vue
index 2b2634338ce..09b3a473b68 100644
--- a/src/views/ProofAddMultiple.vue
+++ b/src/views/ProofAddMultiple.vue
@@ -28,32 +28,32 @@
-
+
-
+
{{ $t('Common.AddNewProofs') }}
-
+
{{ $t('Common.ValidatePrices') }} 🤖
-
+
@@ -76,7 +76,7 @@ export default {
},
data() {
return {
- step: 1,
+ step: 2,
stepItemList: [
{
title: this.$t('Common.Upload'),
diff --git a/src/views/ProofAddSingle.vue b/src/views/ProofAddSingle.vue
index 918c8cd8540..0d97fd64f73 100644
--- a/src/views/ProofAddSingle.vue
+++ b/src/views/ProofAddSingle.vue
@@ -24,22 +24,22 @@
prepend-icon="mdi-image-check"
>
-
+
-
+
{{ $t('Common.AddNewProof') }}
-
+
diff --git a/src/views/Search.vue b/src/views/Search.vue
index df3f5590c20..c5f4a8a2ff5 100644
--- a/src/views/Search.vue
+++ b/src/views/Search.vue
@@ -18,7 +18,7 @@
-
+
diff --git a/src/views/Settings.vue b/src/views/Settings.vue
index 4e1ad5a510e..c580e3d4d8f 100644
--- a/src/views/Settings.vue
+++ b/src/views/Settings.vue
@@ -10,7 +10,7 @@
-
+
{{ $t('UserSettings.Save') }}