import featureAPI from '@/services/feature-api'; import { isNil } from 'lodash'; export function formatStringDate(stringDate) { const date = new Date(stringDate); if (date instanceof Date && !isNaN(date.valueOf())) { const formatted_date = date.getFullYear() + '/' + ('0' + (date.getMonth() + 1)).slice(-2) + '/' + ('0' + date.getDate()).slice(-2) + ' ' + ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2); return formatted_date; } return stringDate; } export const statusChoices = [ { name: 'Brouillon', value: 'draft', }, { name: 'En attente de publication', value: 'pending', }, { name: 'Publié', value: 'published', }, { name: 'Archivé', value: 'archived', }, ]; export function allowedStatus2change(user, isModerate, userStatus, isOwnFeature, currentRouteName) { if ( //* si 'super-admin'(superuser) admin, modérateur ou super contributeur, statuts toujours disponibles: Brouillon, Publié, Archivé user.is_superuser || userStatus === 'Modérateur' || userStatus === 'Administrateur projet' || (userStatus === 'Super Contributeur' && !isModerate) ) { return statusChoices.filter((el) => el.value !== 'pending'); } else if (userStatus === 'Super Contributeur' && isModerate) { return statusChoices.filter( (el) => el.value === 'draft' || el.value === 'pending' ); } else if (userStatus === 'Contributeur') { //* cas particuliers du contributeur if (currentRouteName === 'ajouter-signalement' || !isOwnFeature) { //* même cas à l'ajout d'une feature ou si feature n'a pas été créé par le contributeur return isModerate ? statusChoices.filter( (el) => el.value === 'draft' || el.value === 'pending' ) : statusChoices.filter( (el) => el.value === 'draft' || el.value === 'published' ); } else { //* à l'édition d'une feature et si le contributeur est l'auteur de la feature return isModerate ? statusChoices.filter( (el) => el.value !== 'published' //* toutes sauf "Publié" ) : statusChoices.filter( (el) => el.value !== 'pending' //* toutes sauf "En cours de publication" ); } } return []; } export function transformProperties(prop) { const type = typeof prop; const date = new Date(prop); const regInteger = /^-*?\d+$/; const regFloat = /^-*?\d*?\.\d+$/; const regText = /[\r\n]/; if (type === 'boolean' || (type === 'string' && (prop.toLowerCase() === 'true' || prop.toLowerCase() === 'False'))) { return 'boolean'; } else if ((regInteger.test(prop) || Number.isSafeInteger(prop)) && prop !== 0) { // in case the value is 0, since it can be either float or integer, do not set to integer https://redmine.neogeo.fr/issues/16934 return 'integer'; } else if ( type === 'string' && ['/', ':', '-'].some((el) => prop.includes(el)) && // check for chars found in datestring date instanceof Date && !isNaN(date.valueOf()) ) { return 'date'; } else if (regFloat.test(prop) || type === 'number' && !isNaN(parseFloat(prop)) || prop === 0) { // in case the value is 0, since it can be either float or integer, by default set as a float return 'decimal'; } else if (regText.test(prop)) { return 'text'; } return 'char'; //* string by default, most accepted type in database } export function objIsEmpty(obj) { for(const prop in obj) { if(Object.hasOwn(obj, prop)) { return false; } } return true; } export const reservedKeywords = [ // todo : add keywords for mapstyle (strokewidth...) 'id', 'title', 'description', 'status', 'created_on', 'updated_on', 'archived_on', 'deletion_on', 'feature_type', 'feature_id', 'display_creator', 'display_last_editor', 'project', 'creator', 'lat', 'lon' ]; export const customFieldTypeChoices = [ { name: 'Booléen', value: 'boolean' }, { name: 'Chaîne de caractères', value: 'char' }, { name: 'Date', value: 'date' }, { name: 'Liste de valeurs', value: 'list' }, { name: 'Liste de valeurs pré-enregistrées', value: 'pre_recorded_list' }, { name: 'Liste à choix multiples', value: 'multi_choices_list' }, { name: 'Nombre entier', value: 'integer' }, { name: 'Nombre décimal', value: 'decimal' }, { name: 'Texte multiligne', value: 'text' }, ]; export const featureNativeFields = [ { name: 'status', label: 'Statut', field_type: 'Champ GéoContrib' }, { name: 'feature_type', label: 'Type', field_type: 'Champ GéoContrib' }, { name: 'updated_on', label: 'Dernière mise à jour', field_type: 'Champ GéoContrib' }, { name: 'created_on', label: 'Date de création', field_type: 'Champ GéoContrib' }, { name: 'display_creator', label: 'Auteur', field_type: 'Champ GéoContrib' }, { name: 'display_last_editor', label: 'Dernier éditeur', field_type: 'Champ GéoContrib' }, ]; export const formatDate = (current_datetime) => { let formatted_date = current_datetime.getFullYear() + '-' + ('0' + (current_datetime.getMonth() + 1)).slice(-2) + '-' + ('0' + current_datetime.getDate()).slice(-2) + ' ' + ('0' + current_datetime.getHours()).slice(-2) + ':' + ('0' + current_datetime.getMinutes()).slice(-2); return formatted_date; }; export const retrieveFeatureProperties = async (feature, featureTypes, projectSlug) => { const properties = feature.getProperties(); let { feature_type, status, updated_on, created_on, creator, display_last_editor, index } = properties; if (creator) { creator = creator.full_name ? `${creator.first_name} ${creator.last_name}` : creator.username; } else if (properties.feature_id) { //* if *** MVT *** feature, retrieve display_creator and display_last_editor by fetching the feature details from API const fetchedFeature = await featureAPI.getProjectFeature(projectSlug, properties.feature_id); if (fetchedFeature) { creator = fetchedFeature.properties.display_creator; display_last_editor = fetchedFeature.properties.display_last_editor; feature_type = fetchedFeature.properties.feature_type; } } if (featureTypes && feature_type) { feature_type = featureTypes.find((el) => el.slug === (feature_type.slug || feature_type)); } if (updated_on && !isNaN(new Date(updated_on))) { //* check if date is already formatted updated_on = formatDate(new Date(updated_on)); } if (created_on && !isNaN(new Date(created_on))) { //* check if date is already formatted created_on = formatDate(new Date(created_on)); } if (status) { if (status.label) { //* when the label is already in the feature status = status.label; } else if (featureTypes) { //* if not, retrieve the name/label from the list status = statusChoices.find((el) => el.value === status).name; } } return { feature_type, status, updated_on, created_on, creator, display_last_editor, index }; }; export function findXformValue(feature, customField) { if (!feature) return null; if (feature.properties) { return feature.properties[customField.name] || null; } else if (feature.feature_data) { const field = feature.feature_data.find((el) => el.label === customField.label); return field ? field.value : null; } return null; } export function isXtraFormActive(extraForms, config) { // return true if no config or if the condition is fullfilled if (config) { // if conditional field configuration is not null // get name and value in condition const { conditionField, conditionValue } = config; // get the customForm which activates conditional field const conditioningXForm = extraForms.find((xForm) => xForm.name === conditionField); // check if the conditioning extraform value match the condition value if (conditioningXForm) { // if the values to compare are null or undefined the field can't be activated if (isNil(conditioningXForm.value) || isNil(conditionValue)) { return false; } else if (Array.isArray(conditionValue) && Array.isArray(conditioningXForm.value)) { // case of multiple list or prerecorded values list return conditioningXForm.value.some((value) => conditionValue.includes(value)); } else if (typeof conditioningXForm.value === 'object' && conditioningXForm.value.label) { // case of simple list return conditioningXForm.value.label === conditionValue.label; } else { return conditioningXForm.value === conditionValue; // more simple case of other fields } } } return true; } export function checkDeactivatedValues(extraForms) { // if changes occured, update extraForms array with freshly checked active customForms let newExtraForms = extraForms.map((xForm) => { // we use 'deactivate' instead of 'activate' because at initialization this property cannot be evaluated ... const isDeactivated = !isXtraFormActive(extraForms, xForm.conditional_field_config); // ... if the component is not created to set this property, thus no extra form would appear at all // toggle value to null to deactivate other fields conditioned by it if (isDeactivated) { xForm['value'] = null; } return { ...xForm, ['isDeactivated']: isDeactivated }; }); return newExtraForms; } export function checkFieldForcedValue(field, extraForms) { field['disabled'] = false; //* create a property disabled and (re)set to false by default if (field.forced_value_config) { //* loop over each forced value config for this extraForm for (const config of field.forced_value_config) { //* find the extraForm field conditioning the forced value const conditioningField = extraForms.find((xtraForm) => xtraForm.name === config.conditionField); //* if found check that its value match the condtionValue if (conditioningField && conditioningField.value === config.conditionValue) { //* set this value with the forced value and disable the form field field.value = config.forcedValue; field.disabled = true; } } } return field; } export function activateFieldsNforceValues(extraForms) { for (const [index, field] of extraForms.entries()) { const checkedField = checkFieldForcedValue(field, extraForms); //* each time a value changes, call this function recursively, until there is no more change if (checkedField.value !== field.value) { extraForms[index] = checkedField; //* update the value in extraForms activateFieldsNforceValues(extraForms); //* call the function with new extraForms } } //* when no more changes detected in the loop, check for deactivated extraForms extraForms = checkDeactivatedValues(extraForms); //* return extraForms from the lastly called function return extraForms; }