diff --git a/app/Enums/IdentityType.php b/app/Enums/IdentityType.php new file mode 100644 index 000000000..ff4ec2395 --- /dev/null +++ b/app/Enums/IdentityType.php @@ -0,0 +1,27 @@ + __('Age'), + 'gender-and-sexual-identity' => __('Gender and sexual identity'), + 'indigenous-identity' => __('Indigenous'), + 'ethnoracial-identity' => __('Race and ethnicity'), + 'refugee-or-immigrant' => __('Refugees and/or immigrants'), + 'first-language' => __('First language'), + 'area-type' => __('Living in urban, rural, or remote areas'), + ]; + } +} diff --git a/app/Enums/LocationType.php b/app/Enums/LocationType.php new file mode 100644 index 000000000..5ddc54777 --- /dev/null +++ b/app/Enums/LocationType.php @@ -0,0 +1,17 @@ + __('Specific provinces or territories'), + 'localities' => __('Specific cities or towns'), + ]; + } +} diff --git a/app/Http/Controllers/EngagementController.php b/app/Http/Controllers/EngagementController.php index 99eb50637..0227b6ef0 100644 --- a/app/Http/Controllers/EngagementController.php +++ b/app/Http/Controllers/EngagementController.php @@ -7,6 +7,8 @@ use App\Enums\EngagementFormat; use App\Enums\EngagementRecruitment; use App\Enums\IdentityCluster; +use App\Enums\IdentityType; +use App\Enums\LocationType; use App\Enums\MeetingType; use App\Enums\ProvinceOrTerritory; use App\Enums\TimeZone; @@ -164,23 +166,12 @@ public function criteriaSelection(Engagement $engagement): View 'indigenousIdentities' => Options::forModels(Identity::query()->whereJsonContains('clusters', IdentityCluster::Indigenous))->toArray(), 'ethnoracialIdentities' => Options::forModels(Identity::query()->whereJsonContains('clusters', IdentityCluster::Ethnoracial))->toArray(), 'languages' => Options::forArray(get_available_languages(true))->nullable(__('Choose a language…'))->toArray(), - 'locationTypeOptions' => Options::forArray([ - 'regions' => __('Specific provinces or territories'), - 'localities' => __('Specific cities or towns'), - ])->toArray(), + 'locationTypeOptions' => Options::forEnum(LocationType::class)->toArray(), 'intersectionalOptions' => Options::forArray([ '1' => __('No, give me a group with intersectional experiences and/or identities'), '0' => __('Yes, I’m looking for a group with a specific experience and/or identity (for example: Indigenous, immigrant, 2SLGBTQIA+)'), ])->toArray(), - 'otherIdentityOptions' => Options::forArray([ - 'age-bracket' => __('Age'), - 'gender-and-sexual-identity' => __('Gender and sexual identity'), - 'indigenous-identity' => __('Indigenous'), - 'ethnoracial-identity' => __('Race and ethnicity'), - 'refugee-or-immigrant' => __('Refugees and/or immigrants'), - 'first-language' => __('First language'), - 'area-type' => __('Living in urban, rural, or remote areas'), - ])->nullable(__('Select a criteria…'))->toArray(), + 'otherIdentityOptions' => Options::forEnum(IdentityType::class)->nullable(__('Select a criteria…'))->toArray(), ]); } @@ -192,11 +183,11 @@ public function updateCriteria(UpdateEngagementSelectionCriteriaRequest $request $matchingStrategyData = $request->safe()->except(['ideal_participants', 'minimum_participants']); - if ($matchingStrategyData['location_type'] === 'regions') { + if ($matchingStrategyData['location_type'] === LocationType::Regions->value) { $matchingStrategyData['locations'] = []; } - if ($matchingStrategyData['location_type'] === 'localities') { + if ($matchingStrategyData['location_type'] === LocationType::Localities->value) { $matchingStrategyData['regions'] = []; } @@ -215,7 +206,7 @@ public function updateCriteria(UpdateEngagementSelectionCriteriaRequest $request if ($matchingStrategyData['intersectional'] == 0) { $matchingStrategy->extra_attributes->other_identity_type = $matchingStrategyData['other_identity_type']; - if ($matchingStrategyData['other_identity_type'] === 'age-bracket') { + if ($matchingStrategyData['other_identity_type'] === IdentityType::AgeBracket->value) { $matchingStrategy->languages()->detach(); $matchingStrategy->syncMutuallyExclusiveIdentities( IdentityCluster::Age, @@ -229,7 +220,7 @@ public function updateCriteria(UpdateEngagementSelectionCriteriaRequest $request ); } - if ($matchingStrategyData['other_identity_type'] === 'gender-and-sexual-identity') { + if ($matchingStrategyData['other_identity_type'] === IdentityType::GenderAndSexualIdentity->value) { if (isset($matchingStrategyData['nb_gnc_fluid_identity']) && $matchingStrategyData['nb_gnc_fluid_identity'] == 1) { foreach (Identity::whereJsonContains('clusters', IdentityCluster::GenderDiverse)->get() as $genderDiverseIdentity) { $matchingStrategyData['gender_and_sexual_identities'][] = $genderDiverseIdentity->id; @@ -250,7 +241,7 @@ public function updateCriteria(UpdateEngagementSelectionCriteriaRequest $request ); } - if ($matchingStrategyData['other_identity_type'] === 'indigenous-identity') { + if ($matchingStrategyData['other_identity_type'] === IdentityType::IndigenousIdentity->value) { $matchingStrategy->languages()->detach(); $matchingStrategy->syncMutuallyExclusiveIdentities( IdentityCluster::Indigenous, @@ -264,7 +255,7 @@ public function updateCriteria(UpdateEngagementSelectionCriteriaRequest $request ); } - if ($matchingStrategyData['other_identity_type'] === 'ethnoracial-identity') { + if ($matchingStrategyData['other_identity_type'] === IdentityType::EthnoracialIdentity->value) { $matchingStrategy->languages()->detach(); $matchingStrategy->syncMutuallyExclusiveIdentities( IdentityCluster::Ethnoracial, @@ -279,7 +270,7 @@ public function updateCriteria(UpdateEngagementSelectionCriteriaRequest $request ); } - if ($matchingStrategyData['other_identity_type'] === 'refugee-or-immigrant') { + if ($matchingStrategyData['other_identity_type'] === IdentityType::RefugeeOrImmigrant->value) { $matchingStrategy->languages()->detach(); $matchingStrategy->detachClusters([ IdentityCluster::Age, @@ -294,7 +285,7 @@ public function updateCriteria(UpdateEngagementSelectionCriteriaRequest $request ); } - if ($matchingStrategyData['other_identity_type'] === 'first-language') { + if ($matchingStrategyData['other_identity_type'] === IdentityType::FirstLanguage->value) { $languages = []; foreach ($matchingStrategyData['first_languages'] as $code) { @@ -322,7 +313,7 @@ public function updateCriteria(UpdateEngagementSelectionCriteriaRequest $request ]); } - if ($matchingStrategyData['other_identity_type'] === 'area-type') { + if ($matchingStrategyData['other_identity_type'] === IdentityType::AreaType->value) { $matchingStrategy->languages()->detach(); $matchingStrategy->syncMutuallyExclusiveIdentities( IdentityCluster::Area, diff --git a/app/Http/Requests/AddNotificationableRequest.php b/app/Http/Requests/AddNotificationableRequest.php index b1dcc6291..519b8d85a 100644 --- a/app/Http/Requests/AddNotificationableRequest.php +++ b/app/Http/Requests/AddNotificationableRequest.php @@ -8,6 +8,10 @@ class AddNotificationableRequest extends FormRequest { public function authorize(): bool { + if (! is_callable($this->input('notificationable_type').'::find')) { + return false; + } + $notificationable = $this->input('notificationable_type')::find($this->input('notificationable_id')); return $notificationable && $this->user()->can('receiveNotifications'); diff --git a/app/Http/Requests/AddTranslationRequest.php b/app/Http/Requests/AddTranslationRequest.php index 13be621ad..fcac8ee4f 100644 --- a/app/Http/Requests/AddTranslationRequest.php +++ b/app/Http/Requests/AddTranslationRequest.php @@ -12,6 +12,10 @@ class AddTranslationRequest extends FormRequest */ public function authorize(): bool { + if (! is_callable($this->input('translatable_type').'::where')) { + return false; + } + $translatable = $this->input('translatable_type')::where('id', $this->input('translatable_id'))->first(); return $translatable && $this->user()->can('update', $translatable); @@ -39,7 +43,9 @@ public function rules(): array public function messages(): array { return [ - 'new_language.not_in' => __(':model is already translatable into :language.', ['model' => $this->get('translatable_type')::find($this->get('translatable_id'))->name, 'language' => get_language_exonym($this->get('new_language'))]), + 'new_language.required' => __('Please select a language.', ['model' => $this->get('translatable_type')::find($this->get('translatable_id'))->name]), + 'new_language.string' => __('Please select a language.', ['model' => $this->get('translatable_type')::find($this->get('translatable_id'))->name]), + 'new_language.not_in' => __(':model is already translatable into :language.', ['model' => $this->get('translatable_type')::find($this->get('translatable_id'))->name, 'language' => get_language_exonym($this->get('new_language') ?? '')]), ]; } } diff --git a/app/Http/Requests/DestroyTranslationRequest.php b/app/Http/Requests/DestroyTranslationRequest.php index 3124bde8a..09865532f 100644 --- a/app/Http/Requests/DestroyTranslationRequest.php +++ b/app/Http/Requests/DestroyTranslationRequest.php @@ -12,6 +12,10 @@ class DestroyTranslationRequest extends FormRequest */ public function authorize(): bool { + if (! is_callable($this->input('translatable_type').'::where')) { + return false; + } + $translatable = $this->input('translatable_type')::where('id', $this->input('translatable_id'))->first(); return $translatable && $this->user()->can('update', $translatable); @@ -39,7 +43,9 @@ public function rules(): array public function messages(): array { return [ - 'language.in' => __(':model was not translatable into :language.', ['model' => $this->get('translatable_type')::find($this->get('translatable_id'))->name, 'language' => get_language_exonym($this->get('language'))]), + 'language.required' => __('Please select a language to remove.'), + 'language.string' => __('Please select a language to remove.'), + 'language.in' => __(':model was not translatable into :language.', ['model' => $this->get('translatable_type')::find($this->get('translatable_id'))->name, 'language' => get_language_exonym($this->get('language') ?? '')]), ]; } } diff --git a/app/Http/Requests/MeetingRequest.php b/app/Http/Requests/MeetingRequest.php index 6e91c3634..519f019ec 100644 --- a/app/Http/Requests/MeetingRequest.php +++ b/app/Http/Requests/MeetingRequest.php @@ -7,9 +7,12 @@ use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; use Illuminate\Validation\Rules\Enum; +use Worksome\RequestFactories\Concerns\HasFactory; class MeetingRequest extends FormRequest { + use HasFactory; + public function authorize(): bool { return true; @@ -22,12 +25,12 @@ public function rules(): array $phone = MeetingType::Phone->value; return [ - 'title.*' => 'nullable|string', 'title.en' => 'required_without:title.fr', 'title.fr' => 'required_without:title.en', + 'title.*' => 'nullable|string', 'date' => 'required|date', - 'start_time' => 'required|date_format:G:i', - 'end_time' => 'required|date_format:G:i', + 'start_time' => 'required|date_format:G:i|before:end_time', + 'end_time' => 'required|date_format:G:i|after:start_time', 'timezone' => 'required|timezone', 'meeting_types' => 'required|array', 'meeting_types.*' => [ @@ -36,67 +39,69 @@ public function rules(): array ], 'street_address' => [ 'nullable', - Rule::excludeIf(! in_array($inPerson, $this->input('meeting_types', []))), - Rule::requiredIf(in_array($inPerson, $this->input('meeting_types', []))), + Rule::excludeIf(! in_array($inPerson, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + Rule::requiredIf(in_array($inPerson, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'string', ], 'unit_suite_floor' => [ 'nullable', - Rule::excludeIf(! in_array($inPerson, $this->input('meeting_types', []))), + Rule::excludeIf(! in_array($inPerson, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'string', ], 'locality' => [ 'nullable', - Rule::excludeIf(! in_array($inPerson, $this->input('meeting_types', []))), - Rule::requiredIf(in_array($inPerson, $this->input('meeting_types', []))), + Rule::excludeIf(! in_array($inPerson, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + Rule::requiredIf(in_array($inPerson, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'string', ], 'region' => [ 'nullable', - Rule::excludeIf(! in_array($inPerson, $this->input('meeting_types', []))), - Rule::requiredIf(in_array($inPerson, $this->input('meeting_types', []))), + Rule::excludeIf(! in_array($inPerson, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + Rule::requiredIf(in_array($inPerson, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), new Enum(ProvinceOrTerritory::class), ], 'postal_code' => [ 'nullable', - Rule::excludeIf(! in_array($inPerson, $this->input('meeting_types', []))), - Rule::requiredIf(in_array($inPerson, $this->input('meeting_types', []))), + Rule::excludeIf(! in_array($inPerson, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + Rule::requiredIf(in_array($inPerson, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'postal_code:CA', ], 'directions' => [ 'nullable', - Rule::excludeIf(! in_array($inPerson, $this->input('meeting_types', []))), + Rule::excludeIf(! in_array($inPerson, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'array', ], 'meeting_software' => [ 'nullable', - Rule::excludeIf(! in_array($webConference, $this->input('meeting_types', []))), - Rule::requiredIf(in_array($webConference, $this->input('meeting_types', []))), + Rule::excludeIf(! in_array($webConference, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + Rule::requiredIf(in_array($webConference, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + 'string', ], 'alternative_meeting_software' => [ 'nullable', - Rule::excludeIf(! in_array($webConference, $this->input('meeting_types', []))), + Rule::excludeIf(! in_array($webConference, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'boolean', ], 'meeting_url' => [ 'nullable', - Rule::excludeIf(! in_array($webConference, $this->input('meeting_types', []))), - Rule::requiredIf(in_array($webConference, $this->input('meeting_types', []))), + Rule::excludeIf(! in_array($webConference, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + Rule::requiredIf(in_array($webConference, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + 'url', ], 'additional_video_information' => [ 'nullable', - Rule::excludeIf(! in_array($webConference, $this->input('meeting_types', []))), + Rule::excludeIf(! in_array($webConference, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'array', ], 'meeting_phone' => [ 'nullable', - Rule::excludeIf(! in_array($phone, $this->input('meeting_types', []))), - Rule::requiredIf(in_array($phone, $this->input('meeting_types', []))), - 'phone:CA', + Rule::excludeIf(! in_array($phone, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + Rule::requiredIf(in_array($phone, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + 'phone:CA,US', ], 'additional_phone_information' => [ 'nullable', - Rule::excludeIf(! in_array($phone, $this->input('meeting_types', []))), + Rule::excludeIf(! in_array($phone, is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'array', ], ]; @@ -109,23 +114,33 @@ public function attributes(): array 'end_time' => __('meeting end time'), 'date' => __('meeting date'), 'timezone' => __('meeting time zone'), + 'locality' => __('city or town'), 'region' => __('province or territory'), 'meeting_url' => __('link to join the meeting'), - 'meeting_phone' => __('meeting phone number'), + 'meeting_phone' => __('phone number to join the meeting'), ]; } public function messages(): array { return [ - 'title.*.required_without' => __('A meeting title must be provided in at least one language.'), + 'date.required' => __('You must enter a :attribute'), + 'title.*.required_without' => __('A meeting title must be provided in at least English or French.'), 'meeting_types.required' => __('You must indicate at least one way for participants to attend the meeting.'), + 'meeting_types.*.Illuminate\Validation\Rules\Enum' => __('You must select a valid meeting type.'), 'street_address.required' => __('You must enter a :attribute for the meeting location.'), 'locality.required' => __('You must enter a :attribute for the meeting location.'), 'region.required' => __('You must enter a :attribute for the meeting location.'), 'postal_code.required' => __('You must enter a :attribute for the meeting location.'), 'meeting_software.required' => __('You must indicate the :attribute.'), - 'meeting_url.required' => __('You must provide a :attribute.'), + 'meeting_url.required' => __('You must enter a :attribute.'), + 'meeting_phone.required' => __('You must enter a :attribute.'), + 'start_time.required' => __('You must enter a :attribute'), + 'start_time.date_format' => __('The :attribute format is not valid.'), + 'start_time.before' => __('The :attribute must be before the :date.'), + 'end_time.required' => __('You must enter a :attribute'), + 'end_time.date_format' => __('The :attribute format is not valid.'), + 'end_time.after' => __('The :attribute must be after the :date.'), ]; } } diff --git a/app/Http/Requests/RemoveNotificationableRequest.php b/app/Http/Requests/RemoveNotificationableRequest.php index ca83239eb..b045c421d 100644 --- a/app/Http/Requests/RemoveNotificationableRequest.php +++ b/app/Http/Requests/RemoveNotificationableRequest.php @@ -3,6 +3,7 @@ namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; +use Illuminate\Validation\Validator; class RemoveNotificationableRequest extends FormRequest { @@ -15,7 +16,20 @@ public function rules(): array { return [ 'notificationable_type' => 'required|string|in:App\Models\Organization,App\Models\RegulatedOrganization', - 'notificationable_id' => 'required|integer|exists:'.$this->input('notificationable_type').',id', + 'notificationable_id' => 'required|integer', ]; } + + public function withValidator(Validator $validator) + { + $validator->sometimes('notificationable_id', 'exists:'.$this->input('notificationable_type').',id', function ($input) { + return isset($input->notificationable_type) && in_array( + $input->notificationable_type, + [ + 'App\Models\Organization', + 'App\Models\RegulatedOrganization', + ] + ); + }); + } } diff --git a/app/Http/Requests/SaveIndividualRolesRequest.php b/app/Http/Requests/SaveIndividualRolesRequest.php index 03d4f300d..c2d140d54 100644 --- a/app/Http/Requests/SaveIndividualRolesRequest.php +++ b/app/Http/Requests/SaveIndividualRolesRequest.php @@ -41,6 +41,8 @@ public function messages(): array { return [ 'roles.required' => __('You must select what you would like to do on the website.'), + 'roles.array' => __('You must select what you would like to do on the website.'), + 'roles.*.Illuminate\Validation\Rules\Enum' => __('You must select a valid role to perform on the website.'), ]; } } diff --git a/app/Http/Requests/StoreInvitationRequest.php b/app/Http/Requests/StoreInvitationRequest.php index 450ba53c9..564c30fe0 100644 --- a/app/Http/Requests/StoreInvitationRequest.php +++ b/app/Http/Requests/StoreInvitationRequest.php @@ -38,7 +38,10 @@ public function rules(): array public function messages(): array { return [ - 'email.not_in' => __('This user already belongs to this team.'), + 'email.required' => __('You must enter an email address.'), + 'email.unique' => __('This member has already been invited.'), + 'email.not_in' => __('This member already belongs to this organization.'), + 'role.required' => __('The user’s role is missing.'), ]; } } diff --git a/app/Http/Requests/UpdateEngagementRequest.php b/app/Http/Requests/UpdateEngagementRequest.php index f288da5d6..1cd5eb067 100644 --- a/app/Http/Requests/UpdateEngagementRequest.php +++ b/app/Http/Requests/UpdateEngagementRequest.php @@ -30,12 +30,12 @@ public function rules(): array ]; return [ - 'name.*' => 'nullable|string', 'name.en' => 'required_without:name.fr', 'name.fr' => 'required_without:name.en', - 'description.*' => 'nullable|string', + 'name.*' => 'nullable|string', 'description.en' => 'required_without:description.fr', 'description.fr' => 'required_without:description.en', + 'description.*' => 'nullable|string', 'window_start_date' => [ 'nullable', Rule::excludeIf($this->engagement->format !== 'interviews'), @@ -100,67 +100,69 @@ public function rules(): array ], 'street_address' => [ 'nullable', - Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('in_person', $this->input('meeting_types', []))), - Rule::requiredIf($this->engagement->format === 'interviews' && in_array('in_person', $this->input('meeting_types', []))), + Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('in_person', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + Rule::requiredIf($this->engagement->format === 'interviews' && in_array('in_person', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'string', ], 'unit_suite_floor' => [ 'nullable', - Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('in_person', $this->input('meeting_types', []))), + Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('in_person', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'string', ], 'locality' => [ 'nullable', - Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('in_person', $this->input('meeting_types', []))), - Rule::requiredIf($this->engagement->format === 'interviews' && in_array('in_person', $this->input('meeting_types', []))), + Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('in_person', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + Rule::requiredIf($this->engagement->format === 'interviews' && in_array('in_person', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'string', ], 'region' => [ 'nullable', - Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('in_person', $this->input('meeting_types', []))), - Rule::requiredIf($this->engagement->format === 'interviews' && in_array('in_person', $this->input('meeting_types', []))), + Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('in_person', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + Rule::requiredIf($this->engagement->format === 'interviews' && in_array('in_person', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), new Enum(ProvinceOrTerritory::class), ], 'postal_code' => [ 'nullable', - Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('in_person', $this->input('meeting_types', []))), - Rule::requiredIf($this->engagement->format === 'interviews' && in_array('in_person', $this->input('meeting_types', []))), + Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('in_person', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + Rule::requiredIf($this->engagement->format === 'interviews' && in_array('in_person', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'postal_code:CA', ], 'directions' => [ 'nullable', - Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('in_person', $this->input('meeting_types', []))), + Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('in_person', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'array', ], 'meeting_software' => [ 'nullable', - Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('web_conference', $this->input('meeting_types', []))), - Rule::requiredIf($this->engagement->format === 'interviews' && in_array('web_conference', $this->input('meeting_types', []))), + Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('web_conference', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + Rule::requiredIf($this->engagement->format === 'interviews' && in_array('web_conference', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + 'string', ], 'alternative_meeting_software' => [ 'nullable', - Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('web_conference', $this->input('meeting_types', []))), + Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('web_conference', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'boolean', ], 'meeting_url' => [ 'nullable', - Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('web_conference', $this->input('meeting_types', []))), - Rule::requiredIf($this->engagement->format === 'interviews' && in_array('web_conference', $this->input('meeting_types', []))), + Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('web_conference', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + Rule::requiredIf($this->engagement->format === 'interviews' && in_array('web_conference', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + 'url', ], 'additional_video_information' => [ 'nullable', - Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('web_conference', $this->input('meeting_types', []))), + Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('web_conference', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'array', ], 'meeting_phone' => [ 'nullable', - Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('phone', $this->input('meeting_types', []))), - Rule::requiredIf($this->engagement->format === 'interviews' && in_array('phone', $this->input('meeting_types', []))), - 'phone:CA', + Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('phone', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + Rule::requiredIf($this->engagement->format === 'interviews' && in_array('phone', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), + 'phone:CA,US', ], 'additional_phone_information' => [ 'nullable', - Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('phone', $this->input('meeting_types', []))), + Rule::excludeIf($this->engagement->format !== 'interviews' || ! in_array('phone', is_array($this->input('meeting_types')) ? $this->input('meeting_types') : [])), 'array', ], 'materials_by_date' => [ @@ -284,8 +286,8 @@ public function attributes(): array 'locality' => __('city or town'), 'region' => __('province or territory'), 'meeting_url' => __('link to join the meeting'), - 'meeting_phone' => __('meeting phone number'), - 'materials_by_date' => __('sent by date'), + 'meeting_phone' => __('phone number to join the meeting'), + 'materials_by_date' => __('date for materials to be sent by'), 'complete_by_date' => __('due date'), 'signup_by_date' => __('sign up deadline'), 'other_accepted_formats' => __('accepted formats'), @@ -295,19 +297,44 @@ public function attributes(): array public function messages(): array { return [ - 'name.*.required_without' => __('An engagement name must be provided in at least one language.'), - 'description.*.required_without' => __('An engagement description must be provided in at least one language.'), + 'name.*.required_without' => __('An engagement name must be provided in at least English or French.'), + 'description.*.required_without' => __('An engagement description must be provided in at least English or French.'), + 'document_languages.required' => __('Please select a language that the engagement documents will be in.'), + 'document_languages.*.in' => __('Please select a language that the engagement documents will be in.'), + 'window_start_date.required' => __('You must enter a :attribute'), + 'window_start_date.before' => __('The :attribute must be before the :date.'), + 'window_end_date.required' => __('You must enter a :attribute'), + 'window_end_date.after' => __('The :attribute must be after the :date.'), 'window_start_time.date_format' => __('The :attribute is not in the right format.'), + 'window_start_time.required' => __('You must enter a :attribute'), + 'window_start_time.before' => __('The :attribute must be before the :date.'), 'window_end_time.date_format' => __('The :attribute is not in the right format.'), + 'window_end_time.required' => __('You must enter a :attribute'), + 'window_end_time.after' => __('The :attribute must be after the :date.'), + 'timezone.required' => __('You must enter a :attribute'), + 'timezone.timezone' => __('You must enter a :attribute'), 'street_address.required' => __('You must enter a :attribute for the meeting location.'), 'locality.required' => __('You must enter a :attribute for the meeting location.'), 'region.required' => __('You must enter a :attribute for the meeting location.'), 'postal_code.required' => __('You must enter a :attribute for the meeting location.'), + 'meeting_types.required' => __('You must select at least one way to attend the meeting.'), 'meeting_software.required' => __('You must indicate the :attribute.'), - 'meeting_url.required' => __('You must provide a :attribute.'), + 'meeting_url.required' => __('You must enter a :attribute.'), 'accepted_formats.required' => __('You must indicate the :attribute.'), + 'accepted_formats.*.Illuminate\Validation\Rules\Enum' => __('You must select a valid format.'), 'other_accepted_formats.required' => __('You must indicate the :attribute.'), - 'other_accepted_format.*.required_without' => __('The other accepted format must be provided in at least one language.'), + 'other_accepted_format.*.string' => __('The other accepted format must be a string.'), + 'other_accepted_format.*.required_without' => __('The other accepted format must be provided in at least English or French.'), + 'meeting_types.*.Illuminate\Validation\Rules\Enum' => __('You must select a valid meeting type.'), + 'materials_by_date.required' => __('You must enter a :attribute.'), + 'materials_by_date.date' => __('Please enter a valid :attribute.'), + 'materials_by_date.before' => __('The :attribute must be before the :date.'), + 'complete_by_date.required' => __('You must enter a :attribute.'), + 'complete_by_date.date' => __('Please enter a valid :attribute.'), + 'complete_by_date.after' => __('The :attribute must be after the :date.'), + 'signup_by_date' => __('You must enter a :attribute.'), + 'signup_by_date.date' => __('Please enter a valid date for the :attribute.'), + 'signup_by_date.before' => __('The :attribute must be before the :date.'), ]; } } diff --git a/app/Http/Requests/UpdateEngagementSelectionCriteriaRequest.php b/app/Http/Requests/UpdateEngagementSelectionCriteriaRequest.php index ce4c15d67..2f12bfc8a 100644 --- a/app/Http/Requests/UpdateEngagementSelectionCriteriaRequest.php +++ b/app/Http/Requests/UpdateEngagementSelectionCriteriaRequest.php @@ -2,6 +2,7 @@ namespace App\Http\Requests; +use App\Enums\LocationType; use App\Enums\ProvinceOrTerritory; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; @@ -20,7 +21,7 @@ public function authorize(): bool public function rules(): array { return [ - 'location_type' => 'required|in:regions,localities', + 'location_type' => ['required', new Enum(LocationType::class)], 'regions' => 'nullable|array|required_if:location_type,regions|exclude_if:location_type,localities', 'regions.*' => [new Enum(ProvinceOrTerritory::class)], 'locations' => 'nullable|array|required_if:location_type,localities|exclude_if:location_type,regions', @@ -40,7 +41,7 @@ public function rules(): array 'boolean', Rule::requiredIf(function () { return request('other_identity_type') === 'gender-and-sexual-identity' - && count(request('gender_and_sexual_identities') ?? []) === 0; + && (! is_array(request('gender_and_sexual_identities')) || count(request('gender_and_sexual_identities')) === 0); }), 'exclude_unless:other_identity_type,gender-and-sexual-identity', ], @@ -72,19 +73,57 @@ public function rules(): array ]; } + public function attributes(): array + { + return [ + 'age_brackets' => __('age group'), + 'age_brackets.*' => __('age group'), + 'area_types' => __('area type'), + 'area_types.*' => __('area type'), + 'disability_types' => __('Disability or Deaf group'), + 'disability_types.*' => __('Disability or Deaf group'), + 'ethnoracial_identities' => __('ethnoracial group'), + 'ethnoracial_identities.*' => __('ethnoracial group'), + 'first_languages' => __('first language'), + 'first_languages.*' => __('first language'), + 'gender_and_sexual_identities' => __('gender or sexual identity group'), + 'gender_and_sexual_identities.*' => __('gender or sexual identity group'), + 'ideal_participants' => __('ideal number of participants'), + 'indigenous_identities' => __('Indigenous group'), + 'indigenous_identities.*' => __('Indigenous group'), + 'minimum_participants' => __('minimum number of participants'), + 'nb_gnc_fluid_identity' => __('Non-binary/Gender non-conforming/Gender fluid identity'), + ]; + } + public function messages(): array { return [ - 'minimum_participants.lte' => __('The minimum number of participants is more than the ideal number of participants. Please enter a minimum that is less than or the same as the ideal number of participants.'), + 'minimum_participants.required' => __('You must enter a :attribute.'), + 'minimum_participants.lte' => __('Please enter a :attribute that is less than or the same as the ideal number of participants.'), + 'minimum_participants.integer' => __('The :attribute must be a number.'), 'locations.*.region' => __('You must enter a province or territory.'), 'locations.*.locality' => __('You must enter a city or town.'), 'locations.required_if' => __('You must enter at least one city or town.'), 'regions.required_if' => __('You must choose at least one province or territory.'), - 'disability_types.required_if' => __('One or more Disability or Deaf groups are required.'), - 'gender_and_sexual_identities.required_if' => __('You must select at least one gender or sexual identity group.'), - 'gender_and_sexual_identities.required' => __('You must select at least one gender or sexual identity group.'), - 'nb_gnc_fluid_identity.required' => __('You must select at least one gender or sexual identity group.'), - + 'regions.*.Illuminate\Validation\Rules\Enum' => __('You must choose a valid province or territory'), + 'disability_types.required_if' => __('If you are looking for a specific :attribute, you must select at least one.'), + 'disability_types.*.exists' => __('You must select a valid :attribute.'), + 'age_brackets.required_if' => __('If you are interested in engaging a specific :attribute, you must select at least one.'), + 'age_brackets.*.exists' => __('You must select a valid :attribute.'), + 'gender_and_sexual_identities.required_if' => __('If you are interested in engaging a specific :attribute, you must select at least one.'), + 'gender_and_sexual_identities.required' => __('If you are interested in engaging a specific :attribute, you must select at least one.'), + 'gender_and_sexual_identities.*.exists' => __('You must select a valid :attribute.'), + 'nb_gnc_fluid_identity.required' => __('If you are interested in engaging a specific :attribute, you must select at least one.', ['attribute' => __('gender or sexual identity group')]), + 'indigenous_identities.required_if' => __('If you are interested in engaging a specific :attribute, you must select at least one.'), + 'indigenous_identities.*.exists' => __('You must select a valid :attribute.'), + 'ethnoracial_identities.required_if' => __('If you are interested in engaging a specific :attribute, you must select at least one.'), + 'ethnoracial_identities.*.exists' => __('You must select a valid :attribute.'), + 'first_languages.required_if' => __('If you are interested in engaging a specific :attribute, you must select at least one.'), + 'first_languages.*.in' => __('You must select a valid :attribute.'), + 'area_types.required_if' => __('If you are interested in engaging a specific :attribute, you must select at least one.'), + 'area_types.*.exists' => __('You must select a valid :attribute.'), + 'other_identity_type.required_if' => __('If you are looking for a group with a specific experience or identity, you must select which type of experience or identity you are looking for.'), ]; } diff --git a/app/Http/Requests/UpdateIndividualRequest.php b/app/Http/Requests/UpdateIndividualRequest.php index ae1883597..4d52db458 100644 --- a/app/Http/Requests/UpdateIndividualRequest.php +++ b/app/Http/Requests/UpdateIndividualRequest.php @@ -9,9 +9,12 @@ use Illuminate\Support\Str; use Illuminate\Validation\Rule; use Illuminate\Validation\Rules\Enum; +use Worksome\RequestFactories\Concerns\HasFactory; class UpdateIndividualRequest extends FormRequest { + use HasFactory; + /** * Determine if the user is authorized to make this request. */ @@ -34,9 +37,9 @@ public function rules(): array ], 'pronouns' => 'nullable|array:'.implode(',', to_written_languages($this->individual->languages)), 'bio' => 'required|array:'.implode(',', to_written_languages($this->individual->languages)).'|required_array_keys:'.get_written_language_for_signed_language($this->individual->user->locale), - 'bio.*' => 'nullable|string', 'bio.en' => 'required_without:bio.fr', 'bio.fr' => 'required_without:bio.en', + 'bio.*' => 'nullable|string', 'working_languages' => 'nullable|array', 'consulting_services' => [ 'nullable', @@ -56,7 +59,7 @@ public function rules(): array public function prepareForValidation() { $this->merge([ - 'social_links' => array_map('normalize_url', $this->social_links ?? []), + 'social_links' => array_map('normalize_url', is_array($this->social_links) ? $this->social_links : []), 'website_link' => normalize_url($this->website_link), ]); } @@ -71,11 +74,16 @@ public function attributes(): array public function messages(): array { $messages = [ - 'bio.*.required_without' => 'You must enter your bio.', + 'bio.required_array_keys' => __('Your bio must be provided in at least English or French.'), + 'bio.*.required_without' => __('Your bio must be provided in at least English or French.'), + 'bio.array' => __('Your bio must be provided in at least English or French.'), + 'consulting_services.*.Illuminate\Validation\Rules\Enum' => __('The selected consulting service is invalid'), + 'pronouns.array' => __('Your pronouns must be provided in at least English or French.'), + 'website_link.active_url' => __('You must enter a valid website link.'), ]; foreach ($this->social_links as $key => $value) { - $messages['social_links.'.$key.'.active_url'] = __('You must enter a valid website address for :key.', ['key' => Str::studly($key)]); + $messages['social_links.'.$key.'.active_url'] = __('You must enter a valid link for :key.', ['key' => Str::studly($key)]); } return $messages; diff --git a/app/Models/MatchingStrategy.php b/app/Models/MatchingStrategy.php index ec2e58430..0ddd8e747 100644 --- a/app/Models/MatchingStrategy.php +++ b/app/Models/MatchingStrategy.php @@ -3,6 +3,8 @@ namespace App\Models; use App\Enums\IdentityCluster; +use App\Enums\IdentityType; +use App\Enums\LocationType; use App\Enums\ProvinceOrTerritory; use App\Models\Scopes\ReachableIdentityScope; use App\Traits\HasSchemalessAttributes; @@ -100,10 +102,10 @@ public function locationType(): Attribute return Attribute::make( get: function () { if (! empty($this->regions)) { - return 'regions'; + return LocationType::Regions->value; } if (! empty($this->locations)) { - return 'localities'; + return LocationType::Localities->value; } return null; @@ -157,13 +159,13 @@ public function otherIdentitiesSummary(): Attribute return Attribute::make( get: function () { return match ($this->extra_attributes->get('other_identity_type', null)) { - 'age-bracket' => $this->identities()->whereJsonContains('clusters', IdentityCluster::Age)->pluck('name')->toArray(), - 'gender-and-sexual-identity' => $this->identities()->whereJsonContains('clusters', IdentityCluster::GenderAndSexuality)->pluck('name')->toArray(), - 'indigenous-identity' => $this->identities()->whereJsonContains('clusters', IdentityCluster::Indigenous)->pluck('name')->toArray(), - 'ethnoracial-identity' => $this->identities()->whereJsonContains('clusters', IdentityCluster::Ethnoracial)->pluck('name')->toArray(), - 'refugee-or-immigrant' => $this->identities()->whereJsonContains('clusters', IdentityCluster::Status)->pluck('name')->toArray(), - 'first-language' => $this->languages->map(fn ($language) => $language->name)->toArray(), - 'area-type' => $this->identities()->whereJsonContains('clusters', IdentityCluster::Area)->pluck('name')->toArray(), + IdentityType::AgeBracket->value => $this->identities()->whereJsonContains('clusters', IdentityCluster::Age)->pluck('name')->toArray(), + IdentityType::GenderAndSexualIdentity->value => $this->identities()->whereJsonContains('clusters', IdentityCluster::GenderAndSexuality)->pluck('name')->toArray(), + IdentityType::IndigenousIdentity->value => $this->identities()->whereJsonContains('clusters', IdentityCluster::Indigenous)->pluck('name')->toArray(), + IdentityType::EthnoracialIdentity->value => $this->identities()->whereJsonContains('clusters', IdentityCluster::Ethnoracial)->pluck('name')->toArray(), + IdentityType::RefugeeOrImmigrant->value => $this->identities()->whereJsonContains('clusters', IdentityCluster::Status)->pluck('name')->toArray(), + IdentityType::FirstLanguage->value => $this->languages->map(fn ($language) => $language->name)->toArray(), + IdentityType::AreaType->value => $this->identities()->whereJsonContains('clusters', IdentityCluster::Area)->pluck('name')->toArray(), default => [__('Intersectional - This engagement is looking for people who have all sorts of different identities and lived experiences, such as race, gender, age, sexual orientation, and more.')], }; }, diff --git a/composer.lock b/composer.lock index 4f607609b..780dc6509 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4d29f4ab4d5b440fd480abbeec9499ec", + "content-hash": "39982df0271629f34e5e8a0dd30bd5a6", "packages": [ { "name": "akaunting/laravel-money", @@ -11899,16 +11899,16 @@ }, { "name": "fakerphp/faker", - "version": "v1.21.0", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "92efad6a967f0b79c499705c69b662f738cc9e4d" + "reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/92efad6a967f0b79c499705c69b662f738cc9e4d", - "reference": "92efad6a967f0b79c499705c69b662f738cc9e4d", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e3daa170d00fde61ea7719ef47bb09bb8f1d9b01", + "reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01", "shasum": "" }, "require": { @@ -11961,9 +11961,9 @@ ], "support": { "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v1.21.0" + "source": "https://github.com/FakerPHP/Faker/tree/v1.23.0" }, - "time": "2022-12-13T13:54:32+00:00" + "time": "2023-06-12T08:44:38+00:00" }, { "name": "fidry/cpu-core-counter", @@ -15720,5 +15720,5 @@ "php": "^8.1" }, "platform-dev": [], - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.1.0" } diff --git a/resources/lang/en.json b/resources/lang/en.json index c33cec004..e926f61ec 100644 --- a/resources/lang/en.json +++ b/resources/lang/en.json @@ -224,6 +224,7 @@ "After the consultation follow up with participants to share next steps and your organization’s plan for implementing their feedback. This can help foster confidence in your commitment, and an ongoing relationship with your participants, who can be involved in future updates of your accessibility plan.": "After the consultation follow up with participants to share next steps and your organization’s plan for implementing their feedback. This can help foster confidence in your commitment, and an ongoing relationship with your participants, who can be involved in future updates of your accessibility plan.", "Age": "Age", "Age group": "Age group", + "age group": "age group", "Age groups": "Age groups", "Age groups they can connect to": "Age groups they can connect to", "Agreement pending": "Agreement pending", @@ -240,14 +241,15 @@ "All the training I am doing or have done.": "All the training I am doing or have done.", "Alternative text for images": "Alternative text for images", "Although it is not compulsory, we highly recommend that you include English and French translations of your content.": "Although it is not compulsory, we highly recommend that you include English and French translations of your content.", - "A meeting title must be provided in at least one language.": "A meeting title must be provided in at least one language.", + "A meeting title must be provided in at least English or French.": "A meeting title must be provided in at least English or French.", "American Sign Language (ASL)": "American Sign Language (ASL)", "Analysis of collected information": "Analysis of collected information", "Analyze the outcomes of your consultation with people who are in the context of disability and Deaf groups.": "Analyze the outcomes of your consultation with people who are in the context of disability and Deaf groups.", "An approximate response time must be provided in at least one language.": "An approximate response time must be provided in at least one language.", - "An engagement description must be provided in at least one language.": "An engagement description must be provided in at least one language.", + "An engagement description must be provided in at least English or French.": "An engagement description must be provided in at least English or French.", "An engagement involves a group of people participating in one set way (for example, a focus group or a survey). An engagement like a focus group can have multiple meetings.": "An engagement involves a group of people participating in one set way (for example, a focus group or a survey). An engagement like a focus group can have multiple meetings.", "An engagement involves a group of people participating in one set way (for example, a focus group or survey).": "An engagement involves a group of people participating in one set way (for example, a focus group or survey).", + "An engagement name must be provided in at least English or French.": "An engagement name must be provided in at least English or French.", "An engagement name must be provided in at least one language.": "An engagement name must be provided in at least one language.", "An engagement with this name already exists.": "An engagement with this name already exists.", "a network and is able to conduct effective outreach to people with disabilities and Deaf persons in particular geographic communities and social groups (for example, Indigenous communities).": "a network and is able to conduct effective outreach to people with disabilities and Deaf persons in particular geographic communities and social groups (for example, Indigenous communities).", @@ -278,6 +280,7 @@ "Areas of interest": "Areas of interest", "Areas of your organization this project will impact": "Areas of your organization this project will impact", "Areas where the organization serves": "Areas where the organization serves", + "area type": "area type", "Are you able to attend consultations in real-time, or do you prefer to receive the materials (ex. questions, discussion topics) and record your responses at your own pace?": "Are you able to attend consultations in real-time, or do you prefer to receive the materials (ex. questions, discussion topics) and record your responses at your own pace?", "Are you looking for individuals in specific provinces or territories or specific cities or towns?": "Are you looking for individuals in specific provinces or territories or specific cities or towns?", "Are you sure you want to block :blockable?": "Are you sure you want to block :blockable?", @@ -564,6 +567,7 @@ "Date": "Date", "Date added": "Date added", "Date created": "Date created", + "date for materials to be sent by": "date for materials to be sent by", "Date of training": "Date of training", "Date range": "Date range", "Dates": "Dates", @@ -715,6 +719,7 @@ "Estimates and agreements": "Estimates and agreements", "Estimate status": "Estimate status", "Ethno-racial groups": "Ethno-racial groups", + "ethnoracial group": "ethnoracial group", "Ethnoracial group they can connect to": "Ethnoracial group they can connect to", "Ethnoracial identity": "Ethnoracial identity", "ethnoracial identity": "ethnoracial identity", @@ -746,6 +751,7 @@ "Find learning materials, best practices, and variety of tools to help you throughout the consultation process.": "Find learning materials, best practices, and variety of tools to help you throughout the consultation process.", "Find people with disabilities, Deaf people and community organizations (for example, disability or other relevant civil society organizations, like Indigenous groups), to consult with on your accessibility project.": "Find people with disabilities, Deaf people and community organizations (for example, disability or other relevant civil society organizations, like Indigenous groups), to consult with on your accessibility project.", "First language": "First language", + "first language": "first language", "First Nations": "First Nations", "flexible, please contact us if you need to use another software": "flexible, please contact us if you need to use another software", "Focus group": "Focus group", @@ -799,6 +805,7 @@ "Gender neutral, barrier-free washrooms": "Gender neutral, barrier-free washrooms", "Gender neutral washroom": "Gender neutral washroom", "Gender non-conforming people": "Gender non-conforming people", + "gender or sexual identity group": "gender or sexual identity group", "GENERAL": "GENERAL", "General": "General", "General access needs": "General access needs", @@ -882,6 +889,7 @@ "Ideally, an Accessibility Consultant has:": "Ideally, an Accessibility Consultant has:", "Ideally a Community Connector has:": "Ideally a Community Connector has:", "Ideal number of participants": "Ideal number of participants", + "ideal number of participants": "ideal number of participants", "Identities": "Identities", "If anything about your projects or engagements have changed, please send a new estimate request.": "If anything about your projects or engagements have changed, please send a new estimate request.", "If a Sign Language video translation is available, you will see a button in line with the website content. Pressing that button will load the Sign Language video.": "If a Sign Language video translation is available, you will see a button in line with the website content. Pressing that button will load the Sign Language video.", @@ -891,6 +899,9 @@ "if the provision of the Platform to you by IRIS is, in IRIS’ opinion, no longer commercially or financially viable.": "if the provision of the Platform to you by IRIS is, in IRIS’ opinion, no longer commercially or financially viable.", "If you already have an account, please [sign in](:url).": "If you already have an account, please [sign in](:url).", "IF YOU ARE DISSATISFIED WITH ANY PORTION OF THE PLATFORM OR WITH THESE TERMS OF SERVICE, YOUR SOLE AND EXCLUSIVE REMEDY IS TO DISCONTINUE USE OF THE PLATFORM.": "IF YOU ARE DISSATISFIED WITH ANY PORTION OF THE PLATFORM OR WITH THESE TERMS OF SERVICE, YOUR SOLE AND EXCLUSIVE REMEDY IS TO DISCONTINUE USE OF THE PLATFORM.", + "If you are interested in engaging a specific :attribute, you must select at least one.": "If you are interested in engaging a specific :attribute, you must select at least one.", + "If you are looking for a group with a specific experience or identity, you must select which type of experience or identity you are looking for.": "If you are looking for a group with a specific experience or identity, you must select which type of experience or identity you are looking for.", + "If you are looking for a specific :attribute, you must select at least one.": "If you are looking for a specific :attribute, you must select at least one.", "If you are seeking a Community Connector for this engagement, there are a few ways to find one:": "If you are seeking a Community Connector for this engagement, there are a few ways to find one:", "If you are thinking of working with a specific group, for example, Indigenous people with disabilities, it would be a good idea to hire an Accessibility Consultant from that community.": "If you are thinking of working with a specific group, for example, Indigenous people with disabilities, it would be a good idea to hire an Accessibility Consultant from that community.", "If you delete your account:": "If you delete your account:", @@ -918,6 +929,7 @@ "Incomplete": "Incomplete", "INDEMNITY AND RELEASE.": "INDEMNITY AND RELEASE.", "Indigenous": "Indigenous", + "Indigenous group": "Indigenous group", "Indigenous identity": "Indigenous identity", "Individual": "Individual", "individual": "individual", @@ -1075,7 +1087,6 @@ "Meeting date :date": "Meeting date :date", "Meeting dates": "Meeting dates", "meeting end time": "meeting end time", - "meeting phone number": "meeting phone number", "Meetings": "Meetings", "meeting start time": "meeting start time", "meeting time zone": "meeting time zone", @@ -1089,6 +1100,7 @@ "Microsoft Word": "Microsoft Word", "Middle Eastern": "Middle Eastern", "Minimum number of participants": "Minimum number of participants", + "minimum number of participants": "minimum number of participants", "Missing an engagement?": "Missing an engagement?", "modify, copy, reproduce, reverse engineer, frame, rent, lease, loan, sell, distribute, publish, or create derivative works based on the Platform or the Service Content (as defined below), in whole or in part;": "modify, copy, reproduce, reverse engineer, frame, rent, lease, loan, sell, distribute, publish, or create derivative works based on the Platform or the Service Content (as defined below), in whole or in part;", "Module - :title": "Module - :title", @@ -1159,6 +1171,7 @@ "No interests listed.": "No interests listed.", "No meetings found.": "No meetings found.", "Non-binary, gender non-conforming and\/or gender fluid people": "Non-binary, gender non-conforming and\/or gender fluid people", + "Non-binary\/Gender non-conforming\/Gender fluid identity": "Non-binary\/Gender non-conforming\/Gender fluid identity", "Non-binary people": "Non-binary people", "None found.": "None found.", "None listed": "None listed", @@ -1229,7 +1242,6 @@ "Once you sign up, you can sign up for an orientation session to learn about what you can do on this website. You can also fill in information to facilitate a smoother collaboration with organizations, such as access needs, communication preferences, and consultation preferences.": "Once you sign up, you can sign up for an orientation session to learn about what you can do on this website. You can also fill in information to facilitate a smoother collaboration with organizations, such as access needs, communication preferences, and consultation preferences.", "Once you’ve reviewed the project details, please:": "Once you’ve reviewed the project details, please:", "One of the key parts of preparing for your consultation with the disability and Deaf communities is making sure that your consultations are done in an accessible and inclusive way.": "One of the key parts of preparing for your consultation with the disability and Deaf communities is making sure that your consultations are done in an accessible and inclusive way.", - "One or more Disability or Deaf groups are required.": "One or more Disability or Deaf groups are required.", "Online form, such as survey monkey or google forms": "Online form, such as survey monkey or google forms", "Only people with specific disabilities and\/or Deaf people": "Only people with specific disabilities and\/or Deaf people", "Only reachable within cross-disability and Deaf or intersectional groups": "Only reachable within cross-disability and Deaf or intersectional groups", @@ -1327,6 +1339,7 @@ "phone number": "phone number", "Phone number:": "Phone number:", "Phone number to join": "Phone number to join", + "phone number to join the meeting": "phone number to join the meeting", "Physical and mobility disabilities": "Physical and mobility disabilities", "Plain language": "Plain language", "Plan and share your project with others on this website.": "Plan and share your project with others on this website.", @@ -1356,7 +1369,10 @@ "Please create your profile to share more about who you are, your experiences, and your interests.": "Please create your profile to share more about who you are, your experiences, and your interests.", "Please describe how the Disability and Deaf communities will be impacted by the outcomes of your project.": "Please describe how the Disability and Deaf communities will be impacted by the outcomes of your project.", "Please describe this engagement.": "Please describe this engagement.", + "Please enter a :attribute that is less than or the same as the ideal number of participants.": "Please enter a :attribute that is less than or the same as the ideal number of participants.", "Please enter an end year for your experience that is equal to or greater than the start year.": "Please enter an end year for your experience that is equal to or greater than the start year.", + "Please enter a valid :attribute.": "Please enter a valid :attribute.", + "Please enter a valid date for the :attribute.": "Please enter a valid date for the :attribute.", "Please enter a valid website link under “Accessibility and Inclusion links”.": "Please enter a valid website link under “Accessibility and Inclusion links”.", "Please enter the email address of the individual you have hired as a Community Connector.": "Please enter the email address of the individual you have hired as a Community Connector.", "Please enter your collaboration preferences": "Please enter your collaboration preferences", @@ -1407,6 +1423,9 @@ "Please review and update your public page": "Please review and update your public page", "Please review your page. There is some information for your new role that you will have to fill in.": "Please review your page. There is some information for your new role that you will have to fill in.", "Please see the resource [Planning a Safe, Accessible Consultation](:url).": "Please see the resource [Planning a Safe, Accessible Consultation](:url).", + "Please select a language.": "Please select a language.", + "Please select a language that the engagement documents will be in.": "Please select a language that the engagement documents will be in.", + "Please select a language to remove.": "Please select a language to remove.", "Please select a recruitment method": "Please select a recruitment method", "Please select disability groups that your organization specifically represents": "Please select disability groups that your organization specifically represents", "Please select the disability and\/or Deaf groups that you can connect to.": "Please select the disability and\/or Deaf groups that you can connect to.", @@ -1672,7 +1691,6 @@ "Send invitation": "Send invitation", "Send request": "Send request", "Send the estimate and agreement to <:contact>.": "Send the estimate and agreement to <:contact>.", - "sent by date": "sent by date", "serve and support": "serve and support", "serves and supports": "serves and supports", "Service areas": "Service areas", @@ -1803,7 +1821,11 @@ "Text": "Text", "Text message": "Text message", "Text to speech": "Text to speech", + "The :attribute format is not valid.": "The :attribute format is not valid.", "The :attribute is not in the right format.": "The :attribute is not in the right format.", + "The :attribute must be after the :date.": "The :attribute must be after the :date.", + "The :attribute must be a number.": "The :attribute must be a number.", + "The :attribute must be before the :date.": "The :attribute must be before the :date.", "The :projectable sends out a list of questions, and you can can respond to them at your own pace.": "The :projectable sends out a list of questions, and you can can respond to them at your own pace.", "The Accessibility Exchange": "The Accessibility Exchange", "The Accessibility Exchange will send you notifications, based on what you chose to be notified of here.": "The Accessibility Exchange will send you notifications, based on what you chose to be notified of here.", @@ -1830,11 +1852,11 @@ "Theme": "Theme", "themes": "themes", "Themes": "Themes", - "The minimum number of participants is more than the ideal number of participants. Please enter a minimum that is less than or the same as the ideal number of participants.": "The minimum number of participants is more than the ideal number of participants. Please enter a minimum that is less than or the same as the ideal number of participants.", "The notification has been marked as read.": "The notification has been marked as read.", "the number of people on your team": "the number of people on your team", "The organization you have added does not participate in engagements.": "The organization you have added does not participate in engagements.", - "The other accepted format must be provided in at least one language.": "The other accepted format must be provided in at least one language.", + "The other accepted format must be a string.": "The other accepted format must be a string.", + "The other accepted format must be provided in at least English or French.": "The other accepted format must be provided in at least English or French.", "the other languages are you able to work in": "the other languages are you able to work in", "the other languages you are able to work in": "the other languages you are able to work in", "The other payment type must be specified.": "The other payment type must be specified.", @@ -1848,6 +1870,7 @@ "These are the seven areas listed within the Accessible Canada Act. By law, entities must ensure these areas are accessible.": "These are the seven areas listed within the Accessible Canada Act. By law, entities must ensure these areas are accessible.", "These are the seven areas listed within the Accessible Canada Act. Federally regulated organizations must work to improve their accessibility in all of these areas.": "These are the seven areas listed within the Accessible Canada Act. Federally regulated organizations must work to improve their accessibility in all of these areas.", "These details will help people know what to expect when working with you.": "These details will help people know what to expect when working with you.", + "The selected consulting service is invalid": "The selected consulting service is invalid", "The selected working language is not valid.": "The selected working language is not valid.", "These organizations, coalitions, cross-disability or umbrella groups are made up of, and controlled by, persons with disabilities, Deaf persons, and\/or their family members. These organizations were created to advance and defend the rights of persons with disabilities.": "These organizations, coalitions, cross-disability or umbrella groups are made up of, and controlled by, persons with disabilities, Deaf persons, and\/or their family members. These organizations were created to advance and defend the rights of persons with disabilities.", "These organizations have constituencies which include persons with disabilities, Deaf persons, and family members. Disability and Deaf services are not the primary mandate of these organizations. ": "These organizations have constituencies which include persons with disabilities, Deaf persons, and family members. Disability and Deaf services are not the primary mandate of these organizations. ", @@ -1856,6 +1879,7 @@ "The suspension of :account and its users has been lifted.": "The suspension of :account and its users has been lifted.", "The suspension of :account has been lifted.": "The suspension of :account has been lifted.", "The type of disability they experience": "The type of disability they experience", + "The user’s role is missing.": "The user’s role is missing.", "They have been instructed to send their signed agreement to <:email>.": "They have been instructed to send their signed agreement to <:email>.", "They require Video Relay Service (VRS) for phone calls": "They require Video Relay Service (VRS) for phone calls", "They will not be able to:": "They will not be able to:", @@ -1897,13 +1921,14 @@ "This is the name that will be displayed on your page. This does not have to be your legal name.": "This is the name that will be displayed on your page. This does not have to be your legal name.", "This is the name that will be displayed on your project page.": "This is the name that will be displayed on your project page.", "This is the name that will show up publicly on your page.": "This is the name that will show up publicly on your page.", + "This member already belongs to this organization.": "This member already belongs to this organization.", + "This member has already been invited.": "This member has already been invited.", "This organization has already been invited.": "This organization has already been invited.", "This organization has people on staff who have lived experience of the communities they :represent_or_serve_and_support.": "This organization has people on staff who have lived experience of the communities they :represent_or_serve_and_support.", "This site is for three kinds of users. Select an option below to learn more.": "This site is for three kinds of users. Select an option below to learn more.", "This site uses cookies to help provide a better experience.": "This site uses cookies to help provide a better experience.", "This survey will be provided in the following digital formats:": "This survey will be provided in the following digital formats:", "This survey will be provided in the following formats:": "This survey will be provided in the following formats:", - "This user already belongs to this team.": "This user already belongs to this team.", "This website was made in partnership with members and organizations from the disability and Deaf communities, supporters, and members from Federally Regulated Organizations.": "This website was made in partnership with members and organizations from the disability and Deaf communities, supporters, and members from Federally Regulated Organizations.", "This will help governments and businesses communicate and work with you in a format that is accessible to you.": "This will help governments and businesses communicate and work with you in a format that is accessible to you.", "This will help people know what to expect when working with you.": "This will help people know what to expect when working with you.", @@ -2290,12 +2315,17 @@ "You must choose at least one type of federally regulated organization.": "You must choose at least one type of federally regulated organization.", "You must choose at least one type of organization.": "You must choose at least one type of organization.", "You must choose at least one type of project.": "You must choose at least one type of project.", + "You must choose a valid province or territory": "You must choose a valid province or territory", + "You must enter a :attribute": "You must enter a :attribute", + "You must enter a :attribute.": "You must enter a :attribute.", "You must enter a :attribute for the meeting location.": "You must enter a :attribute for the meeting location.", "You must enter a city or town.": "You must enter a city or town.", "You must enter an email address.": "You must enter an email address.", "You must enter a province or territory.": "You must enter a province or territory.", "You must enter at least one city or town.": "You must enter at least one city or town.", + "You must enter a valid link for :key.": "You must enter a valid link for :key.", "You must enter a valid website address for :key.": "You must enter a valid website address for :key.", + "You must enter a valid website link.": "You must enter a valid website link.", "You must enter your organization's name in either English or French.": "You must enter your organization's name in either English or French.", "You must enter your organization name.": "You must enter your organization name.", "You must enter your organization name in either English or French.": "You must enter your organization name in either English or French.", @@ -2307,14 +2337,12 @@ "You must indicate the :attribute.": "You must indicate the :attribute.", "You must indicate who you want to engage.": "You must indicate who you want to engage.", "You must pick at least one of these roles.": "You must pick at least one of these roles.", - "You must provide a :attribute.": "You must provide a :attribute.", "You must select a language.": "You must select a language.", "You must select a role for your organization.": "You must select a role for your organization.", "You must select at least one age group you can connect to.": "You must select at least one age group you can connect to.", "You must select at least one age group your organization specifically :represents_or_serves_and_supports.": "You must select at least one age group your organization specifically :represents_or_serves_and_supports.", "You must select at least one ethno-racial identity you can connect to.": "You must select at least one ethno-racial identity you can connect to.", "You must select at least one ethno-racial identity your organization specifically :represents_or_serves_and_supports.": "You must select at least one ethno-racial identity your organization specifically :represents_or_serves_and_supports.", - "You must select at least one gender or sexual identity group.": "You must select at least one gender or sexual identity group.", "You must select at least one gender or sexual identity group you can connect to.": "You must select at least one gender or sexual identity group you can connect to.", "You must select at least one gender or sexual identity group your organization specifically :represents_or_serves_and_supports.": "You must select at least one gender or sexual identity group your organization specifically :represents_or_serves_and_supports.", "You must select at least one Indigenous group you can connect to.": "You must select at least one Indigenous group you can connect to.", @@ -2323,6 +2351,11 @@ "You must select at least one option for “Can you connect to people with disabilities, Deaf persons, and\/or their supporters?”": "You must select at least one option for “Can you connect to people with disabilities, Deaf persons, and\/or their supporters?”", "You must select at least one option for “Where do the people that you :represent_or_serve_and_support come from?”": "You must select at least one option for “Where do the people that you :represent_or_serve_and_support come from?”", "You must select at least one option for “Where do the people that you can connect to come from?”": "You must select at least one option for “Where do the people that you can connect to come from?”", + "You must select at least one way to attend the meeting.": "You must select at least one way to attend the meeting.", + "You must select a valid :attribute.": "You must select a valid :attribute.", + "You must select a valid format.": "You must select a valid format.", + "You must select a valid meeting type.": "You must select a valid meeting type.", + "You must select a valid role to perform on the website.": "You must select a valid role to perform on the website.", "You must select one option for “Can you connect to a specific age group or groups?”": "You must select one option for “Can you connect to a specific age group or groups?”", "You must select one option for “Can you connect to people who are First Nations, Inuit, or Métis?”": "You must select one option for “Can you connect to people who are First Nations, Inuit, or Métis?”", "You must select one option for “Can you connect to people who are marginalized based on gender or sexual identity?”": "You must select one option for “Can you connect to people who are marginalized based on gender or sexual identity?”", @@ -2364,6 +2397,7 @@ "Your agreement has been received for :project. You can now publish your project page and engagement details. Sign in to your account at https:\/\/accessibilityexchange.ca to continue.": "Your agreement has been received for :project. You can now publish your project page and engagement details. Sign in to your account at https:\/\/accessibilityexchange.ca to continue.", "Your areas of interest have been updated.": "Your areas of interest have been updated.", "Your bio": "Your bio", + "Your bio must be provided in at least English or French.": "Your bio must be provided in at least English or French.", "Your communication and consultation preferences have been updated.": "Your communication and consultation preferences have been updated.", "Your Community Connector has been removed.": "Your Community Connector has been removed.", "Your consultation preferences": "Your consultation preferences", @@ -2418,6 +2452,7 @@ "Your project has been created.": "Your project has been created.", "Your project has been deleted.": "Your project has been deleted.", "Your projects and engagements": "Your projects and engagements", + "Your pronouns must be provided in at least English or French.": "Your pronouns must be provided in at least English or French.", "your public profile will be removed from the platform": "your public profile will be removed from the platform", "your public profile will be removed from the website": "your public profile will be removed from the website", "Your regulated organization, :name, will be deleted and cannot be recovered. If you still want to delete your regulated organization, please enter your current password to proceed.": "Your regulated organization, :name, will be deleted and cannot be recovered. If you still want to delete your regulated organization, please enter your current password to proceed.", diff --git a/resources/lang/en/invitation.php b/resources/lang/en/invitation.php index a3493207d..f52e03e3f 100644 --- a/resources/lang/en/invitation.php +++ b/resources/lang/en/invitation.php @@ -7,8 +7,8 @@ 'cancel_member_invitation_link' => 'Cancel invitation', 'cancel_member_invitation_link_with_email' => 'Cancel invitation for :email', 'create_invitation_succeeded' => 'Your invitation has been sent.', - 'invited_user_already_belongs_to_a_team' => 'This user already belongs to a team.', - 'invited_user_already_belongs_to_this_team' => 'This user already belongs to this team.', + 'invited_user_already_belongs_to_a_team' => 'The person you invited is already a member of another organization.', + 'invited_user_already_belongs_to_this_team' => 'The person you invited is already a member of this organization.', 'cancel_invitation_succeeded' => 'The invitation has been cancelled.', 'email_not_valid' => 'You are logged in as :email, but this invitation is for a different email address.', 'accept_invitation_succeeded' => 'You have joined the :invitationable team.', diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php index 0e8247d5c..aee77eee2 100644 --- a/resources/lang/en/validation.php +++ b/resources/lang/en/validation.php @@ -96,16 +96,18 @@ 'not_regex' => 'The :attribute format is invalid.', 'numeric' => 'The :attribute must be a number.', 'password' => 'The password is incorrect.', + 'postal_code' => 'You must enter a valid Canadian postal code.', 'present' => 'The :attribute field must be present.', 'regex' => 'The :attribute format is invalid.', 'required' => 'You must enter your :attribute.', + 'required_array_keys' => 'The :attribute must contain values for :values', 'required_if' => 'The :attribute field is required when :other is :value.', 'required_unless' => 'The :attribute field is required unless :other is in :values.', 'required_with' => 'The :attribute field is required when :values is present.', 'required_with_all' => 'The :attribute field is required when :values are present.', 'required_without' => 'The :attribute field is required when :values is not present.', 'required_without_all' => 'The :attribute field is required when none of :values are present.', - 'phone' => 'The :attribute is not a valid phone number.', + 'phone' => 'The :attribute is not a valid number.', 'prohibits' => 'The :attribute field is prohibited when :other is present.', 'prohibited' => 'The :attribute field is prohibited.', 'prohibited_if' => 'The :attribute field is prohibited when :other is :value.', @@ -122,7 +124,7 @@ 'timezone' => 'The :attribute must be a valid zone.', 'unique' => 'The :attribute has already been taken.', 'uploaded' => 'The :attribute failed to upload.', - 'url' => 'The :attribute format is invalid.', + 'url' => 'The :attribute is invalid.', 'uuid' => 'The :attribute must be a valid UUID.', /* diff --git a/resources/lang/fr.json b/resources/lang/fr.json index 7176522f1..442138e02 100644 --- a/resources/lang/fr.json +++ b/resources/lang/fr.json @@ -224,6 +224,7 @@ "After the consultation follow up with participants to share next steps and your organization’s plan for implementing their feedback. This can help foster confidence in your commitment, and an ongoing relationship with your participants, who can be involved in future updates of your accessibility plan.": "Après la consultation, assurez un suivi auprès des personnes participantes pour leur faire part des prochaines étapes et du plan de votre organisation pour mettre en œuvre leurs commentaires. Cela peut contribuer à renforcer la confiance envers votre initiative et à établir une relation durable avec vos participants, lesquels pourraient éventuellement participer aux futures mises à jour de votre plan d'accessibilité.", "Age": "Âge", "Age group": "Groupe d'âge", + "age group": "", "Age groups": "Groupes d'âge", "Age groups they can connect to": "Tranches d'âge auprès desquelles vous pouvez agir comme intermédiaire", "Agreement pending": "Entente en attente", @@ -240,14 +241,15 @@ "All the training I am doing or have done.": "Toutes les formations que je fais ou que j'ai faites.", "Alternative text for images": "Texte de remplacement pour les images", "Although it is not compulsory, we highly recommend that you include English and French translations of your content.": "Although it is not compulsory, we highly recommend that you include English and French translations of your content.", - "A meeting title must be provided in at least one language.": "Un titre de réunion doit être fourni dans au moins une langue.", + "A meeting title must be provided in at least English or French.": "", "American Sign Language (ASL)": "American Sign Language (ASL)", "Analysis of collected information": "Analyse des informations recueillies", "Analyze the outcomes of your consultation with people who are in the context of disability and Deaf groups.": "Analyser les résultats de votre consultation avec des personnes faisant partie de groupes de personnes en situation de handicap et de personnes sourdes.", "An approximate response time must be provided in at least one language.": "Un temps de réponse approximatif doit être indiqué dans au moins une langue.", - "An engagement description must be provided in at least one language.": "Une description de la consultation doit être fournie dans au moins une langue.", + "An engagement description must be provided in at least English or French.": "", "An engagement involves a group of people participating in one set way (for example, a focus group or a survey). An engagement like a focus group can have multiple meetings.": "Une consultation implique un groupe de personnes participant d'une manière donnée (par exemple, un groupe de discussion ou un sondage). Une consultation, comme un groupe de discussion, peut se dérouler sur plusieurs réunions.", "An engagement involves a group of people participating in one set way (for example, a focus group or survey).": "Une consultation implique un groupe de personnes participant d'une manière donnée (par exemple, un groupe de discussion ou un sondage).", + "An engagement name must be provided in at least English or French.": "", "An engagement name must be provided in at least one language.": "Le nom de la consultation doit être fourni dans au moins une langue.", "An engagement with this name already exists.": "Une consultation avec ce nom existe déjà.", "a network and is able to conduct effective outreach to people with disabilities and Deaf persons in particular geographic communities and social groups (for example, Indigenous communities).": "un réseau et est capable de mener des actions de sensibilisation efficaces auprès des personnes en situation de handicap et des personnes sourdes dans des communautés géographiques et des groupes particuliers (par exemple, les communautés autochtones).", @@ -278,6 +280,7 @@ "Areas of interest": "Domaines d'intérêt", "Areas of your organization this project will impact": "Secteurs de votre organisation sur lesquels ce projet aura un impact", "Areas where the organization serves": "Régions où l'organisation est active", + "area type": "", "Are you able to attend consultations in real-time, or do you prefer to receive the materials (ex. questions, discussion topics) and record your responses at your own pace?": "Êtes-vous en mesure d'assister aux consultations en temps réel, ou préférez-vous recevoir le matériel (ex. questions, sujets de discussion) et enregistrer vos réponses à votre propre rythme ?", "Are you looking for individuals in specific provinces or territories or specific cities or towns?": "Cherchez-vous des personnes dans des provinces ou territoires spécifiques ou dans des villes ou villages spécifiques ?", "Are you sure you want to block :blockable?": "Voulez-vous vraiment bloquer :blockable?", @@ -564,6 +567,7 @@ "Date": "Date", "Date added": "Date ajoutée", "Date created": "Date de création", + "date for materials to be sent by": "", "Date of training": "Date de la formation", "Date range": "Plage de dates", "Dates": "Dates", @@ -715,6 +719,7 @@ "Estimates and agreements": "Devis et ententes", "Estimate status": "Statut du devis", "Ethno-racial groups": "Communautés ethniques et racisées", + "ethnoracial group": "", "Ethnoracial group they can connect to": "Communautés ethniques et racisées auprès desquelles ils peuvent servir d'intermédiaire", "Ethnoracial identity": "Identité ethnoraciale", "ethnoracial identity": "identité ethnoraciale", @@ -746,6 +751,7 @@ "Find learning materials, best practices, and variety of tools to help you throughout the consultation process.": "Supports d'apprentissage, meilleures pratiques et une variété d'outils pour vous aider tout au long du processus de consultation.", "Find people with disabilities, Deaf people and community organizations (for example, disability or other relevant civil society organizations, like Indigenous groups), to consult with on your accessibility project.": "Trouvez des personnes en situation de handicap, des personnes sourdes et des organisations communautaires (par exemple, des organisations de personnes en situation de handicap ou d'autres organisations pertinentes de la société civile, comme les groupes autochtones), à consulter dans le cadre de votre projet en matière d'accessibilité.", "First language": "Première langue", + "first language": "", "First Nations": "Premières Nations", "flexible, please contact us if you need to use another software": "flexible, veuillez nous contacter si vous souhaitez utiliser un autre logiciel", "Focus group": "Groupe de discussion", @@ -799,6 +805,7 @@ "Gender neutral, barrier-free washrooms": "Toilettes mixtes et accessibles", "Gender neutral washroom": "Salle de bain non genrée", "Gender non-conforming people": "Personnes non-conformes au genre", + "gender or sexual identity group": "", "GENERAL": "DISPOSITIONS GÉNÉRALES", "General": "Général", "General access needs": "Besoins généraux en matière d'accessibilité", @@ -882,6 +889,7 @@ "Ideally, an Accessibility Consultant has:": "Dans l'idéal, une personne consultante en matière d'accessibilité possède :", "Ideally a Community Connector has:": "Dans l'idéal, une personne facilitatrice communautaire possède :", "Ideal number of participants": "Nombre idéal de personnes participantes", + "ideal number of participants": "", "Identities": "Identités", "If anything about your projects or engagements have changed, please send a new estimate request.": "Si un élément de vos projets ou consultations a changé, veuillez envoyer une nouvelle demande de devis.", "If a Sign Language video translation is available, you will see a button in line with the website content. Pressing that button will load the Sign Language video.": "Si une traduction vidéo en langue des signes est disponible, vous verrez un bouton en ligne avec le contenu du site Internet. En appuyant sur ce bouton, la vidéo en langue des signes sera chargée.", @@ -891,6 +899,9 @@ "if the provision of the Platform to you by IRIS is, in IRIS’ opinion, no longer commercially or financially viable.": "if the provision of the Platform to you by IRIS is, in IRIS’ opinion, no longer commercially or financially viable.", "If you already have an account, please [sign in](:url).": "Si vous avez déjà un compte, veuillez [vous identifier](:url).", "IF YOU ARE DISSATISFIED WITH ANY PORTION OF THE PLATFORM OR WITH THESE TERMS OF SERVICE, YOUR SOLE AND EXCLUSIVE REMEDY IS TO DISCONTINUE USE OF THE PLATFORM.": "IF YOU ARE DISSATISFIED WITH ANY PORTION OF THE PLATFORM OR WITH THESE TERMS OF SERVICE, YOUR SOLE AND EXCLUSIVE REMEDY IS TO DISCONTINUE USE OF THE PLATFORM.", + "If you are interested in engaging a specific :attribute, you must select at least one.": "", + "If you are looking for a group with a specific experience or identity, you must select which type of experience or identity you are looking for.": "", + "If you are looking for a specific :attribute, you must select at least one.": "", "If you are seeking a Community Connector for this engagement, there are a few ways to find one:": "Si vous recherchez une personne facilitatrice communautaire pour cette consultation, plusieurs moyens s'offrent à vous :", "If you are thinking of working with a specific group, for example, Indigenous people with disabilities, it would be a good idea to hire an Accessibility Consultant from that community.": "Si vous envisagez de travailler avec un groupe spécifique, par exemple, des personnes en situation de handicap issues de communautés autochtones, il pourrait être avantageux d'engager une personne consultante en matière d'accessibilité issue de cette communauté.", "If you delete your account:": "Si vous supprimez votre compte :", @@ -918,6 +929,7 @@ "Incomplete": "", "INDEMNITY AND RELEASE.": "INDEMNITY AND RELEASE.", "Indigenous": "Autochtone", + "Indigenous group": "", "Indigenous identity": "Indigenous identity", "Individual": "Individu", "individual": "individu", @@ -1075,7 +1087,6 @@ "Meeting date :date": "Date de la réunion :date", "Meeting dates": "Dates de réunion", "meeting end time": "heure de fin de la réunion", - "meeting phone number": "numéro de téléphone de la réunion", "Meetings": "Réunions", "meeting start time": "heure de début de la réunion", "meeting time zone": "fuseau horaire de la réunion", @@ -1089,6 +1100,7 @@ "Microsoft Word": "Microsoft Word", "Middle Eastern": "Moyen-oriental", "Minimum number of participants": "Nombre minimum de personnes participantes", + "minimum number of participants": "", "Missing an engagement?": "Manque-t-il une consultation?", "modify, copy, reproduce, reverse engineer, frame, rent, lease, loan, sell, distribute, publish, or create derivative works based on the Platform or the Service Content (as defined below), in whole or in part;": "modify, copy, reproduce, reverse engineer, frame, rent, lease, loan, sell, distribute, publish, or create derivative works based on the Platform or the Service Content (as defined below), in whole or in part;", "Module - :title": "Module - :title", @@ -1159,6 +1171,7 @@ "No interests listed.": "Aucun intérêt répertorié.", "No meetings found.": "Aucune réunion trouvée.", "Non-binary, gender non-conforming and\/or gender fluid people": "Personnes non-binaires, non-conformes au genre et\/ou fluides de genre", + "Non-binary\/Gender non-conforming\/Gender fluid identity": "", "Non-binary people": "Personnes non-binaires", "None found.": "Rien n'a été trouvé.", "None listed": "Aucun listé", @@ -1229,7 +1242,6 @@ "Once you sign up, you can sign up for an orientation session to learn about what you can do on this website. You can also fill in information to facilitate a smoother collaboration with organizations, such as access needs, communication preferences, and consultation preferences.": "Une fois inscrit, vous pouvez vous inscrire à une séance d'orientation pour découvrir ce que vous pouvez faire sur ce site. Vous pouvez également remplir des informations destinées à rendre la collaboration avec les organisations plus harmonieuse, telles que vos besoins en matière d'accessibilité, vos préférences en ce qui concerne les communications ou encore les consultations.", "Once you’ve reviewed the project details, please:": "Une fois que vous aurez revu les détails du projet, veuillez :", "One of the key parts of preparing for your consultation with the disability and Deaf communities is making sure that your consultations are done in an accessible and inclusive way.": "L'un des éléments clés de la préparation de votre consultation avec les communautés de personnes en situation de handicap et de personnes sourdes est de s'assurer que vos consultations se déroulent d'une manière accessible et inclusive.", - "One or more Disability or Deaf groups are required.": "One or more Disability or Deaf groups are required.", "Online form, such as survey monkey or google forms": "Formulaire en ligne, tel que SurveyMonkey ou Google Forms", "Only people with specific disabilities and\/or Deaf people": "Personnes ayant des handicaps spécifiques et\/ou personnes sourdes", "Only reachable within cross-disability and Deaf or intersectional groups": "Only reachable within cross-disability and Deaf or intersectional groups", @@ -1327,6 +1339,7 @@ "phone number": "numéro de téléphone", "Phone number:": "Numéro de téléphone :", "Phone number to join": "Numéro de téléphone à rejoindre", + "phone number to join the meeting": "", "Physical and mobility disabilities": "Déficience physique et de mobilité", "Plain language": "Langage simple", "Plan and share your project with others on this website.": "Planifiez et partagez votre projet avec d'autres personnes sur ce site Internet.", @@ -1356,7 +1369,10 @@ "Please create your profile to share more about who you are, your experiences, and your interests.": "Veuillez créer votre profil pour en dire plus sur qui vous êtes, vos expériences et vos intérêts.", "Please describe how the Disability and Deaf communities will be impacted by the outcomes of your project.": "Veuillez décrire comment les communautés des personnes en situation de handicap et des personnes sourdes seront touchées par les résultats de votre projet.", "Please describe this engagement.": "Veuillez décrire cette consultation.", + "Please enter a :attribute that is less than or the same as the ideal number of participants.": "", "Please enter an end year for your experience that is equal to or greater than the start year.": "Please enter an end year for your experience that is equal to or greater than the start year.", + "Please enter a valid :attribute.": "", + "Please enter a valid date for the :attribute.": "", "Please enter a valid website link under “Accessibility and Inclusion links”.": "Veuillez saisir un lien Internet valide sous \"Liens en lien avec l'accessibilité et l'inclusion\".", "Please enter the email address of the individual you have hired as a Community Connector.": "Veuillez entrer l'adresse courriel de la personne que vous avez embauchée en tant que personne facilitatrice communautaire.", "Please enter your collaboration preferences": "Veuillez entrer vos préférences de collaboration", @@ -1407,6 +1423,9 @@ "Please review and update your public page": "Veuillez réviser et mettre à jour votre page publique", "Please review your page. There is some information for your new role that you will have to fill in.": "Merci de vérifier l'information présentée sur cette page. De l'information sur les nouveaux rôles que vous avez sélectionnés est disponible.", "Please see the resource [Planning a Safe, Accessible Consultation](:url).": "Veuillez consulter la ressource [Planification d'une consultation sûre et accessible](:url).", + "Please select a language.": "", + "Please select a language that the engagement documents will be in.": "", + "Please select a language to remove.": "", "Please select a recruitment method": "Veuillez sélectionner une méthode de recrutement", "Please select disability groups that your organization specifically represents": "Veuillez sélectionner les groupes de personnes en situation de handicap que votre organisation représente spécifiquement", "Please select the disability and\/or Deaf groups that you can connect to.": "Veuillez sélectionner les groupes de personnes en situation de handicap et\/ou de personnes sourdes auprès desquels vous pouvez agir comme intermédiaire.", @@ -1672,7 +1691,6 @@ "Send invitation": "Envoyer l'invitation", "Send request": "Envoyer la demande", "Send the estimate and agreement to <:contact>.": "Envoyez le devis et l'entente à <:contact>.", - "sent by date": "envoyé par date", "serve and support": "servir et soutenir", "serves and supports": "sert et soutien", "Service areas": "Régions desservies", @@ -1803,7 +1821,11 @@ "Text": "Texte", "Text message": "Message texte", "Text to speech": "Synthèse vocale", + "The :attribute format is not valid.": "", "The :attribute is not in the right format.": "Le champ :attribute n'est pas au bon format.", + "The :attribute must be after the :date.": "", + "The :attribute must be a number.": "", + "The :attribute must be before the :date.": "", "The :projectable sends out a list of questions, and you can can respond to them at your own pace.": "Dans ce cas, l':projectable vous enverra une liste de questions et vous pourrez y répondre à votre propre rythme.", "The Accessibility Exchange": "Connecteur pour l’accessibilité", "The Accessibility Exchange will send you notifications, based on what you chose to be notified of here.": "Le Connecteur pour l'accessibilité vous enverra des notifications, en fonction de ce que vous avez choisi de recevoir ici.", @@ -1830,11 +1852,11 @@ "Theme": "Thème", "themes": "thèmes", "Themes": "Thèmes", - "The minimum number of participants is more than the ideal number of participants. Please enter a minimum that is less than or the same as the ideal number of participants.": "Le nombre minimum de personnes participantes est supérieur au nombre idéal de personnes participantes. Veuillez saisir un minimum inférieur ou égal au nombre idéal de personnes participantes.", "The notification has been marked as read.": "La notification a été marquée comme lue.", "the number of people on your team": "the number of people on your team", "The organization you have added does not participate in engagements.": "L'organisation que vous avez ajoutée ne désire pas participer à des consultations.", - "The other accepted format must be provided in at least one language.": "L'autre format accepté doit être fourni dans au moins une langue.", + "The other accepted format must be a string.": "", + "The other accepted format must be provided in at least English or French.": "", "the other languages are you able to work in": "les autres langues dans lesquelles vous êtes capable de travailler", "the other languages you are able to work in": "les autres langues dans lesquelles vous êtes capable de travailler", "The other payment type must be specified.": "Vous devez spécifier l'autre type de paiement.", @@ -1848,6 +1870,7 @@ "These are the seven areas listed within the Accessible Canada Act. By law, entities must ensure these areas are accessible.": "Ces sept domaines sont énumérés dans la Loi canadienne sur l'accessibilité. En vertu de la loi, les entités doivent s'assurer que ces domaines sont accessibles.", "These are the seven areas listed within the Accessible Canada Act. Federally regulated organizations must work to improve their accessibility in all of these areas.": "Ces sept domaines sont énumérés dans la Loi canadienne sur l'accessibilité. En vertu de la loi, les organisations sous réglementation fédérale doivent s'assurer que ces domaines sont accessibles.", "These details will help people know what to expect when working with you.": "Ces détails aideront les gens à savoir à quoi s'attendre lorsqu'ils travaillent avec vous.", + "The selected consulting service is invalid": "", "The selected working language is not valid.": "La langue de travail sélectionnée n'est pas valide.", "These organizations, coalitions, cross-disability or umbrella groups are made up of, and controlled by, persons with disabilities, Deaf persons, and\/or their family members. These organizations were created to advance and defend the rights of persons with disabilities.": "Ces organisations, coalitions, groupes multi-handicap ou parapluies sont constitués et contrôlés par des personnes en situation de handicap, des personnes sourdes et\/ou des membres de leur famille. Ces organisations ont été créées pour faire avancer et défendre les droits des personnes en situation de handicap.", "These organizations have constituencies which include persons with disabilities, Deaf persons, and family members. Disability and Deaf services are not the primary mandate of these organizations. ": "Ces organisations comptent parmi leurs membres des personnes en situation de handicap, des personnes sourdes et des membres de leur famille. Les services aux personnes en situation de handicap et aux personnes sourdes ne constituent pas le mandat principal de ces organisations. ", @@ -1856,6 +1879,7 @@ "The suspension of :account and its users has been lifted.": "The suspension of :account and its users has been lifted.", "The suspension of :account has been lifted.": "The suspension of :account has been lifted.", "The type of disability they experience": "Le type de handicap vécu", + "The user’s role is missing.": "", "They have been instructed to send their signed agreement to <:email>.": "Ils ont été priés d'envoyer leur accord signé à <:email>.", "They require Video Relay Service (VRS) for phone calls": "Cette personne a besoin du service de relais vidéo (SRV) pour les appels téléphoniques", "They will not be able to:": "Ils ne seront pas en mesure de faire les choses suivantes :", @@ -1897,13 +1921,14 @@ "This is the name that will be displayed on your page. This does not have to be your legal name.": "Il s'agit du nom qui sera affiché sur votre page. Il peut être différent de votre nom légal.", "This is the name that will be displayed on your project page.": "Il s'agit du nom qui sera affiché sur la page de votre projet.", "This is the name that will show up publicly on your page.": "Il s'agit du nom qui apparaîtra publiquement sur votre page.", + "This member already belongs to this organization.": "", + "This member has already been invited.": "", "This organization has already been invited.": "Cette organisation a déjà été invitée.", "This organization has people on staff who have lived experience of the communities they :represent_or_serve_and_support.": "Cette organisation compte parmi son personnel des personnes ayant une expérience vécue des communautés qu'elle :represent_or_serve_and_support.", "This site is for three kinds of users. Select an option below to learn more.": "Ce site s'adresse à trois types de publics. Sélectionnez une option ci-dessous pour en savoir plus.", "This site uses cookies to help provide a better experience.": "This site uses cookies to help provide a better experience.", "This survey will be provided in the following digital formats:": "Ce sondage sera fourni dans les formats numériques suivants :", "This survey will be provided in the following formats:": "Ce sondage sera fourni dans les formats suivants :", - "This user already belongs to this team.": "Cette personne fait déjà partie de cette équipe.", "This website was made in partnership with members and organizations from the disability and Deaf communities, supporters, and members from Federally Regulated Organizations.": "Ce site Internet a été conçu en partenariat avec des membres et des organisations de la communauté des personnes en situation de handicap et des personnes sourdes, de leurs alliés et des membres d'organisations sous réglementation fédérale.", "This will help governments and businesses communicate and work with you in a format that is accessible to you.": "Cela aidera les gouvernements et les entreprises à communiquer et à travailler avec vous dans un format qui vous est accessible.", "This will help people know what to expect when working with you.": "Cela permettra aux gens de savoir à quoi s'attendre lorsqu'ils travaillent avec vous.", @@ -2290,12 +2315,17 @@ "You must choose at least one type of federally regulated organization.": "Vous devez choisir au moins un type d'organisation sous réglementation fédérale.", "You must choose at least one type of organization.": "Vous devez choisir au moins un type d'organisation.", "You must choose at least one type of project.": "Vous devez choisir au moins un type de projet.", + "You must choose a valid province or territory": "", + "You must enter a :attribute": "", + "You must enter a :attribute.": "", "You must enter a :attribute for the meeting location.": "Vous devez saisir un\/une :attribute pour le lieu de la réunion.", "You must enter a city or town.": "Vous devez indiquer une ville ou un village.", "You must enter an email address.": "Vous devez saisir une adresse courriel.", "You must enter a province or territory.": "Vous devez indiquer une province ou un territoire.", "You must enter at least one city or town.": "Vous devez indiquer au moins une ville ou un village.", + "You must enter a valid link for :key.": "", "You must enter a valid website address for :key.": "Vous devez indiquer une adresse valide pour :key.", + "You must enter a valid website link.": "", "You must enter your organization's name in either English or French.": "Vous devez saisir le nom de votre organisation en anglais ou en français.", "You must enter your organization name.": "Vous devez saisir le nom de votre organisation.", "You must enter your organization name in either English or French.": "Vous devez saisir le nom de votre organisation en anglais ou en français.", @@ -2307,14 +2337,12 @@ "You must indicate the :attribute.": "Vous devez indiquer l'attribut :attribute.", "You must indicate who you want to engage.": "Vous devez indiquer qui vous voulez impliquer.", "You must pick at least one of these roles.": "Vous devez choisir au moins un de ces rôles.", - "You must provide a :attribute.": "Vous devez fournir un :attribute.", "You must select a language.": "Vous devez sélectionner une langue.", "You must select a role for your organization.": "Vous devez sélectionner un rôle pour votre organisation.", "You must select at least one age group you can connect to.": "Vous devez sélectionner au moins un groupe d'âge auprès duquel vous pouvez servir d'intermédiaire.", "You must select at least one age group your organization specifically :represents_or_serves_and_supports.": "Vous devez sélectionner au moins un groupe d'âge que votre organisation :represents_or_serves_and_supports spécifiquement.", "You must select at least one ethno-racial identity you can connect to.": "Vous devez sélectionner au moins une identité ethnoraciale auprès de laquelle vous pouvez servir d'intermédiaire.", "You must select at least one ethno-racial identity your organization specifically :represents_or_serves_and_supports.": "Vous devez sélectionner au moins une identité ethnoraciale spécifique que votre organisation :represents_or_serves_and_supports.", - "You must select at least one gender or sexual identity group.": "Vous devez sélectionner au moins un groupe relatif au genre ou à l'identité sexuelle.", "You must select at least one gender or sexual identity group you can connect to.": "Vous devez sélectionner au moins un groupe d'identité sexuelle ou de genre auprès duquel vous pouvez servir d'intermédiaire.", "You must select at least one gender or sexual identity group your organization specifically :represents_or_serves_and_supports.": "Vous devez sélectionner au moins un groupe d'identité sexuelle ou de genre que votre organisation :represents_or_serves_and_supports.", "You must select at least one Indigenous group you can connect to.": "Vous devez sélectionner au moins un groupe autochtone auprès duquel vous pouvez servir d'intermédiaire.", @@ -2323,6 +2351,11 @@ "You must select at least one option for “Can you connect to people with disabilities, Deaf persons, and\/or their supporters?”": "Vous devez sélectionner au moins une option pour \"Pouvez-vous servir d'intermédiaire auprès des personnes en situation de handicap, des personnes sourdes et\/ou leurs alliés?\"", "You must select at least one option for “Where do the people that you :represent_or_serve_and_support come from?”": "Vous devez sélectionner au moins une option pour « D'où viennent les personnes que vous représentez »", "You must select at least one option for “Where do the people that you can connect to come from?”": "Vous devez sélectionner au moins une option pour « D'où viennent les personnes auprès desquelles vous pouvez servir d'intermédiaire ? »", + "You must select at least one way to attend the meeting.": "", + "You must select a valid :attribute.": "", + "You must select a valid format.": "", + "You must select a valid meeting type.": "", + "You must select a valid role to perform on the website.": "", "You must select one option for “Can you connect to a specific age group or groups?”": "Vous devez sélectionner une option pour « Pouvez-vous servir d'intermédiaire auprès d'un ou de plusieurs groupes d'âge spécifiques ? »", "You must select one option for “Can you connect to people who are First Nations, Inuit, or Métis?”": "Vous devez sélectionner une option pour « Pouvez-vous servir d'intermédiaire auprès de personnes issues des Premières Nations, de personnes Inuit ou Métis ? »", "You must select one option for “Can you connect to people who are marginalized based on gender or sexual identity?”": "Vous devez sélectionner une option pour « Pouvez-vous servir d'intermédiaire auprès de personne marginalisées en raison de leur identité de genre ou sexuelle ? »", @@ -2364,6 +2397,7 @@ "Your agreement has been received for :project. You can now publish your project page and engagement details. Sign in to your account at https:\/\/accessibilityexchange.ca to continue.": "Votre entente a été reçue pour :project. Vous pouvez maintenant publier votre page de projet et les détails de votre consultation. Connectez-vous à votre compte sur https:\/\/accessibilityexchange.ca pour continuer.", "Your areas of interest have been updated.": "Vos centres d'intérêt ont été mis à jour.", "Your bio": "Votre bio", + "Your bio must be provided in at least English or French.": "", "Your communication and consultation preferences have been updated.": "Vos préférences en matière de communication et de consultation ont été mises à jour.", "Your Community Connector has been removed.": "Votre personne facilitatrice communautaire a été supprimée.", "Your consultation preferences": "Vos préférences en matière de consultation", @@ -2418,6 +2452,7 @@ "Your project has been created.": "Votre projet a été créé.", "Your project has been deleted.": "Votre projet a été supprimé.", "Your projects and engagements": "Vos projets et consultations", + "Your pronouns must be provided in at least English or French.": "", "your public profile will be removed from the platform": "votre profil public sera supprimé de la plateforme", "your public profile will be removed from the website": "votre profil public sera supprimé du site Internet", "Your regulated organization, :name, will be deleted and cannot be recovered. If you still want to delete your regulated organization, please enter your current password to proceed.": "Votre organisme réglementé, :name, sera supprimé et ne pourra pas être récupéré. Si vous souhaitez toujours supprimer votre organisme réglementé, veuillez saisir votre mot de passe actuel pour continuer.", diff --git a/resources/lang/lsq.json b/resources/lang/lsq.json index 7176522f1..442138e02 100644 --- a/resources/lang/lsq.json +++ b/resources/lang/lsq.json @@ -224,6 +224,7 @@ "After the consultation follow up with participants to share next steps and your organization’s plan for implementing their feedback. This can help foster confidence in your commitment, and an ongoing relationship with your participants, who can be involved in future updates of your accessibility plan.": "Après la consultation, assurez un suivi auprès des personnes participantes pour leur faire part des prochaines étapes et du plan de votre organisation pour mettre en œuvre leurs commentaires. Cela peut contribuer à renforcer la confiance envers votre initiative et à établir une relation durable avec vos participants, lesquels pourraient éventuellement participer aux futures mises à jour de votre plan d'accessibilité.", "Age": "Âge", "Age group": "Groupe d'âge", + "age group": "", "Age groups": "Groupes d'âge", "Age groups they can connect to": "Tranches d'âge auprès desquelles vous pouvez agir comme intermédiaire", "Agreement pending": "Entente en attente", @@ -240,14 +241,15 @@ "All the training I am doing or have done.": "Toutes les formations que je fais ou que j'ai faites.", "Alternative text for images": "Texte de remplacement pour les images", "Although it is not compulsory, we highly recommend that you include English and French translations of your content.": "Although it is not compulsory, we highly recommend that you include English and French translations of your content.", - "A meeting title must be provided in at least one language.": "Un titre de réunion doit être fourni dans au moins une langue.", + "A meeting title must be provided in at least English or French.": "", "American Sign Language (ASL)": "American Sign Language (ASL)", "Analysis of collected information": "Analyse des informations recueillies", "Analyze the outcomes of your consultation with people who are in the context of disability and Deaf groups.": "Analyser les résultats de votre consultation avec des personnes faisant partie de groupes de personnes en situation de handicap et de personnes sourdes.", "An approximate response time must be provided in at least one language.": "Un temps de réponse approximatif doit être indiqué dans au moins une langue.", - "An engagement description must be provided in at least one language.": "Une description de la consultation doit être fournie dans au moins une langue.", + "An engagement description must be provided in at least English or French.": "", "An engagement involves a group of people participating in one set way (for example, a focus group or a survey). An engagement like a focus group can have multiple meetings.": "Une consultation implique un groupe de personnes participant d'une manière donnée (par exemple, un groupe de discussion ou un sondage). Une consultation, comme un groupe de discussion, peut se dérouler sur plusieurs réunions.", "An engagement involves a group of people participating in one set way (for example, a focus group or survey).": "Une consultation implique un groupe de personnes participant d'une manière donnée (par exemple, un groupe de discussion ou un sondage).", + "An engagement name must be provided in at least English or French.": "", "An engagement name must be provided in at least one language.": "Le nom de la consultation doit être fourni dans au moins une langue.", "An engagement with this name already exists.": "Une consultation avec ce nom existe déjà.", "a network and is able to conduct effective outreach to people with disabilities and Deaf persons in particular geographic communities and social groups (for example, Indigenous communities).": "un réseau et est capable de mener des actions de sensibilisation efficaces auprès des personnes en situation de handicap et des personnes sourdes dans des communautés géographiques et des groupes particuliers (par exemple, les communautés autochtones).", @@ -278,6 +280,7 @@ "Areas of interest": "Domaines d'intérêt", "Areas of your organization this project will impact": "Secteurs de votre organisation sur lesquels ce projet aura un impact", "Areas where the organization serves": "Régions où l'organisation est active", + "area type": "", "Are you able to attend consultations in real-time, or do you prefer to receive the materials (ex. questions, discussion topics) and record your responses at your own pace?": "Êtes-vous en mesure d'assister aux consultations en temps réel, ou préférez-vous recevoir le matériel (ex. questions, sujets de discussion) et enregistrer vos réponses à votre propre rythme ?", "Are you looking for individuals in specific provinces or territories or specific cities or towns?": "Cherchez-vous des personnes dans des provinces ou territoires spécifiques ou dans des villes ou villages spécifiques ?", "Are you sure you want to block :blockable?": "Voulez-vous vraiment bloquer :blockable?", @@ -564,6 +567,7 @@ "Date": "Date", "Date added": "Date ajoutée", "Date created": "Date de création", + "date for materials to be sent by": "", "Date of training": "Date de la formation", "Date range": "Plage de dates", "Dates": "Dates", @@ -715,6 +719,7 @@ "Estimates and agreements": "Devis et ententes", "Estimate status": "Statut du devis", "Ethno-racial groups": "Communautés ethniques et racisées", + "ethnoracial group": "", "Ethnoracial group they can connect to": "Communautés ethniques et racisées auprès desquelles ils peuvent servir d'intermédiaire", "Ethnoracial identity": "Identité ethnoraciale", "ethnoracial identity": "identité ethnoraciale", @@ -746,6 +751,7 @@ "Find learning materials, best practices, and variety of tools to help you throughout the consultation process.": "Supports d'apprentissage, meilleures pratiques et une variété d'outils pour vous aider tout au long du processus de consultation.", "Find people with disabilities, Deaf people and community organizations (for example, disability or other relevant civil society organizations, like Indigenous groups), to consult with on your accessibility project.": "Trouvez des personnes en situation de handicap, des personnes sourdes et des organisations communautaires (par exemple, des organisations de personnes en situation de handicap ou d'autres organisations pertinentes de la société civile, comme les groupes autochtones), à consulter dans le cadre de votre projet en matière d'accessibilité.", "First language": "Première langue", + "first language": "", "First Nations": "Premières Nations", "flexible, please contact us if you need to use another software": "flexible, veuillez nous contacter si vous souhaitez utiliser un autre logiciel", "Focus group": "Groupe de discussion", @@ -799,6 +805,7 @@ "Gender neutral, barrier-free washrooms": "Toilettes mixtes et accessibles", "Gender neutral washroom": "Salle de bain non genrée", "Gender non-conforming people": "Personnes non-conformes au genre", + "gender or sexual identity group": "", "GENERAL": "DISPOSITIONS GÉNÉRALES", "General": "Général", "General access needs": "Besoins généraux en matière d'accessibilité", @@ -882,6 +889,7 @@ "Ideally, an Accessibility Consultant has:": "Dans l'idéal, une personne consultante en matière d'accessibilité possède :", "Ideally a Community Connector has:": "Dans l'idéal, une personne facilitatrice communautaire possède :", "Ideal number of participants": "Nombre idéal de personnes participantes", + "ideal number of participants": "", "Identities": "Identités", "If anything about your projects or engagements have changed, please send a new estimate request.": "Si un élément de vos projets ou consultations a changé, veuillez envoyer une nouvelle demande de devis.", "If a Sign Language video translation is available, you will see a button in line with the website content. Pressing that button will load the Sign Language video.": "Si une traduction vidéo en langue des signes est disponible, vous verrez un bouton en ligne avec le contenu du site Internet. En appuyant sur ce bouton, la vidéo en langue des signes sera chargée.", @@ -891,6 +899,9 @@ "if the provision of the Platform to you by IRIS is, in IRIS’ opinion, no longer commercially or financially viable.": "if the provision of the Platform to you by IRIS is, in IRIS’ opinion, no longer commercially or financially viable.", "If you already have an account, please [sign in](:url).": "Si vous avez déjà un compte, veuillez [vous identifier](:url).", "IF YOU ARE DISSATISFIED WITH ANY PORTION OF THE PLATFORM OR WITH THESE TERMS OF SERVICE, YOUR SOLE AND EXCLUSIVE REMEDY IS TO DISCONTINUE USE OF THE PLATFORM.": "IF YOU ARE DISSATISFIED WITH ANY PORTION OF THE PLATFORM OR WITH THESE TERMS OF SERVICE, YOUR SOLE AND EXCLUSIVE REMEDY IS TO DISCONTINUE USE OF THE PLATFORM.", + "If you are interested in engaging a specific :attribute, you must select at least one.": "", + "If you are looking for a group with a specific experience or identity, you must select which type of experience or identity you are looking for.": "", + "If you are looking for a specific :attribute, you must select at least one.": "", "If you are seeking a Community Connector for this engagement, there are a few ways to find one:": "Si vous recherchez une personne facilitatrice communautaire pour cette consultation, plusieurs moyens s'offrent à vous :", "If you are thinking of working with a specific group, for example, Indigenous people with disabilities, it would be a good idea to hire an Accessibility Consultant from that community.": "Si vous envisagez de travailler avec un groupe spécifique, par exemple, des personnes en situation de handicap issues de communautés autochtones, il pourrait être avantageux d'engager une personne consultante en matière d'accessibilité issue de cette communauté.", "If you delete your account:": "Si vous supprimez votre compte :", @@ -918,6 +929,7 @@ "Incomplete": "", "INDEMNITY AND RELEASE.": "INDEMNITY AND RELEASE.", "Indigenous": "Autochtone", + "Indigenous group": "", "Indigenous identity": "Indigenous identity", "Individual": "Individu", "individual": "individu", @@ -1075,7 +1087,6 @@ "Meeting date :date": "Date de la réunion :date", "Meeting dates": "Dates de réunion", "meeting end time": "heure de fin de la réunion", - "meeting phone number": "numéro de téléphone de la réunion", "Meetings": "Réunions", "meeting start time": "heure de début de la réunion", "meeting time zone": "fuseau horaire de la réunion", @@ -1089,6 +1100,7 @@ "Microsoft Word": "Microsoft Word", "Middle Eastern": "Moyen-oriental", "Minimum number of participants": "Nombre minimum de personnes participantes", + "minimum number of participants": "", "Missing an engagement?": "Manque-t-il une consultation?", "modify, copy, reproduce, reverse engineer, frame, rent, lease, loan, sell, distribute, publish, or create derivative works based on the Platform or the Service Content (as defined below), in whole or in part;": "modify, copy, reproduce, reverse engineer, frame, rent, lease, loan, sell, distribute, publish, or create derivative works based on the Platform or the Service Content (as defined below), in whole or in part;", "Module - :title": "Module - :title", @@ -1159,6 +1171,7 @@ "No interests listed.": "Aucun intérêt répertorié.", "No meetings found.": "Aucune réunion trouvée.", "Non-binary, gender non-conforming and\/or gender fluid people": "Personnes non-binaires, non-conformes au genre et\/ou fluides de genre", + "Non-binary\/Gender non-conforming\/Gender fluid identity": "", "Non-binary people": "Personnes non-binaires", "None found.": "Rien n'a été trouvé.", "None listed": "Aucun listé", @@ -1229,7 +1242,6 @@ "Once you sign up, you can sign up for an orientation session to learn about what you can do on this website. You can also fill in information to facilitate a smoother collaboration with organizations, such as access needs, communication preferences, and consultation preferences.": "Une fois inscrit, vous pouvez vous inscrire à une séance d'orientation pour découvrir ce que vous pouvez faire sur ce site. Vous pouvez également remplir des informations destinées à rendre la collaboration avec les organisations plus harmonieuse, telles que vos besoins en matière d'accessibilité, vos préférences en ce qui concerne les communications ou encore les consultations.", "Once you’ve reviewed the project details, please:": "Une fois que vous aurez revu les détails du projet, veuillez :", "One of the key parts of preparing for your consultation with the disability and Deaf communities is making sure that your consultations are done in an accessible and inclusive way.": "L'un des éléments clés de la préparation de votre consultation avec les communautés de personnes en situation de handicap et de personnes sourdes est de s'assurer que vos consultations se déroulent d'une manière accessible et inclusive.", - "One or more Disability or Deaf groups are required.": "One or more Disability or Deaf groups are required.", "Online form, such as survey monkey or google forms": "Formulaire en ligne, tel que SurveyMonkey ou Google Forms", "Only people with specific disabilities and\/or Deaf people": "Personnes ayant des handicaps spécifiques et\/ou personnes sourdes", "Only reachable within cross-disability and Deaf or intersectional groups": "Only reachable within cross-disability and Deaf or intersectional groups", @@ -1327,6 +1339,7 @@ "phone number": "numéro de téléphone", "Phone number:": "Numéro de téléphone :", "Phone number to join": "Numéro de téléphone à rejoindre", + "phone number to join the meeting": "", "Physical and mobility disabilities": "Déficience physique et de mobilité", "Plain language": "Langage simple", "Plan and share your project with others on this website.": "Planifiez et partagez votre projet avec d'autres personnes sur ce site Internet.", @@ -1356,7 +1369,10 @@ "Please create your profile to share more about who you are, your experiences, and your interests.": "Veuillez créer votre profil pour en dire plus sur qui vous êtes, vos expériences et vos intérêts.", "Please describe how the Disability and Deaf communities will be impacted by the outcomes of your project.": "Veuillez décrire comment les communautés des personnes en situation de handicap et des personnes sourdes seront touchées par les résultats de votre projet.", "Please describe this engagement.": "Veuillez décrire cette consultation.", + "Please enter a :attribute that is less than or the same as the ideal number of participants.": "", "Please enter an end year for your experience that is equal to or greater than the start year.": "Please enter an end year for your experience that is equal to or greater than the start year.", + "Please enter a valid :attribute.": "", + "Please enter a valid date for the :attribute.": "", "Please enter a valid website link under “Accessibility and Inclusion links”.": "Veuillez saisir un lien Internet valide sous \"Liens en lien avec l'accessibilité et l'inclusion\".", "Please enter the email address of the individual you have hired as a Community Connector.": "Veuillez entrer l'adresse courriel de la personne que vous avez embauchée en tant que personne facilitatrice communautaire.", "Please enter your collaboration preferences": "Veuillez entrer vos préférences de collaboration", @@ -1407,6 +1423,9 @@ "Please review and update your public page": "Veuillez réviser et mettre à jour votre page publique", "Please review your page. There is some information for your new role that you will have to fill in.": "Merci de vérifier l'information présentée sur cette page. De l'information sur les nouveaux rôles que vous avez sélectionnés est disponible.", "Please see the resource [Planning a Safe, Accessible Consultation](:url).": "Veuillez consulter la ressource [Planification d'une consultation sûre et accessible](:url).", + "Please select a language.": "", + "Please select a language that the engagement documents will be in.": "", + "Please select a language to remove.": "", "Please select a recruitment method": "Veuillez sélectionner une méthode de recrutement", "Please select disability groups that your organization specifically represents": "Veuillez sélectionner les groupes de personnes en situation de handicap que votre organisation représente spécifiquement", "Please select the disability and\/or Deaf groups that you can connect to.": "Veuillez sélectionner les groupes de personnes en situation de handicap et\/ou de personnes sourdes auprès desquels vous pouvez agir comme intermédiaire.", @@ -1672,7 +1691,6 @@ "Send invitation": "Envoyer l'invitation", "Send request": "Envoyer la demande", "Send the estimate and agreement to <:contact>.": "Envoyez le devis et l'entente à <:contact>.", - "sent by date": "envoyé par date", "serve and support": "servir et soutenir", "serves and supports": "sert et soutien", "Service areas": "Régions desservies", @@ -1803,7 +1821,11 @@ "Text": "Texte", "Text message": "Message texte", "Text to speech": "Synthèse vocale", + "The :attribute format is not valid.": "", "The :attribute is not in the right format.": "Le champ :attribute n'est pas au bon format.", + "The :attribute must be after the :date.": "", + "The :attribute must be a number.": "", + "The :attribute must be before the :date.": "", "The :projectable sends out a list of questions, and you can can respond to them at your own pace.": "Dans ce cas, l':projectable vous enverra une liste de questions et vous pourrez y répondre à votre propre rythme.", "The Accessibility Exchange": "Connecteur pour l’accessibilité", "The Accessibility Exchange will send you notifications, based on what you chose to be notified of here.": "Le Connecteur pour l'accessibilité vous enverra des notifications, en fonction de ce que vous avez choisi de recevoir ici.", @@ -1830,11 +1852,11 @@ "Theme": "Thème", "themes": "thèmes", "Themes": "Thèmes", - "The minimum number of participants is more than the ideal number of participants. Please enter a minimum that is less than or the same as the ideal number of participants.": "Le nombre minimum de personnes participantes est supérieur au nombre idéal de personnes participantes. Veuillez saisir un minimum inférieur ou égal au nombre idéal de personnes participantes.", "The notification has been marked as read.": "La notification a été marquée comme lue.", "the number of people on your team": "the number of people on your team", "The organization you have added does not participate in engagements.": "L'organisation que vous avez ajoutée ne désire pas participer à des consultations.", - "The other accepted format must be provided in at least one language.": "L'autre format accepté doit être fourni dans au moins une langue.", + "The other accepted format must be a string.": "", + "The other accepted format must be provided in at least English or French.": "", "the other languages are you able to work in": "les autres langues dans lesquelles vous êtes capable de travailler", "the other languages you are able to work in": "les autres langues dans lesquelles vous êtes capable de travailler", "The other payment type must be specified.": "Vous devez spécifier l'autre type de paiement.", @@ -1848,6 +1870,7 @@ "These are the seven areas listed within the Accessible Canada Act. By law, entities must ensure these areas are accessible.": "Ces sept domaines sont énumérés dans la Loi canadienne sur l'accessibilité. En vertu de la loi, les entités doivent s'assurer que ces domaines sont accessibles.", "These are the seven areas listed within the Accessible Canada Act. Federally regulated organizations must work to improve their accessibility in all of these areas.": "Ces sept domaines sont énumérés dans la Loi canadienne sur l'accessibilité. En vertu de la loi, les organisations sous réglementation fédérale doivent s'assurer que ces domaines sont accessibles.", "These details will help people know what to expect when working with you.": "Ces détails aideront les gens à savoir à quoi s'attendre lorsqu'ils travaillent avec vous.", + "The selected consulting service is invalid": "", "The selected working language is not valid.": "La langue de travail sélectionnée n'est pas valide.", "These organizations, coalitions, cross-disability or umbrella groups are made up of, and controlled by, persons with disabilities, Deaf persons, and\/or their family members. These organizations were created to advance and defend the rights of persons with disabilities.": "Ces organisations, coalitions, groupes multi-handicap ou parapluies sont constitués et contrôlés par des personnes en situation de handicap, des personnes sourdes et\/ou des membres de leur famille. Ces organisations ont été créées pour faire avancer et défendre les droits des personnes en situation de handicap.", "These organizations have constituencies which include persons with disabilities, Deaf persons, and family members. Disability and Deaf services are not the primary mandate of these organizations. ": "Ces organisations comptent parmi leurs membres des personnes en situation de handicap, des personnes sourdes et des membres de leur famille. Les services aux personnes en situation de handicap et aux personnes sourdes ne constituent pas le mandat principal de ces organisations. ", @@ -1856,6 +1879,7 @@ "The suspension of :account and its users has been lifted.": "The suspension of :account and its users has been lifted.", "The suspension of :account has been lifted.": "The suspension of :account has been lifted.", "The type of disability they experience": "Le type de handicap vécu", + "The user’s role is missing.": "", "They have been instructed to send their signed agreement to <:email>.": "Ils ont été priés d'envoyer leur accord signé à <:email>.", "They require Video Relay Service (VRS) for phone calls": "Cette personne a besoin du service de relais vidéo (SRV) pour les appels téléphoniques", "They will not be able to:": "Ils ne seront pas en mesure de faire les choses suivantes :", @@ -1897,13 +1921,14 @@ "This is the name that will be displayed on your page. This does not have to be your legal name.": "Il s'agit du nom qui sera affiché sur votre page. Il peut être différent de votre nom légal.", "This is the name that will be displayed on your project page.": "Il s'agit du nom qui sera affiché sur la page de votre projet.", "This is the name that will show up publicly on your page.": "Il s'agit du nom qui apparaîtra publiquement sur votre page.", + "This member already belongs to this organization.": "", + "This member has already been invited.": "", "This organization has already been invited.": "Cette organisation a déjà été invitée.", "This organization has people on staff who have lived experience of the communities they :represent_or_serve_and_support.": "Cette organisation compte parmi son personnel des personnes ayant une expérience vécue des communautés qu'elle :represent_or_serve_and_support.", "This site is for three kinds of users. Select an option below to learn more.": "Ce site s'adresse à trois types de publics. Sélectionnez une option ci-dessous pour en savoir plus.", "This site uses cookies to help provide a better experience.": "This site uses cookies to help provide a better experience.", "This survey will be provided in the following digital formats:": "Ce sondage sera fourni dans les formats numériques suivants :", "This survey will be provided in the following formats:": "Ce sondage sera fourni dans les formats suivants :", - "This user already belongs to this team.": "Cette personne fait déjà partie de cette équipe.", "This website was made in partnership with members and organizations from the disability and Deaf communities, supporters, and members from Federally Regulated Organizations.": "Ce site Internet a été conçu en partenariat avec des membres et des organisations de la communauté des personnes en situation de handicap et des personnes sourdes, de leurs alliés et des membres d'organisations sous réglementation fédérale.", "This will help governments and businesses communicate and work with you in a format that is accessible to you.": "Cela aidera les gouvernements et les entreprises à communiquer et à travailler avec vous dans un format qui vous est accessible.", "This will help people know what to expect when working with you.": "Cela permettra aux gens de savoir à quoi s'attendre lorsqu'ils travaillent avec vous.", @@ -2290,12 +2315,17 @@ "You must choose at least one type of federally regulated organization.": "Vous devez choisir au moins un type d'organisation sous réglementation fédérale.", "You must choose at least one type of organization.": "Vous devez choisir au moins un type d'organisation.", "You must choose at least one type of project.": "Vous devez choisir au moins un type de projet.", + "You must choose a valid province or territory": "", + "You must enter a :attribute": "", + "You must enter a :attribute.": "", "You must enter a :attribute for the meeting location.": "Vous devez saisir un\/une :attribute pour le lieu de la réunion.", "You must enter a city or town.": "Vous devez indiquer une ville ou un village.", "You must enter an email address.": "Vous devez saisir une adresse courriel.", "You must enter a province or territory.": "Vous devez indiquer une province ou un territoire.", "You must enter at least one city or town.": "Vous devez indiquer au moins une ville ou un village.", + "You must enter a valid link for :key.": "", "You must enter a valid website address for :key.": "Vous devez indiquer une adresse valide pour :key.", + "You must enter a valid website link.": "", "You must enter your organization's name in either English or French.": "Vous devez saisir le nom de votre organisation en anglais ou en français.", "You must enter your organization name.": "Vous devez saisir le nom de votre organisation.", "You must enter your organization name in either English or French.": "Vous devez saisir le nom de votre organisation en anglais ou en français.", @@ -2307,14 +2337,12 @@ "You must indicate the :attribute.": "Vous devez indiquer l'attribut :attribute.", "You must indicate who you want to engage.": "Vous devez indiquer qui vous voulez impliquer.", "You must pick at least one of these roles.": "Vous devez choisir au moins un de ces rôles.", - "You must provide a :attribute.": "Vous devez fournir un :attribute.", "You must select a language.": "Vous devez sélectionner une langue.", "You must select a role for your organization.": "Vous devez sélectionner un rôle pour votre organisation.", "You must select at least one age group you can connect to.": "Vous devez sélectionner au moins un groupe d'âge auprès duquel vous pouvez servir d'intermédiaire.", "You must select at least one age group your organization specifically :represents_or_serves_and_supports.": "Vous devez sélectionner au moins un groupe d'âge que votre organisation :represents_or_serves_and_supports spécifiquement.", "You must select at least one ethno-racial identity you can connect to.": "Vous devez sélectionner au moins une identité ethnoraciale auprès de laquelle vous pouvez servir d'intermédiaire.", "You must select at least one ethno-racial identity your organization specifically :represents_or_serves_and_supports.": "Vous devez sélectionner au moins une identité ethnoraciale spécifique que votre organisation :represents_or_serves_and_supports.", - "You must select at least one gender or sexual identity group.": "Vous devez sélectionner au moins un groupe relatif au genre ou à l'identité sexuelle.", "You must select at least one gender or sexual identity group you can connect to.": "Vous devez sélectionner au moins un groupe d'identité sexuelle ou de genre auprès duquel vous pouvez servir d'intermédiaire.", "You must select at least one gender or sexual identity group your organization specifically :represents_or_serves_and_supports.": "Vous devez sélectionner au moins un groupe d'identité sexuelle ou de genre que votre organisation :represents_or_serves_and_supports.", "You must select at least one Indigenous group you can connect to.": "Vous devez sélectionner au moins un groupe autochtone auprès duquel vous pouvez servir d'intermédiaire.", @@ -2323,6 +2351,11 @@ "You must select at least one option for “Can you connect to people with disabilities, Deaf persons, and\/or their supporters?”": "Vous devez sélectionner au moins une option pour \"Pouvez-vous servir d'intermédiaire auprès des personnes en situation de handicap, des personnes sourdes et\/ou leurs alliés?\"", "You must select at least one option for “Where do the people that you :represent_or_serve_and_support come from?”": "Vous devez sélectionner au moins une option pour « D'où viennent les personnes que vous représentez »", "You must select at least one option for “Where do the people that you can connect to come from?”": "Vous devez sélectionner au moins une option pour « D'où viennent les personnes auprès desquelles vous pouvez servir d'intermédiaire ? »", + "You must select at least one way to attend the meeting.": "", + "You must select a valid :attribute.": "", + "You must select a valid format.": "", + "You must select a valid meeting type.": "", + "You must select a valid role to perform on the website.": "", "You must select one option for “Can you connect to a specific age group or groups?”": "Vous devez sélectionner une option pour « Pouvez-vous servir d'intermédiaire auprès d'un ou de plusieurs groupes d'âge spécifiques ? »", "You must select one option for “Can you connect to people who are First Nations, Inuit, or Métis?”": "Vous devez sélectionner une option pour « Pouvez-vous servir d'intermédiaire auprès de personnes issues des Premières Nations, de personnes Inuit ou Métis ? »", "You must select one option for “Can you connect to people who are marginalized based on gender or sexual identity?”": "Vous devez sélectionner une option pour « Pouvez-vous servir d'intermédiaire auprès de personne marginalisées en raison de leur identité de genre ou sexuelle ? »", @@ -2364,6 +2397,7 @@ "Your agreement has been received for :project. You can now publish your project page and engagement details. Sign in to your account at https:\/\/accessibilityexchange.ca to continue.": "Votre entente a été reçue pour :project. Vous pouvez maintenant publier votre page de projet et les détails de votre consultation. Connectez-vous à votre compte sur https:\/\/accessibilityexchange.ca pour continuer.", "Your areas of interest have been updated.": "Vos centres d'intérêt ont été mis à jour.", "Your bio": "Votre bio", + "Your bio must be provided in at least English or French.": "", "Your communication and consultation preferences have been updated.": "Vos préférences en matière de communication et de consultation ont été mises à jour.", "Your Community Connector has been removed.": "Votre personne facilitatrice communautaire a été supprimée.", "Your consultation preferences": "Vos préférences en matière de consultation", @@ -2418,6 +2452,7 @@ "Your project has been created.": "Votre projet a été créé.", "Your project has been deleted.": "Votre projet a été supprimé.", "Your projects and engagements": "Vos projets et consultations", + "Your pronouns must be provided in at least English or French.": "", "your public profile will be removed from the platform": "votre profil public sera supprimé de la plateforme", "your public profile will be removed from the website": "votre profil public sera supprimé du site Internet", "Your regulated organization, :name, will be deleted and cannot be recovered. If you still want to delete your regulated organization, please enter your current password to proceed.": "Votre organisme réglementé, :name, sera supprimé et ne pourra pas être récupéré. Si vous souhaitez toujours supprimer votre organisme réglementé, veuillez saisir votre mot de passe actuel pour continuer.", diff --git a/resources/views/components/date-picker.blade.php b/resources/views/components/date-picker.blade.php index 5b863fb95..d7fa9627f 100644 --- a/resources/views/components/date-picker.blade.php +++ b/resources/views/components/date-picker.blade.php @@ -48,4 +48,5 @@ + diff --git a/resources/views/engagements/show-criteria-selection.blade.php b/resources/views/engagements/show-criteria-selection.blade.php index 3412ccee1..c6891b12e 100644 --- a/resources/views/engagements/show-criteria-selection.blade.php +++ b/resources/views/engagements/show-criteria-selection.blade.php @@ -38,7 +38,7 @@
-
+
{{ __('Are you looking for individuals in specific provinces or territories or specific cities or towns?') }} @@ -48,7 +48,7 @@
+ x-show="locationType == '{{ App\Enums\LocationType::Regions->value }}'"> {{ __('Specific provinces or territories') }}
@@ -61,7 +61,7 @@
+ x-show="locationType == '{{ App\Enums\LocationType::Localities->value }}'"> {{ __('Specific cities or towns') }} @@ -152,7 +152,7 @@ class="sr-only">{{ __('Disability or Deaf group') }}
+ x-show="otherIdentityType == '{{ App\Enums\IdentityType::AgeBracket->value }}'"> {{ __('What age group are you interested in engaging?') }} {{ __('Disability or Deaf group') }}
+ x-show="otherIdentityType == '{{ App\Enums\IdentityType::GenderAndSexualIdentity->value }}'"> {{ __('What group that has been marginalized based on gender or sexual identity are you interested in engaging?') }} @@ -181,7 +181,7 @@ class="sr-only">{{ __('Disability or Deaf group') }}
+ x-show="otherIdentityType == '{{ App\Enums\IdentityType::IndigenousIdentity->value }}'"> {{ __('What Indigenous group are you interested in engaging?') }} @@ -192,7 +192,7 @@ class="sr-only">{{ __('Disability or Deaf group') }}
+ x-show="otherIdentityType == '{{ App\Enums\IdentityType::EthnoracialIdentity->value }}'"> {{ __('What ethno-racial group are you interested in engaging?') }} {{ __('Disability or Deaf group') }}
+ x-show="otherIdentityType == '{{ App\Enums\IdentityType::FirstLanguage->value }}'"> {{ __('What first languages are used by the people you’re interested in engaging?') }} @@ -212,7 +212,7 @@ class="sr-only">{{ __('Disability or Deaf group') }}
+ x-show="otherIdentityType == '{{ App\Enums\IdentityType::AreaType->value }}'"> {{ __('Where do the people you’re interested in engaging live?') }} {{ __('Please check all that apply.') }} {{ __('Remove this language') }} @endif + @endforeach diff --git a/tests/Datasets/AddNotificaitonableRequestValidationErrors.php b/tests/Datasets/AddNotificaitonableRequestValidationErrors.php new file mode 100644 index 000000000..de4ad56df --- /dev/null +++ b/tests/Datasets/AddNotificaitonableRequestValidationErrors.php @@ -0,0 +1,25 @@ + [ + ['notificationable_type' => null], + ], + 'notificationable type not a string' => [ + ['notificationable_type' => false], + ], + 'notificationable type is invalid' => [ + [], + fn () => ['notificationable_type' => __('validation.in', ['attribute' => 'notificationable type'])], + ], + 'missing notificationable id' => [ + ['notificationable_id' => null], + ], + 'notificationable id not an integer' => [ + ['notificationable_id' => 'test'], + ], + 'notificationable id is invalid' => [ + ['notificationable_id' => 10000000], + ], + ]; +}); diff --git a/tests/Datasets/AddTranslationRequestValidationErrors.php b/tests/Datasets/AddTranslationRequestValidationErrors.php new file mode 100644 index 000000000..70174eb2a --- /dev/null +++ b/tests/Datasets/AddTranslationRequestValidationErrors.php @@ -0,0 +1,27 @@ + [ + ['translatable_type' => null], + ], + 'translatable type not a string' => [ + ['translatable_type' => true], + ], + 'translatable id invalid' => [ + ['translatable_id' => 1000000], + ], + 'missing new language' => [ + ['new_language' => null], + fn () => ['new_language' => __('Please select a language.', ['model' => 'Tester'])], + ], + 'new language not a string' => [ + ['new_language' => 30], + fn () => ['new_language' => __('Please select a language.', ['model' => 'Tester'])], + ], + 'new language already in use' => [ + ['new_language' => 'en'], + fn () => ['new_language' => __(':model is already translatable into :language.', ['model' => 'Tester', 'language' => get_language_exonym('en')])], + ], + ]; +}); diff --git a/tests/Datasets/DestroyTranslationRequestValidationErrors.php b/tests/Datasets/DestroyTranslationRequestValidationErrors.php new file mode 100644 index 000000000..bf168591d --- /dev/null +++ b/tests/Datasets/DestroyTranslationRequestValidationErrors.php @@ -0,0 +1,27 @@ + [ + ['translatable_type' => null], + ], + 'translatable type not a string' => [ + ['translatable_type' => true], + ], + 'translatable id invalid' => [ + ['translatable_id' => 1000000], + ], + 'missing language' => [ + ['language' => null], + fn () => ['language' => __('Please select a language to remove.')], + ], + 'language not a string' => [ + ['language' => 30], + fn () => ['language' => __('Please select a language to remove.')], + ], + 'language invalid' => [ + ['language' => 'es'], + fn () => ['language' => __(':model was not translatable into :language.', ['model' => 'Tester', 'language' => get_language_exonym('es')])], + ], + ]; +}); diff --git a/tests/Datasets/MatchingStrategyLocationType.php b/tests/Datasets/MatchingStrategyLocationType.php index 0eebb9c29..72bbc2eb5 100644 --- a/tests/Datasets/MatchingStrategyLocationType.php +++ b/tests/Datasets/MatchingStrategyLocationType.php @@ -1,5 +1,6 @@ value, ], 'with regions' => [ ['regions' => [ProvinceOrTerritory::Ontario->value]], @@ -33,7 +34,7 @@ ], 'regions' => [ProvinceOrTerritory::Ontario->value], ], - 'regions', + LocationType::Regions->value, ], ]; }); diff --git a/tests/Datasets/MatchingStrategyOtherIdentitiesSummary.php b/tests/Datasets/MatchingStrategyOtherIdentitiesSummary.php index 800960569..c75c2d2ce 100644 --- a/tests/Datasets/MatchingStrategyOtherIdentitiesSummary.php +++ b/tests/Datasets/MatchingStrategyOtherIdentitiesSummary.php @@ -1,6 +1,7 @@ [ [ - 'extra_attributes' => ['other_identity_type' => 'age-bracket'], + 'extra_attributes' => ['other_identity_type' => IdentityType::AgeBracket->value], ], fn () => [Identity::whereJsonContains('clusters', IdentityCluster::Age)->first()], ], 'with gender-and-sexual-identity identities' => [ [ - 'extra_attributes' => ['other_identity_type' => 'gender-and-sexual-identity'], + 'extra_attributes' => ['other_identity_type' => IdentityType::GenderAndSexualIdentity->value], ], fn () => [Identity::whereJsonContains('clusters', IdentityCluster::GenderAndSexuality)->first()], ], 'with indigenous-identity identities' => [ [ - 'extra_attributes' => ['other_identity_type' => 'indigenous-identity'], + 'extra_attributes' => ['other_identity_type' => IdentityType::IndigenousIdentity->value], ], fn () => [Identity::whereJsonContains('clusters', IdentityCluster::Indigenous)->first()], ], 'with ethnoracial-identity identities' => [ [ - 'extra_attributes' => ['other_identity_type' => 'ethnoracial-identity'], + 'extra_attributes' => ['other_identity_type' => IdentityType::EthnoracialIdentity->value], ], fn () => [Identity::whereJsonContains('clusters', IdentityCluster::Ethnoracial)->first()], ], 'with refugee-or-immigrant identities' => [ [ - 'extra_attributes' => ['other_identity_type' => 'refugee-or-immigrant'], + 'extra_attributes' => ['other_identity_type' => IdentityType::RefugeeOrImmigrant->value], ], fn () => [Identity::whereJsonContains('clusters', IdentityCluster::Status)->first()], ], 'with area-type identities' => [ [ - 'extra_attributes' => ['other_identity_type' => 'area-type'], + 'extra_attributes' => ['other_identity_type' => IdentityType::AreaType->value], ], fn () => [Identity::whereJsonContains('clusters', IdentityCluster::Area)->first()], ], 'with first-language identities' => [ [ - 'extra_attributes' => ['other_identity_type' => 'first-language'], + 'extra_attributes' => ['other_identity_type' => IdentityType::FirstLanguage->value], ], ['English'], ], diff --git a/tests/Datasets/MeetingRequestValidationErrors.php b/tests/Datasets/MeetingRequestValidationErrors.php new file mode 100644 index 000000000..7c83c518e --- /dev/null +++ b/tests/Datasets/MeetingRequestValidationErrors.php @@ -0,0 +1,203 @@ + [ + ['title' => ['es' => 'la sesión']], + fn () => [ + 'title.en' => __('A meeting title must be provided in at least English or French.'), + 'title.fr' => __('A meeting title must be provided in at least English or French.'), + ], + [ + 'meetingType' => MeetingType::InPerson->value, + 'without' => ['title.en'], + ], + ], + 'Title is not a string' => [ + ['title' => ['en' => false]], + fn () => ['title.en' => __('validation.string', ['attribute' => 'title.en'])], + ['meetingType' => MeetingType::InPerson->value], + ], + 'Date missing' => [ + ['date' => null], + fn () => ['date' => __('You must enter a :attribute', ['attribute' => __('meeting date')])], + [ + 'meetingType' => MeetingType::InPerson->value, + 'without' => ['date'], + ], + ], + 'Date is invalid' => [ + ['date' => 'someday'], + fn () => ['date' => __('validation.date', ['attribute' => __('meeting date')])], + ['meetingType' => MeetingType::InPerson->value], + ], + 'Start time missing' => [ + ['start_time' => null], + fn () => ['start_time' => __('You must enter a :attribute', ['attribute' => __('meeting start time')])], + [ + 'meetingType' => MeetingType::InPerson->value, + 'without' => ['start_time'], + ], + ], + 'Start time is invalid' => [ + ['start_time' => '8:00am'], + fn () => ['start_time' => __('The :attribute format is not valid.', ['attribute' => __('meeting start time')])], + ['meetingType' => MeetingType::InPerson->value], + ], + 'Start time is after end time' => [ + [ + 'start_time' => '22:00', + 'end_time' => '7:00', + ], + fn () => [ + 'start_time' => __('The :attribute must be before the :date.', ['attribute' => __('meeting start time'), 'date' => __('meeting end time')]), + 'end_time' => __('The :attribute must be after the :date.', ['attribute' => __('meeting end time'), 'date' => __('meeting start time')]), + ], + ['meetingType' => MeetingType::InPerson->value], + ], + 'End time missing' => [ + ['end_time' => null], + fn () => ['end_time' => __('You must enter a :attribute', ['attribute' => __('meeting end time')])], + [ + 'meetingType' => MeetingType::InPerson->value, + 'without' => ['end_time'], + ], + ], + 'End time is invalid' => [ + ['end_time' => '8:00am'], + fn () => ['end_time' => __('The :attribute format is not valid.', ['attribute' => __('meeting end time')])], + ['meetingType' => MeetingType::InPerson->value], + ], + 'Meeting types missing' => [ + ['meeting_types' => null], + fn () => ['meeting_types' => __('You must indicate at least one way for participants to attend the meeting.')], + ['without' => ['meeting_types']], + ], + 'Meeting types is not an array' => [ + ['meeting_types' => MeetingType::InPerson->value], + fn () => ['meeting_types' => __('validation.array', ['attribute' => 'meeting types'])], + ], + 'Meeting type is invalid' => [ + ['meeting_types' => ['new_meeting_type']], + fn () => ['meeting_types.0' => __('You must select a valid meeting type.')], + ], + 'Street address missing' => [ + ['street_address' => null], + fn () => ['street_address' => __('You must enter a :attribute for the meeting location.', ['attribute' => 'street address'])], + [ + 'meetingType' => MeetingType::InPerson->value, + 'without' => ['street_address'], + ], + ], + 'Street address is not a string' => [ + ['street_address' => 1234], + fn () => ['street_address' => __('validation.string', ['attribute' => 'street address'])], + ['meetingType' => MeetingType::InPerson->value], + ], + 'Unit/Suite/Floor is not a string' => [ + ['unit_suite_floor' => 1234], + fn () => ['unit_suite_floor' => __('validation.string', ['attribute' => 'unit suite floor'])], + ['meetingType' => MeetingType::InPerson->value], + ], + 'Locality missing' => [ + ['locality' => null], + fn () => ['locality' => __('You must enter a :attribute for the meeting location.', ['attribute' => __('city or town')])], + [ + 'meetingType' => MeetingType::InPerson->value, + 'without' => ['locality'], + ], + ], + 'Locality is not a string' => [ + ['locality' => 1234], + fn () => ['locality' => __('validation.string', ['attribute' => __('city or town')])], + ['meetingType' => MeetingType::InPerson->value], + ], + 'Region missing' => [ + ['region' => null], + fn () => ['region' => __('You must enter a :attribute for the meeting location.', ['attribute' => __('province or territory')])], + [ + 'meetingType' => MeetingType::InPerson->value, + 'without' => ['region'], + ], + ], + 'Region is not a string' => [ + ['region' => 'XX'], + fn () => ['region' => __('validation.in', ['attribute' => __('province or territory')])], + ['meetingType' => MeetingType::InPerson->value], + ], + 'Postal code missing' => [ + ['postal_code' => null], + fn () => ['postal_code' => __('You must enter a :attribute for the meeting location.', ['attribute' => 'postal code'])], + [ + 'meetingType' => MeetingType::InPerson->value, + 'without' => ['postal_code'], + ], + ], + 'Postal code is not a string' => [ + ['postal_code' => 'XX'], + fn () => ['postal_code' => __('validation.postal_code', ['attribute' => 'postal code'])], + ['meetingType' => MeetingType::InPerson->value], + ], + 'Directions is not an array' => [ + ['directions' => 'Take first elevator to the second floor.'], + fn () => ['directions' => __('validation.array', ['attribute' => 'directions'])], + ['meetingType' => MeetingType::InPerson->value], + ], + 'Meeting software missing' => [ + ['meeting_software' => null], + fn () => ['meeting_software' => __('You must indicate the :attribute.', ['attribute' => 'meeting software'])], + [ + 'meetingType' => MeetingType::WebConference->value, + 'without' => ['meeting_software'], + ], + ], + 'Meeting software is not a string' => [ + ['meeting_software' => 1234], + fn () => ['meeting_software' => __('validation.string', ['attribute' => 'meeting software'])], + ['meetingType' => MeetingType::WebConference->value], + ], + 'Alternative meeting software is not a boolean' => [ + ['alternative_meeting_software' => 'false'], + fn () => ['alternative_meeting_software' => __('validation.boolean', ['attribute' => 'alternative meeting software'])], + ['meetingType' => MeetingType::WebConference->value], + ], + 'Meeting url missing' => [ + ['meeting_url' => null], + fn () => ['meeting_url' => __('You must enter a :attribute.', ['attribute' => __('link to join the meeting')])], + [ + 'meetingType' => MeetingType::WebConference->value, + 'without' => ['meeting_url'], + ], + ], + 'Meeting url is not a valid url' => [ + ['meeting_url' => 'zoom'], + fn () => ['meeting_url' => __('validation.url', ['attribute' => __('link to join the meeting')])], + ['meetingType' => MeetingType::WebConference->value], + ], + 'Additional video information is not an array' => [ + ['additional_video_information' => 'Wait for host to accept you to the room.'], + fn () => ['additional_video_information' => __('validation.array', ['attribute' => 'additional video information'])], + ['meetingType' => MeetingType::WebConference->value], + ], + 'Meeting phone missing' => [ + ['meeting_phone' => null], + fn () => ['meeting_phone' => __('You must enter a :attribute.', ['attribute' => __('phone number to join the meeting')])], + [ + 'meetingType' => MeetingType::Phone->value, + 'without' => ['meeting_phone'], + ], + ], + 'Meeting phone is not a valid phone number' => [ + ['meeting_phone' => '1800123456'], + fn () => ['meeting_phone' => __('validation.phone', ['attribute' => __('phone number to join the meeting')])], + ['meetingType' => MeetingType::Phone->value], + ], + 'Additional phone information is not an array' => [ + ['additional_phone_information' => 'Press option 1.'], + fn () => ['additional_phone_information' => __('validation.array', ['attribute' => 'additional phone information'])], + ['meetingType' => MeetingType::Phone->value], + ], + ]; +}); diff --git a/tests/Datasets/RemoveNotificaitonableRequestValidationErrors.php b/tests/Datasets/RemoveNotificaitonableRequestValidationErrors.php new file mode 100644 index 000000000..b120584bf --- /dev/null +++ b/tests/Datasets/RemoveNotificaitonableRequestValidationErrors.php @@ -0,0 +1,37 @@ + [ + ['notificationable_type' => null], + fn () => ['notificationable_type' => __('validation.required', ['attribute' => 'notificationable type'])], + ], + 'notificationable type not a string' => [ + ['notificationable_type' => false], + fn () => [ + 'notificationable_type' => __('validation.string', ['attribute' => 'notificationable type']), + 'notificationable_type' => __('validation.in', ['attribute' => 'notificationable type']), + ], + ], + 'notificationable type is invalid' => [ + ['notificationable_type' => 'fakeClass'], + fn () => ['notificationable_type' => __('validation.in', ['attribute' => 'notificationable type'])], + ], + 'missing notificationable id' => [ + ['notificationable_id' => null], + fn () => ['notificationable_id' => __('validation.required', ['attribute' => 'notificationable id'])], + ], + 'notificationable id not an integer' => [ + ['notificationable_id' => 'test'], + fn () => [ + 'notificationable_id' => __('validation.integer', ['attribute' => 'notificationable id']), + ], + ], + 'notificationable id is invalid' => [ + ['notificationable_id' => 10000000], + fn () => [ + 'notificationable_id' => __('validation.in', ['attribute' => 'notificationable id']), + ], + ], + ]; +}); diff --git a/tests/Datasets/SaveIndividualRolesRequestValidationErrors.php b/tests/Datasets/SaveIndividualRolesRequestValidationErrors.php new file mode 100644 index 000000000..e32212a21 --- /dev/null +++ b/tests/Datasets/SaveIndividualRolesRequestValidationErrors.php @@ -0,0 +1,20 @@ + [ + [], + fn () => ['roles' => __('You must select what you would like to do on the website.')], + ], + 'Roles not an array' => [ + fn () => ['roles' => IndividualRole::AccessibilityConsultant->value], + fn () => ['roles' => __('You must select what you would like to do on the website.')], + ], + 'Role invalid' => [ + fn () => ['roles' => ['invalid-role']], + fn () => ['roles.0' => __('You must select a valid role to perform on the website.')], + ], + ]; +}); diff --git a/tests/Datasets/StoreInvitationRequestValidationErrors.php b/tests/Datasets/StoreInvitationRequestValidationErrors.php new file mode 100644 index 000000000..73f992ec0 --- /dev/null +++ b/tests/Datasets/StoreInvitationRequestValidationErrors.php @@ -0,0 +1,26 @@ + [ + ['email' => null], + fn () => ['email' => __('You must enter an email address.')], + ], + 'invitation already sent' => [ + ['email' => 'invitation.sent.test@example.com'], + fn () => ['email' => __('This member has already been invited.')], + ], + 'user already a member' => [ + ['email' => 'invitation.existing.member.test@example.com'], + fn () => ['email' => __('This member already belongs to this organization.')], + ], + 'role missing' => [ + ['role' => null], + fn () => ['role' => __('The user’s role is missing.')], + ], + 'invalid role' => [ + ['role' => 'fake'], + fn () => ['role' => __('validation.in', ['attribute' => 'role'])], + ], + ]; +}); diff --git a/tests/Datasets/UpdateEngagementRequestValidationErrors.php b/tests/Datasets/UpdateEngagementRequestValidationErrors.php new file mode 100644 index 000000000..202b1b01d --- /dev/null +++ b/tests/Datasets/UpdateEngagementRequestValidationErrors.php @@ -0,0 +1,652 @@ + [ + ['name' => null], + fn () => [ + 'name.en' => __('An engagement name must be provided in at least English or French.'), + 'name.fr' => __('An engagement name must be provided in at least English or French.'), + ], + ], + 'Name is missing required translation' => [ + 'state' => ['name' => ['es' => 'el contrato']], + 'errors' => fn () => [ + 'name.en' => __('An engagement name must be provided in at least English or French.'), + 'name.fr' => __('An engagement name must be provided in at least English or French.'), + ], + ['without' => ['name']], + ], + 'Name translation is not a string' => [ + 'state' => ['name.en' => false], + 'errors' => fn () => ['name.en' => __('validation.string', ['attribute' => 'name.en'])], + ], + 'Description is missing' => [ + ['description' => null], + fn () => [ + 'description.en' => __('An engagement description must be provided in at least English or French.'), + 'description.fr' => __('An engagement description must be provided in at least English or French.'), + ], + ], + 'Description is missing required translation' => [ + 'state' => ['description' => ['es' => 'descripción']], + 'errors' => fn () => [ + 'description.en' => __('An engagement description must be provided in at least English or French.'), + 'description.fr' => __('An engagement description must be provided in at least English or French.'), + ], + ['without' => ['description']], + ], + 'Description translation is not a string' => [ + 'state' => ['description.en' => false], + 'errors' => fn () => ['description.en' => __('validation.string', ['attribute' => 'description.en'])], + ], + 'Window start date is missing' => [ + ['window_start_date' => null], + fn () => ['window_start_date' => __('You must enter a :attribute', ['attribute' => __('start date')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Window start date is an invalid date' => [ + ['window_start_date' => 'someday'], + fn () => ['window_start_date' => __('validation.date', ['attribute' => __('start date')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Window start date is after end date' => [ + [ + 'window_start_date' => now()->addMonths(2), + 'window_end_date' => now()->subWeek(), + ], + fn () => [ + 'window_start_date' => __('The :attribute must be before the :date.', ['attribute' => __('start date'), 'date' => __('end date')]), + 'window_end_date' => __('The :attribute must be after the :date.', ['attribute' => __('end date'), 'date' => __('start date')]), + ], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Window end date is missing' => [ + ['window_end_date' => null], + fn () => ['window_end_date' => __('You must enter a :attribute', ['attribute' => __('end date')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Window end date is an invalid date' => [ + ['window_end_date' => 'someday'], + fn () => ['window_end_date' => __('validation.date', ['attribute' => __('end date')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Window start time is missing' => [ + ['window_start_time' => null], + fn () => ['window_start_time' => __('You must enter a :attribute', ['attribute' => __('start time')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Window start time is an invalid time' => [ + ['window_start_time' => '8:00am'], + fn () => ['window_start_time' => __('The :attribute is not in the right format.', ['attribute' => __('start time')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Window start time is after end time' => [ + [ + 'window_start_time' => '11:00', + 'window_end_time' => '8:00', + ], + fn () => [ + 'window_start_time' => __('The :attribute must be before the :date.', ['attribute' => __('start time'), 'date' => __('end time')]), + 'window_end_time' => __('The :attribute must be after the :date.', ['attribute' => __('end time'), 'date' => __('start time')]), + ], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Window end time is missing' => [ + ['window_end_time' => null], + fn () => ['window_end_time' => __('You must enter a :attribute', ['attribute' => __('end time')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Window end time is an invalid time' => [ + ['window_end_time' => '1200'], + fn () => ['window_end_time' => __('The :attribute is not in the right format.', ['attribute' => __('end time')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Timezone is missing' => [ + ['timezone' => null], + fn () => ['timezone' => __('You must enter a :attribute', ['attribute' => 'timezone'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Timezone is invalid' => [ + ['timezone' => 'my timezone'], + fn () => ['timezone' => __('You must enter a :attribute', ['attribute' => 'timezone'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Window flexibility is not a boolean value' => [ + ['window_flexibility' => ['false']], + fn () => ['window_flexibility' => __('validation.boolean', ['attribute' => 'window flexibility'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Weekday availabilities is not an array' => [ + fn () => ['weekday_availabilities' => Availability::Available->value], + fn () => [ + 'weekday_availabilities' => __('validation.array', ['attribute' => 'weekday availabilities']), + 'weekday_availabilities.monday' => __('validation.required', ['attribute' => __('availability for Monday')]), + 'weekday_availabilities.tuesday' => __('validation.required', ['attribute' => __('availability for Tuesday')]), + 'weekday_availabilities.wednesday' => __('validation.required', ['attribute' => __('availability for Wednesday')]), + 'weekday_availabilities.thursday' => __('validation.required', ['attribute' => __('availability for Thursday')]), + 'weekday_availabilities.friday' => __('validation.required', ['attribute' => __('availability for Friday')]), + 'weekday_availabilities.saturday' => __('validation.required', ['attribute' => __('availability for Saturday')]), + 'weekday_availabilities.sunday' => __('validation.required', ['attribute' => __('availability for Sunday')]), + ], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Weekday availabilities are invalid' => [ + fn () => [ + 'weekday_availabilities.monday' => 'my availability', + 'weekday_availabilities.tuesday' => 'my availability', + 'weekday_availabilities.wednesday' => 'my availability', + 'weekday_availabilities.thursday' => 'my availability', + 'weekday_availabilities.friday' => 'my availability', + 'weekday_availabilities.saturday' => 'my availability', + 'weekday_availabilities.sunday' => 'my availability', + ], + fn () => [ + 'weekday_availabilities.monday' => __('validation.in', ['attribute' => __('availability for Monday')]), + 'weekday_availabilities.tuesday' => __('validation.in', ['attribute' => __('availability for Tuesday')]), + 'weekday_availabilities.wednesday' => __('validation.in', ['attribute' => __('availability for Wednesday')]), + 'weekday_availabilities.thursday' => __('validation.in', ['attribute' => __('availability for Thursday')]), + 'weekday_availabilities.friday' => __('validation.in', ['attribute' => __('availability for Friday')]), + 'weekday_availabilities.saturday' => __('validation.in', ['attribute' => __('availability for Saturday')]), + 'weekday_availabilities.sunday' => __('validation.in', ['attribute' => __('availability for Sunday')]), + ], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Meeting types is missing' => [ + ['meeting_types' => null], + fn () => ['meeting_types' => __('You must select at least one way to attend the meeting.', ['attribute' => 'meeting types'])], + [ + 'format' => EngagementFormat::Interviews->value, + ], + ], + 'Meeting types is not an array' => [ + ['meeting_types' => MeetingType::InPerson->value], + fn () => ['meeting_types' => __('validation.array', ['attribute' => 'meeting types'])], + [ + 'format' => EngagementFormat::Interviews->value, + ], + ], + 'Meeting type is invalid' => [ + ['meeting_types' => ['my meeting']], + fn () => ['meeting_types.0' => __('You must select a valid meeting type.')], + [ + 'format' => EngagementFormat::Interviews->value, + ], + ], + 'Street address is missing' => [ + ['street_address' => null], + fn () => ['street_address' => __('You must enter a :attribute for the meeting location.', ['attribute' => 'street address'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Street address is invalid' => [ + ['street_address' => false], + fn () => ['street_address' => __('validation.string', ['attribute' => 'street address'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Unit/suite/floor is invalid' => [ + ['unit_suite_floor' => false], + fn () => ['unit_suite_floor' => __('validation.string', ['attribute' => 'unit suite floor'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Locality is missing' => [ + ['locality' => null], + fn () => ['locality' => __('You must enter a :attribute for the meeting location.', ['attribute' => __('city or town')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Locality is invalid' => [ + ['locality' => false], + fn () => ['locality' => __('validation.string', ['attribute' => __('city or town')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Region is missing' => [ + ['region' => null], + fn () => ['region' => __('You must enter a :attribute for the meeting location.', ['attribute' => __('province or territory')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Region is invalid' => [ + ['region' => 'ZZ'], + fn () => ['region' => __('validation.in', ['attribute' => __('province or territory')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Postal code is missing' => [ + ['postal_code' => null], + fn () => ['postal_code' => __('You must enter a :attribute for the meeting location.', ['attribute' => 'postal code'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Postal code is invalid' => [ + ['postal_code' => '123456'], + fn () => ['postal_code' => __('validation.postal_code')], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Directions is not an array' => [ + ['directions' => 'Use the front elevator to go to the second floor.'], + fn () => ['directions' => __('validation.array', ['attribute' => 'directions'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Meeting software is missing' => [ + ['meeting_software' => null], + fn () => ['meeting_software' => __('You must indicate the :attribute.', ['attribute' => 'meeting software'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::WebConference->value, + ], + ], + 'Meeting software is invalid' => [ + ['meeting_software' => false], + fn () => ['meeting_software' => __('validation.string', ['attribute' => 'meeting software'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::WebConference->value, + ], + ], + 'Alternative meeting software is invalid' => [ + ['alternative_meeting_software' => ['false']], + fn () => ['alternative_meeting_software' => __('validation.boolean', ['attribute' => 'alternative meeting software'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::WebConference->value, + ], + ], + 'Meeting url is missing' => [ + ['meeting_url' => null], + fn () => ['meeting_url' => __('You must enter a :attribute.', ['attribute' => __('link to join the meeting')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::WebConference->value, + ], + ], + 'Meeting url is invalid' => [ + ['meeting_url' => 'not_a_url'], + fn () => ['meeting_url' => __('validation.url', ['attribute' => __('link to join the meeting')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::WebConference->value, + ], + ], + 'Additional video information is not an array' => [ + ['additional_video_information' => 'more info'], + fn () => ['additional_video_information' => __('validation.array', ['attribute' => 'additional video information'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::WebConference->value, + ], + ], + 'Meeting phone number is missing' => [ + ['meeting_phone' => null], + fn () => ['meeting_phone' => __('validation.required', ['attribute' => __('phone number to join the meeting')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::Phone->value, + ], + ], + 'Meeting phone number is invalid' => [ + ['meeting_phone' => '1800123456'], + fn () => ['meeting_phone' => __('validation.phone', ['attribute' => __('phone number to join the meeting')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::Phone->value, + ], + ], + 'Additional phone information is not an array' => [ + ['additional_phone_information' => 'Press 1 after the beep.'], + fn () => ['additional_phone_information' => __('validation.array', ['attribute' => 'additional phone information'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::Phone->value, + ], + ], + 'Materials by date missing - interviews' => [ + ['materials_by_date' => null], + fn () => ['materials_by_date' => __('You must enter a :attribute.', ['attribute' => __('date for materials to be sent by')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Materials by date is invalid - interviews' => [ + ['materials_by_date' => 'someday'], + fn () => ['materials_by_date' => __('Please enter a valid :attribute.', ['attribute' => __('date for materials to be sent by')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Materials by date is after completed date - interviews' => [ + [ + 'materials_by_date' => now()->addMonth(5), + 'complete_by_date' => now()->addMonth(4), + ], + fn () => [ + 'materials_by_date' => __('The :attribute must be before the :date.', ['attribute' => __('date for materials to be sent by'), 'date' => __('due date')]), + 'complete_by_date' => __('The :attribute must be after the :date.', ['attribute' => __('due date'), 'date' => __('date for materials to be sent by')]), + ], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Materials by date missing - other-async' => [ + ['materials_by_date' => null], + fn () => ['materials_by_date' => __('You must enter a :attribute.', ['attribute' => __('date for materials to be sent by')])], + [ + 'format' => EngagementFormat::OtherAsync->value, + ], + ], + 'Materials by date is invalid - other-async' => [ + ['materials_by_date' => 'someday'], + fn () => ['materials_by_date' => __('Please enter a valid :attribute.', ['attribute' => __('date for materials to be sent by')])], + [ + 'format' => EngagementFormat::OtherAsync->value, + ], + ], + 'Materials by date is after completed date - other-async' => [ + [ + 'materials_by_date' => now()->addMonth(5), + 'complete_by_date' => now()->addMonth(4), + ], + fn () => [ + 'materials_by_date' => __('The :attribute must be before the :date.', ['attribute' => __('date for materials to be sent by'), 'date' => __('due date')]), + 'complete_by_date' => __('The :attribute must be after the :date.', ['attribute' => __('due date'), 'date' => __('date for materials to be sent by')]), + ], + [ + 'format' => EngagementFormat::OtherAsync->value, + ], + ], + 'Materials by date missing - survey' => [ + ['materials_by_date' => null], + fn () => ['materials_by_date' => __('You must enter a :attribute.', ['attribute' => __('date for materials to be sent by')])], + [ + 'format' => EngagementFormat::Survey->value, + ], + ], + 'Materials by date is invalid - survey' => [ + ['materials_by_date' => 'someday'], + fn () => ['materials_by_date' => __('Please enter a valid :attribute.', ['attribute' => __('date for materials to be sent by')])], + [ + 'format' => EngagementFormat::Survey->value, + ], + ], + 'Materials by date is after completed date - survey' => [ + [ + 'materials_by_date' => now()->addMonth(5), + 'complete_by_date' => now()->addMonth(4), + ], + fn () => [ + 'materials_by_date' => __('The :attribute must be before the :date.', ['attribute' => __('date for materials to be sent by'), 'date' => __('due date')]), + 'complete_by_date' => __('The :attribute must be after the :date.', ['attribute' => __('due date'), 'date' => __('date for materials to be sent by')]), + ], + [ + 'format' => EngagementFormat::Survey->value, + ], + ], + 'Complete by date missing - interviews' => [ + ['complete_by_date' => null], + fn () => ['complete_by_date' => __('You must enter a :attribute.', ['attribute' => __('due date')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Complete by date is invalid - interviews' => [ + ['complete_by_date' => 'someday'], + fn () => ['complete_by_date' => __('Please enter a valid :attribute.', ['attribute' => __('due date')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Complete by date missing - other-async' => [ + ['complete_by_date' => null], + fn () => ['complete_by_date' => __('You must enter a :attribute.', ['attribute' => __('due date')])], + [ + 'format' => EngagementFormat::OtherAsync->value, + ], + ], + 'Complete by date is invalid - other-async' => [ + ['complete_by_date' => 'someday'], + fn () => ['complete_by_date' => __('Please enter a valid :attribute.', ['attribute' => __('due date')])], + [ + 'format' => EngagementFormat::OtherAsync->value, + ], + ], + 'Complete by date missing - survey' => [ + ['complete_by_date' => null], + fn () => ['complete_by_date' => __('You must enter a :attribute.', ['attribute' => __('due date')])], + [ + 'format' => EngagementFormat::Survey->value, + ], + ], + 'Complete by date is invalid - survey' => [ + ['complete_by_date' => 'someday'], + fn () => ['complete_by_date' => __('Please enter a valid :attribute.', ['attribute' => __('due date')])], + [ + 'format' => EngagementFormat::Survey->value, + ], + ], + 'Document languages missing - other-async' => [ + ['document_languages' => null], + fn () => ['document_languages' => __('Please select a language that the engagement documents will be in.')], + [ + 'format' => EngagementFormat::OtherAsync->value, + ], + ], + 'Document languages not an array - other-async' => [ + ['document_languages' => 'en'], + fn () => ['document_languages' => __('validation.array', ['attribute' => 'document languages'])], + [ + 'format' => EngagementFormat::OtherAsync->value, + ], + ], + 'Document language is invalid - other-async' => [ + ['document_languages' => ['xx']], + fn () => ['document_languages.0' => __('Please select a language that the engagement documents will be in.')], + [ + 'format' => EngagementFormat::OtherAsync->value, + ], + ], + 'Document languages missing - survey' => [ + ['document_languages' => null], + fn () => ['document_languages' => __('Please select a language that the engagement documents will be in.')], + [ + 'format' => EngagementFormat::Survey->value, + ], + ], + 'Document languages not an array - survey' => [ + ['document_languages' => 'en'], + fn () => ['document_languages' => __('validation.array', ['attribute' => 'document languages'])], + [ + 'format' => EngagementFormat::Survey->value, + ], + ], + 'Document language is invalid - survey' => [ + ['document_languages' => ['xx']], + fn () => ['document_languages.0' => __('Please select a language that the engagement documents will be in.')], + [ + 'format' => EngagementFormat::Survey->value, + ], + ], + 'Accepted formats missing' => [ + ['accepted_formats' => null], + fn () => ['accepted_formats' => __('You must indicate the :attribute.', ['attribute' => 'accepted formats'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + 'without' => ['other_accepted_format'], + ], + ], + 'Accepted formats is not an array' => [ + ['accepted_formats' => AcceptedFormat::Writing->value], + fn () => ['accepted_formats' => __('validation.array', ['attribute' => 'accepted formats'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + 'without' => ['other_accepted_format'], + ], + ], + 'Accepted format is invalid' => [ + ['accepted_formats' => ['Text']], + fn () => ['accepted_formats.0' => __('You must select a valid format.')], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + 'without' => ['other_accepted_format'], + ], + ], + 'Other accepted formats is not a boolean' => [ + ['other_accepted_formats' => 'false'], + fn () => ['other_accepted_formats' => __('validation.boolean', ['attribute' => __('accepted formats')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Other accepted format is not a string' => [ + [ + 'other_accepted_formats' => true, + 'other_accepted_format' => ['en' => false], + ], + fn () => ['other_accepted_format.en' => __('The other accepted format must be a string.')], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Other accepted format is missing required translation' => [ + [ + 'other_accepted_formats' => true, + 'other_accepted_format' => ['es' => 'la escritura'], + ], + fn () => [ + 'other_accepted_format.en' => __('The other accepted format must be provided in at least English or French.'), + 'other_accepted_format.fr' => __('The other accepted format must be provided in at least English or French.'), + ], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + 'without' => ['other_accepted_format.en'], + ], + ], + 'Open to other formats is not a boolean' => [ + ['open_to_other_formats' => 'ture'], + fn () => ['open_to_other_formats' => __('validation.boolean', ['attribute' => 'open to other formats'])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Paid is not a boolean' => [ + ['paid' => 'false'], + fn () => ['paid' => __('validation.boolean', ['attribute' => 'paid'])], + ], + 'Signup by date is missing' => [ + ['signup_by_date' => null], + fn () => ['signup_by_date' => __('You must enter a :attribute.', ['attribute' => __('sign up deadline')])], + ], + 'Signup by date is an invalid date' => [ + ['signup_by_date' => 'someday'], + fn () => ['signup_by_date' => __('Please enter a valid date for the :attribute.', ['attribute' => __('sign up deadline')])], + ], + 'Signup by date after window start date' => [ + [ + 'window_start_date' => now()->addMonth(1), + 'signup_by_date' => now()->addMonth(2), + ], + fn () => ['signup_by_date' => __('The :attribute must be before the :date.', ['attribute' => __('sign up deadline'), 'date' => __('start date')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + 'Signup by date after materials by date' => [ + [ + 'materials_by_date' => now()->addMonth(1), + 'signup_by_date' => now()->addMonth(2), + ], + fn () => ['signup_by_date' => __('The :attribute must be before the :date.', ['attribute' => __('sign up deadline'), 'date' => __('date for materials to be sent by')])], + [ + 'format' => EngagementFormat::Interviews->value, + 'meetingType' => MeetingType::InPerson->value, + ], + ], + ]; +}); diff --git a/tests/Datasets/UpdateEngagementSelectionCriteriaRequestValidationErrors.php b/tests/Datasets/UpdateEngagementSelectionCriteriaRequestValidationErrors.php new file mode 100644 index 000000000..bb182d526 --- /dev/null +++ b/tests/Datasets/UpdateEngagementSelectionCriteriaRequestValidationErrors.php @@ -0,0 +1,335 @@ + [ + ['location_type' => null], + fn () => ['location_type' => __('validation.required', ['attribute' => 'location type'])], + ], + 'Location type is invalid' => [ + ['location_type' => 'test location'], + fn () => ['location_type' => __('validation.in', ['attribute' => 'location type'])], + ], + 'Regions is missing' => [ + fn () => ['location_type' => LocationType::Regions->value], + fn () => ['regions' => __('You must choose at least one province or territory.')], + ['regions'], + ], + 'Regions is not an array' => [ + fn () => [ + 'location_type' => LocationType::Regions->value, + 'regions' => ProvinceOrTerritory::Ontario->value, + ], + fn () => ['regions' => __('validation.array', ['attribute' => 'regions'])], + ], + 'Region is invalid' => [ + fn () => [ + 'location_type' => LocationType::Regions->value, + 'regions' => ['XX'], + ], + fn () => ['regions.0' => __('You must choose a valid province or territory')], + ], + 'Locations missing' => [ + fn () => ['location_type' => LocationType::Localities->value], + fn () => ['locations' => __('You must enter at least one city or town.')], + ['locations'], + ], + 'Locations is not an array' => [ + fn () => [ + 'location_type' => LocationType::Localities->value, + 'locations' => 'my location', + ], + fn () => ['locations' => __('validation.array', ['attribute' => 'locations'])], + ], + 'Location region is missing' => [ + fn () => [ + 'location_type' => LocationType::Localities->value, + 'locations' => [['locality' => 'my city']], + ], + fn () => ['locations.0.region' => __('You must enter a province or territory.')], + ], + 'Location region is invalid' => [ + fn () => [ + 'location_type' => LocationType::Localities->value, + 'locations' => [ + [ + 'region' => 'XX', + 'locality' => 'my city', + ], + ], + ], + fn () => ['locations.0.region' => __('You must enter a province or territory.')], + ], + 'Location locality is missing' => [ + fn () => [ + 'location_type' => LocationType::Localities->value, + 'locations' => [['region' => ProvinceOrTerritory::Ontario->value]], + ], + fn () => ['locations.0.locality' => __('You must enter a city or town.')], + ], + 'Location locality is invalid' => [ + fn () => [ + 'location_type' => LocationType::Localities->value, + 'locations' => [ + [ + 'region' => ProvinceOrTerritory::Ontario->value, + 'locality' => false, + ], + ], + ], + fn () => ['locations.0.locality' => __('You must enter a city or town.')], + ], + 'Cross disability and deaf missing' => [ + ['cross_disability_and_deaf' => null], + fn () => ['cross_disability_and_deaf' => __('validation.required', ['attribute' => 'cross disability and deaf'])], + ], + 'Cross disability and deaf is not boolean' => [ + ['cross_disability_and_deaf' => 'true'], + fn () => ['cross_disability_and_deaf' => __('validation.boolean', ['attribute' => 'cross disability and deaf'])], + ], + 'Disability types missing' => [ + [ + 'cross_disability_and_deaf' => false, + ], + fn () => ['disability_types' => __('If you are looking for a specific :attribute, you must select at least one.', ['attribute' => __('Disability or Deaf group')])], + ], + 'Disability types is not an array' => [ + [ + 'cross_disability_and_deaf' => false, + 'disability_types' => 1, + ], + fn () => ['disability_types' => __('validation.array', ['attribute' => __('Disability or Deaf group')])], + ], + 'Disability types is invalid' => [ + [ + 'cross_disability_and_deaf' => false, + 'disability_types' => [1000], + ], + fn () => ['disability_types.0' => __('You must select a valid :attribute.', ['attribute' => __('Disability or Deaf group')])], + ], + 'Intersectional missing' => [ + ['intersectional' => null], + fn () => ['intersectional' => __('validation.required', ['attribute' => 'intersectional'])], + ], + 'Intersectional is not boolean' => [ + ['intersectional' => 'false'], + fn () => ['intersectional' => __('validation.boolean', ['attribute' => 'intersectional'])], + ], + 'Other identity type missing' => [ + ['intersectional' => false], + fn () => ['other_identity_type' => __('If you are looking for a group with a specific experience or identity, you must select which type of experience or identity you are looking for.')], + ['other_identity_type'], + ], + 'Other identity type is not a string' => [ + [ + 'intersectional' => false, + 'other_identity_type' => 1234, + ], + fn () => ['other_identity_type' => __('validation.string', ['attribute' => 'other identity type'])], + ], + 'Age brackets missing' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::AgeBracket->value, + ], + fn () => ['age_brackets' => __('If you are interested in engaging a specific :attribute, you must select at least one.', ['attribute' => __('age group')])], + ['age_brackets'], + ], + 'Age brackets is not an array' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::AgeBracket->value, + 'age_brackets' => 1, + ], + fn () => ['age_brackets' => __('validation.array', ['attribute' => __('age group')])], + ], + 'Age bracket is invalid' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::AgeBracket->value, + 'age_brackets' => [1000], + ], + fn () => ['age_brackets.0' => __('You must select a valid :attribute.', ['attribute' => __('age group')])], + ], + 'Gender and sexual identities missing' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::GenderAndSexualIdentity->value, + ], + fn () => ['gender_and_sexual_identities' => __('If you are interested in engaging a specific :attribute, you must select at least one.', ['attribute' => __('gender or sexual identity group')])], + ['gender_and_sexual_identities'], + ], + 'Gender and sexual identities is not an array' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::GenderAndSexualIdentity->value, + 'gender_and_sexual_identities' => 1, + ], + fn () => ['gender_and_sexual_identities' => __('validation.array', ['attribute' => __('gender or sexual identity group')])], + ], + 'Gender and sexual identity is invalid' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::GenderAndSexualIdentity->value, + 'gender_and_sexual_identities' => [1000], + ], + fn () => ['gender_and_sexual_identities.0' => __('You must select a valid :attribute.', ['attribute' => __('gender or sexual identity group')])], + ], + 'Non-binary/Gender non-conforming/Fluid identity missing' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::GenderAndSexualIdentity->value, + 'gender-and-sexual-identity' => [], + ], + fn () => ['nb_gnc_fluid_identity' => __('If you are interested in engaging a specific :attribute, you must select at least one.', ['attribute' => __('gender or sexual identity group')])], + ['nb_gnc_fluid_identity'], + ], + 'Non-binary/Gender non-conforming/Fluid identity is not boolean' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::GenderAndSexualIdentity->value, + 'gender-and-sexual-identity' => [], + 'nb_gnc_fluid_identity' => 'false', + ], + fn () => ['nb_gnc_fluid_identity' => __('validation.boolean', ['attribute' => __('Non-binary/Gender non-conforming/Gender fluid identity')])], + ], + 'Indigenous identities missing' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::IndigenousIdentity->value, + ], + fn () => ['indigenous_identities' => __('If you are interested in engaging a specific :attribute, you must select at least one.', ['attribute' => __('Indigenous group')])], + ['indigenous_identities'], + ], + 'Indigenous identities is not an array' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::IndigenousIdentity->value, + 'indigenous_identities' => 1, + ], + fn () => ['indigenous_identities' => __('validation.array', ['attribute' => __('Indigenous group')])], + ], + 'Indigenous identity is invalid' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::IndigenousIdentity->value, + 'indigenous_identities' => [1000], + ], + fn () => ['indigenous_identities.0' => __('You must select a valid :attribute.', ['attribute' => __('Indigenous group')])], + ], + 'Ethnoracial identities missing' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::EthnoracialIdentity->value, + ], + fn () => ['ethnoracial_identities' => __('If you are interested in engaging a specific :attribute, you must select at least one.', ['attribute' => __('ethnoracial group')])], + ['ethnoracial_identities'], + ], + 'Ethnoracial identities is not an array' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::EthnoracialIdentity->value, + 'ethnoracial_identities' => 1, + ], + fn () => ['ethnoracial_identities' => __('validation.array', ['attribute' => __('ethnoracial group')])], + ], + 'Ethnoracial identity is invalid' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::EthnoracialIdentity->value, + 'ethnoracial_identities' => [1000], + ], + fn () => ['ethnoracial_identities.0' => __('You must select a valid :attribute.', ['attribute' => __('ethnoracial group')])], + ], + 'First languages missing' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::FirstLanguage->value, + ], + fn () => ['first_languages' => __('If you are interested in engaging a specific :attribute, you must select at least one.', ['attribute' => __('first language')])], + ['first_languages'], + ], + 'First languages is not an array' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::FirstLanguage->value, + 'first_languages' => 1, + ], + fn () => ['first_languages' => __('validation.array', ['attribute' => __('first language')])], + ], + 'First language is invalid' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::FirstLanguage->value, + 'first_languages' => ['XX'], + ], + fn () => ['first_languages.0' => __('You must select a valid :attribute.', ['attribute' => __('first language')])], + ], + 'Area types missing' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::AreaType->value, + ], + fn () => ['area_types' => __('If you are interested in engaging a specific :attribute, you must select at least one.', ['attribute' => __('area type')])], + ['area_types'], + ], + 'Area types is not an array' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::AreaType->value, + 'area_types' => 1, + ], + fn () => ['area_types' => __('validation.array', ['attribute' => __('area type')])], + ], + 'Area type is invalid' => [ + [ + 'intersectional' => false, + 'other_identity_type' => IdentityType::AreaType->value, + 'area_types' => [1000], + ], + fn () => ['area_types.0' => __('You must select a valid :attribute.', ['attribute' => __('area type')])], + ], + 'Ideal participants is missing' => [ + ['ideal_participants' => null], + fn () => ['ideal_participants' => __('validation.required', ['attribute' => __('ideal number of participants')])], + ['ideal_participants'], + ], + 'Ideal participants is not an integer' => [ + ['ideal_participants' => 'ten'], + fn () => ['ideal_participants' => __('validation.integer', ['attribute' => __('ideal number of participants')])], + ], + 'Ideal participants is below minimum' => [ + [ + 'minimum_participants' => 5, + 'ideal_participants' => 8, + ], + fn () => ['ideal_participants' => __('validation.min.numeric', ['attribute' => __('ideal number of participants'), 'min' => 10])], + ], + 'Minimum participants is missing' => [ + ['minimum_participants' => null], + fn () => ['minimum_participants' => __('You must enter a :attribute.', ['attribute' => __('minimum number of participants')])], + ['minimum_participants'], + ], + 'Minimum participants is not an integer' => [ + ['minimum_participants' => 'ten'], + fn () => ['minimum_participants' => __('The :attribute must be a number.', ['attribute' => __('minimum number of participants')])], + ], + 'Minimum participants is below minimum' => [ + [ + 'minimum_participants' => 8, + ], + fn () => ['minimum_participants' => __('validation.min.numeric', ['attribute' => __('minimum number of participants'), 'min' => 10])], + ], + 'Minimum participants is more than ideal participants' => [ + [ + 'minimum_participants' => 15, + 'ideal_participants' => 12, + ], + fn () => ['minimum_participants' => __('Please enter a :attribute that is less than or the same as the ideal number of participants.', ['attribute' => __('minimum number of participants')])], + ], + ]; +}); diff --git a/tests/Datasets/UpdateIndividualRequestValidationErrors.php b/tests/Datasets/UpdateIndividualRequestValidationErrors.php new file mode 100644 index 000000000..82d62e036 --- /dev/null +++ b/tests/Datasets/UpdateIndividualRequestValidationErrors.php @@ -0,0 +1,82 @@ + [ + ['name' => null], + fn () => ['name' => __('validation.required', ['attribute' => 'name'])], + ['name'], + ], + 'Name not a string' => [ + ['name' => false], + fn () => ['name' => __('validation.string', ['attribute' => 'name'])], + ], + 'Name too long' => [ + ['name' => '4wdjO$bfTeX4m7ya+WTGK10ywy=3tZhfrHnFkx3ZgC8Uyn1a441EjhDw0HqyFm*btGHQneD=q@+bcJEj$owvxR#bsnb+sdm5Xw+a4wdjO$bfTeX4m7ya+WTGK10ywy=3tZhfrHnFkx3ZgC8Uyn1a441EjhDw0HqyFm*btGHQneD=q@+bcJEj$owvxR#bsnb+sdm5Xw+a4wdjO$bfTeX4m7ya+WTGK10ywy=3tZhfrHnFkx3ZgC8Uyn1a441EjhDw0HqyFm*btGHQneD=q@+bcJEj$owvxR#bsnb+sdm5Xw+a'], + fn () => ['name' => __('validation.max.string', ['attribute' => 'name', 'max' => 255])], + ], + 'Missing region' => [ + ['region' => null], + fn () => ['region' => __('validation.required', ['attribute' => __('province or territory')])], + ['region'], + ], + 'Invalid region' => [ + ['region' => 'zz'], + fn () => ['region' => __('validation.in', ['attribute' => __('province or territory')])], + ], + 'Pronouns translation not an array' => [ + ['pronouns' => 'She'], + fn () => ['pronouns' => __('Your pronouns must be provided in at least English or French.')], + ], + 'Invalid pronoun translation' => [ + ['pronouns' => ['es' => 'Ella']], + fn () => ['pronouns' => __('Your pronouns must be provided in at least English or French.')], + ], + 'Bio missing' => [ + ['bio' => null], + fn () => ['bio' => __('validation.required', ['attribute' => 'bio'])], + ['bio'], + ], + 'Bio not an array' => [ + ['bio' => 'en'], + fn () => ['bio' => __('Your bio must be provided in at least English or French.')], + ], + 'Invalid bio translation' => [ + ['bio' => ['123' => 'test language', 'en' => 'my bio']], + fn () => ['bio' => __('Your bio must be provided in at least English or French.')], + ], + 'Bio translation not a string' => [ + ['bio' => ['en' => [123]]], + fn () => ['bio.en' => __('validation.string', ['attribute' => 'bio.en'])], + ], + 'Bio missing required translation' => [ + ['bio' => ['es' => 'biografía']], + fn () => [ + 'bio' => __('Your bio must be provided in at least English or French.'), + 'bio.en' => __('Your bio must be provided in at least English or French.'), + 'bio.fr' => __('Your bio must be provided in at least English or French.'), + ], + ['bio.en'], + ], + 'Working languages not an array' => [ + ['working_languages' => 'en'], + fn () => ['working_languages' => __('validation.array', ['attribute' => 'working languages'])], + ], + 'Consulting services not an array' => [ + ['consulting_services' => 'analysis'], + fn () => ['consulting_services' => __('validation.array', ['attribute' => 'consulting services'])], + ], + 'Consulting service invalid' => [ + ['consulting_services' => ['test-service']], + fn () => ['consulting_services.0' => __('The selected consulting service is invalid')], + ], + 'Social link is not an active URL' => [ + ['social_links' => ['Test' => 'https://example.fake/']], + fn () => ['social_links.Test' => __('You must enter a valid link for :key.', ['key' => 'Test'])], + ], + 'Website link is not an active URL' => [ + ['website_link' => 'https://example.fake/'], + fn () => ['website_link' => __('You must enter a valid website link.')], + ], + ]; +}); diff --git a/tests/Feature/EngagementTest.php b/tests/Feature/EngagementTest.php index f68c0e56f..733fd027d 100644 --- a/tests/Feature/EngagementTest.php +++ b/tests/Feature/EngagementTest.php @@ -1,6 +1,10 @@ assertOk(); $data = UpdateEngagementSelectionCriteriaRequest::factory()->create([ - 'location_type' => 'localities', + 'location_type' => LocationType::Localities->value, 'regions' => $engagement->matchingStrategy->regions ?? [], 'locations' => [ [ @@ -191,7 +195,7 @@ Identity::whereJsonContains('clusters', IdentityCluster::DisabilityAndDeaf)->first()->id, ], 'intersectional' => 0, - 'other_identity_type' => 'age-bracket', + 'other_identity_type' => IdentityType::AgeBracket->value, 'age_brackets' => [Identity::whereJsonContains('clusters', IdentityCluster::Age)->first()->id], ]); @@ -207,7 +211,7 @@ $data = UpdateEngagementSelectionCriteriaRequest::factory()->create([ 'intersectional' => 0, - 'other_identity_type' => 'gender-and-sexual-identity', + 'other_identity_type' => IdentityType::GenderAndSexualIdentity->value, 'nb_gnc_fluid_identity' => 1, 'gender_and_sexual_identities' => [Identity::whereJsonContains('clusters', IdentityCluster::GenderAndSexuality)->first()->id], ]); @@ -225,7 +229,7 @@ $data = UpdateEngagementSelectionCriteriaRequest::factory()->create([ 'intersectional' => 0, - 'other_identity_type' => 'indigenous-identity', + 'other_identity_type' => IdentityType::IndigenousIdentity->value, 'indigenous_identities' => Identity::whereJsonContains('clusters', IdentityCluster::Indigenous)->get()->modelKeys(), ]); @@ -241,7 +245,7 @@ $data = UpdateEngagementSelectionCriteriaRequest::factory()->create([ 'intersectional' => 0, - 'other_identity_type' => 'ethnoracial-identity', + 'other_identity_type' => IdentityType::EthnoracialIdentity->value, 'ethnoracial_identities' => Identity::whereJsonContains('clusters', IdentityCluster::Ethnoracial)->pluck('id')->toArray(), ]); @@ -257,7 +261,7 @@ $data = UpdateEngagementSelectionCriteriaRequest::factory()->create([ 'intersectional' => 0, - 'other_identity_type' => 'refugee-or-immigrant', + 'other_identity_type' => IdentityType::RefugeeOrImmigrant->value, ]); $response = $this->actingAs($user)->put(localized_route('engagements.update-criteria', $engagement), $data); @@ -272,7 +276,7 @@ $data = UpdateEngagementSelectionCriteriaRequest::factory()->create([ 'intersectional' => 0, - 'other_identity_type' => 'first-language', + 'other_identity_type' => IdentityType::FirstLanguage->value, 'first_languages' => ['fr', 'lsq'], ]); @@ -287,7 +291,7 @@ $data = UpdateEngagementSelectionCriteriaRequest::factory()->create([ 'intersectional' => 0, - 'other_identity_type' => 'area-type', + 'other_identity_type' => IdentityType::AreaType->value, 'area_types' => Identity::whereJsonContains('clusters', IdentityCluster::Area)->pluck('id')->toArray(), ]); @@ -398,6 +402,68 @@ $response->assertForbidden(); }); +test('update engagement request validation errors', function ($state, $errors, $modifiers = []) { + $user = User::factory()->create(['context' => UserContext::RegulatedOrganization->value]); + $regulatedOrganization = RegulatedOrganization::factory() + ->hasAttached($user, ['role' => 'admin']) + ->create(); + $project = Project::factory()->create([ + 'projectable_id' => $regulatedOrganization->id, + ]); + $format = $modifiers['format'] ?? EngagementFormat::Workshop->value; + $engagement = Engagement::factory()->create([ + 'project_id' => $project->id, + 'format' => $format, + ]); + + $requestFactory = UpdateEngagementRequest::factory(); + + $formatTransformer = match ($format) { + EngagementFormat::Interviews->value => 'formatInterview', + EngagementFormat::Survey->value, EngagementFormat::OtherAsync->value => 'formatAsync', + default => null + }; + + if ($formatTransformer) { + $requestFactory = $requestFactory->$formatTransformer(); + } + + $meetingTypeTransformer = match ($modifiers['meetingType'] ?? '') { + MeetingType::InPerson->value => 'meetingInPerson', + MeetingType::Phone->value => 'meetingPhone', + MeetingType::WebConference->value => 'meetingWebConference', + default => null + }; + + if ($meetingTypeTransformer) { + $requestFactory = $requestFactory->$meetingTypeTransformer(); + } + + $data = $requestFactory->without($modifiers['without'] ?? [])->create($state); + + $response = $this->actingAs($user)->put(localized_route('engagements.update', $engagement), $data); + $response->assertSessionHasErrors($errors); +})->with('updateEngagementRequestValidationErrors'); + +test('update engagement selection criteria request validation errors', function ($state, $errors, $without = []) { + $user = User::factory()->create(['context' => UserContext::RegulatedOrganization->value]); + $regulatedOrganization = RegulatedOrganization::factory() + ->hasAttached($user, ['role' => 'admin']) + ->create(); + $project = Project::factory()->create([ + 'projectable_id' => $regulatedOrganization->id, + ]); + $engagement = Engagement::factory()->create([ + 'project_id' => $project->id, + ]); + + $requestFactory = UpdateEngagementSelectionCriteriaRequest::factory(); + + $data = $requestFactory->without($without ?? [])->create($state); + $response = $this->actingAs($user)->put(localized_route('engagements.update-criteria', $engagement), $data); + $response->assertSessionHasErrors($errors); +})->with('updateEngagementSelectionCriteriaRequestValidationErrors'); + test('users with regulated organization admin role can manage engagements', function () { $this->seed(IdentitySeeder::class); diff --git a/tests/Feature/IndividualTest.php b/tests/Feature/IndividualTest.php index 91f96d09f..01c406701 100644 --- a/tests/Feature/IndividualTest.php +++ b/tests/Feature/IndividualTest.php @@ -3,8 +3,10 @@ use App\Enums\CommunityConnectorHasLivedExperience; use App\Enums\EngagementFormat; use App\Enums\IdentityCluster; +use App\Enums\IndividualRole; use App\Enums\MeetingType; use App\Http\Requests\UpdateIndividualConstituenciesRequest; +use App\Http\Requests\UpdateIndividualRequest; use App\Models\Engagement; use App\Models\Identity; use App\Models\Impact; @@ -127,6 +129,16 @@ expect(flash()->message)->toBe($expected['message']($individual)); })->with('individualRoleChange'); +test('save roles request validation errors', function ($data, $errors) { + $individual = Individual::factory() + ->for(User::factory()) + ->create(['roles' => null]); + + $response = $this->actingAs($individual->user) + ->put(localized_route('individuals.save-roles'), $data); + $response->assertSessionHasErrors($errors); +})->with('saveIndividualRolesRequestValidationErrors'); + test('users can create individual pages', function () { $this->seed(ImpactSeeder::class); $this->seed(SectorSeeder::class); @@ -694,6 +706,55 @@ $response->assertForbidden(); }); +test('update individual request validation errors', function ($state, $errors, $without = []) { + $roles = [ + IndividualRole::CommunityConnector, + IndividualRole::ConsultationParticipant, + ]; + + if (array_key_exists('consulting_services', $state)) { + $roles[] = IndividualRole::AccessibilityConsultant; + } + + $individual = Individual::factory() + ->for(User::factory()) + ->create(['roles' => $roles]); + + $data = UpdateIndividualRequest::factory()->without($without ?? [])->create($state); + + $response = $this->actingAs($individual->user) + ->put(localized_route('individuals.update', $individual), $data); + $response->assertSessionHasErrors($errors); +})->with('updateIndividualRequestValidationErrors'); + +test('updating social links without an array should ignore the change', function () { + $individual = Individual::factory() + ->for(User::factory()) + ->create([ + 'roles' => [ + IndividualRole::CommunityConnector, + IndividualRole::ConsultationParticipant, + ], + 'social_links' => [ + 'facebook' => 'https://facebook.com', + ], + ]); + + $response = $this->actingAs($individual->user) + ->put(localized_route('individuals.update', $individual), [ + 'name' => $individual->name, + 'region' => $individual->region, + 'bio' => ['en' => 'base bio'], + 'social_links' => 'https://google.ca', + ]); + $response->assertSessionHasNoErrors(); + $response->assertRedirect(localized_route('individuals.edit', ['individual' => $individual, 'step' => 1])); + + $individual->refresh(); + expect($individual->social_links)->toHaveCount(1); + expect($individual->social_links['facebook'])->toBe('https://facebook.com'); +}); + test('users can delete individual pages', function () { $user = User::factory()->create(); $individual = $user->individual; diff --git a/tests/Feature/InvitationTest.php b/tests/Feature/InvitationTest.php new file mode 100644 index 000000000..f2ca08798 --- /dev/null +++ b/tests/Feature/InvitationTest.php @@ -0,0 +1,177 @@ +create(['context' => UserContext::RegulatedOrganization->value]); + + $regulatedOrganization = RegulatedOrganization::factory() + ->hasAttached($user, ['role' => TeamRole::Administrator->value]) + ->create(); + + $response = $this->actingAs($user)->post(localized_route('invitations.create'), [ + 'invitationable_id' => $regulatedOrganization->id, + 'invitationable_type' => get_class($regulatedOrganization), + 'email' => 'newuser@here.com', + 'role' => TeamRole::Member->value, + ]); + + $response->assertSessionHasNoErrors(); + expect(flash()->class)->toBe('success'); + expect(flash()->message)->toBe(__('invitation.create_invitation_succeeded')); + + Mail::assertSent(InvitationMessage::class, function (InvitationMessage $mail) { + return $mail->hasTo('newuser@here.com'); + }); + + $response->assertRedirect(localized_route('settings.edit-roles-and-permissions')); +}); + +test('create invitation validation errors', function ($data, $errors) { + Mail::fake(); + + $user = User::factory()->create([ + 'context' => UserContext::RegulatedOrganization->value, + 'email' => 'invitation.existing.member.test@example.com', + ]); + + $regulatedOrganization = RegulatedOrganization::factory() + ->hasAttached($user, ['role' => TeamRole::Administrator->value]) + ->create(); + + Invitation::factory()->create([ + 'invitationable_id' => $regulatedOrganization->id, + 'invitationable_type' => get_class($regulatedOrganization), + 'email' => 'invitation.sent.test@example.com', + ]); + + $postData = array_merge([ + 'email' => 'invitation.user.test@example.com', + 'role' => TeamRole::Member->value, + 'invitationable_id' => $regulatedOrganization->id, + 'invitationable_type' => get_class($regulatedOrganization), + ], $data); + + $response = $this->actingAs($user)->post(localized_route('invitations.create'), $postData); + + $response->assertSessionHasErrors($errors); + + Mail::assertNothingOutgoing(); +})->with('storeInvitationRequestValidationErrors'); + +test('accept invitation request', function () { + $user = User::factory()->create(['context' => UserContext::RegulatedOrganization->value]); + $regulatedOrganization = RegulatedOrganization::factory()->create(); + $invitation = Invitation::factory()->create([ + 'invitationable_id' => $regulatedOrganization->id, + 'invitationable_type' => get_class($regulatedOrganization), + 'email' => $user->email, + ]); + + $acceptUrl = URL::signedRoute('invitations.accept', ['invitation' => $invitation]); + + $response = $this->actingAs($user)->get($acceptUrl); + $response->assertSessionHasNoErrors(); + expect(flash()->class)->toBe('success'); + expect(flash()->message)->toBe(__('invitation.accept_invitation_succeeded', ['invitationable' => $regulatedOrganization->name])); + + $this->assertTrue($regulatedOrganization->fresh()->hasUserWithEmail($user->email)); + $response->assertRedirect(localized_route('dashboard')); +}); + +test('accept invitation request - validation errors: existing member', function () { + $user = User::factory()->create(['context' => UserContext::RegulatedOrganization->value]); + + $regulatedOrganization = RegulatedOrganization::factory() + ->hasAttached($user, ['role' => TeamRole::Member->value]) + ->create(); + + $invitation = Invitation::factory()->create([ + 'invitationable_id' => $regulatedOrganization->id, + 'invitationable_type' => get_class($regulatedOrganization), + 'email' => $user->email, + ]); + + $acceptUrl = URL::signedRoute('invitations.accept', ['invitation' => $invitation]); + + $response = $this->actingAs($user)->get($acceptUrl); + $response->assertSessionHasErrors([ + 'email' => __('invitation.invited_user_already_belongs_to_this_team'), + ], errorBag: 'acceptInvitation'); +}); + +test('accept invitation request - validation errors: member of other team', function () { + $user = User::factory()->create(['context' => UserContext::RegulatedOrganization->value]); + + RegulatedOrganization::factory() + ->hasAttached($user, ['role' => TeamRole::Member->value]) + ->create(); + + $regulatedOrganization = RegulatedOrganization::factory()->create(); + + $invitation = Invitation::factory()->create([ + 'invitationable_id' => $regulatedOrganization->id, + 'invitationable_type' => get_class($regulatedOrganization), + 'email' => $user->email, + ]); + + $acceptUrl = URL::signedRoute('invitations.accept', ['invitation' => $invitation]); + + $response = $this->actingAs($user)->get($acceptUrl); + $response->assertSessionHasErrors([ + 'email' => __('invitation.invited_user_already_belongs_to_a_team'), + ], errorBag: 'acceptInvitation'); +}); + +test('decline invitation request', function () { + $user = User::factory()->create(['context' => UserContext::RegulatedOrganization->value]); + $regulatedOrganization = RegulatedOrganization::factory()->create(); + $invitation = Invitation::factory()->create([ + 'invitationable_id' => $regulatedOrganization->id, + 'invitationable_type' => get_class($regulatedOrganization), + 'email' => $user->email, + ]); + + $response = $this->actingAs($user)->delete(route('invitations.decline', $invitation)); + $response->assertSessionHasNoErrors(); + expect(flash()->class)->toBe('success'); + expect(flash()->message)->toBe(__('invitation.decline_invitation_succeeded', ['invitationable' => $regulatedOrganization->name])); + + expect(Invitation::find($invitation))->toHaveCount(0); + + $response->assertRedirect(localized_route('dashboard')); +}); + +test('destroy invitation', function () { + $user = User::factory()->create(['context' => UserContext::RegulatedOrganization->value]); + + $regulatedOrganization = RegulatedOrganization::factory() + ->hasAttached($user, ['role' => TeamRole::Administrator->value]) + ->create(); + + $invitation = Invitation::factory()->create([ + 'invitationable_id' => $regulatedOrganization->id, + 'invitationable_type' => get_class($regulatedOrganization), + 'email' => 'newuser@here.com', + ]); + + $response = $this->actingAs($user)->delete(route('invitations.destroy', $invitation)); + $response->assertSessionHasNoErrors(); + expect(flash()->class)->toBe('success'); + expect(flash()->message)->toBe(__('invitation.cancel_invitation_succeeded')); + + expect(Invitation::find($invitation))->toHaveCount(0); + + $response->assertRedirect(localized_route('settings.edit-roles-and-permissions')); +}); diff --git a/tests/Feature/MeetingTest.php b/tests/Feature/MeetingTest.php index 4e41a0838..8360bbdfa 100644 --- a/tests/Feature/MeetingTest.php +++ b/tests/Feature/MeetingTest.php @@ -1,5 +1,8 @@ display_meeting_types)->toContain('Virtual – web conference'); }); +test('Meeting request validation errors', function ($state, $errors, $modifiers = []) { + $user = User::factory()->create(['context' => UserContext::RegulatedOrganization->value]); + $regulatedOrganization = RegulatedOrganization::factory() + ->hasAttached($user, ['role' => 'admin']) + ->has(Project::factory()->has(Engagement::factory()->has(Meeting::factory()))) + ->create(); + + $engagement = $regulatedOrganization->projects->first()->engagements->first(); + $meeting = $engagement->meetings->first(); + + $requestFactory = MeetingRequest::factory(); + + $meetingTypeTransformer = match ($modifiers['meetingType'] ?? '') { + MeetingType::InPerson->value => 'inPerson', + MeetingType::Phone->value => 'phone', + MeetingType::WebConference->value => 'webConference', + default => null + }; + + if ($meetingTypeTransformer) { + $requestFactory = $requestFactory->$meetingTypeTransformer(); + } + + $data = $requestFactory->without($modifiers['without'] ?? [])->create($state); + + // create meeting + $response = $this->actingAs($user)->post(localized_route('meetings.store', $engagement), $data); + $response->assertSessionHasErrors($errors); + + // update existing meeting + $response = $this->actingAs($user)->post(localized_route('meetings.update', ['meeting' => $meeting, 'engagement' => $engagement]), $data); + $response->assertSessionHasErrors($errors); +})->with('meetingRequestValidationErrors'); + test('meetings can be deleted', function () { $this->seed(IdentitySeeder::class); diff --git a/tests/Feature/NotificationListTest.php b/tests/Feature/NotificationListTest.php index 56372c73d..9b4a709e9 100644 --- a/tests/Feature/NotificationListTest.php +++ b/tests/Feature/NotificationListTest.php @@ -133,3 +133,40 @@ $nullUser = null; expect($organization->isNotifying($nullUser))->toBeFalse(); }); + +test('add notificationable validation errors', function ($data, $errors = null) { + $user = User::factory()->create(); + $organization = Organization::factory()->create(['name' => ['en' => 'Umbrella Corporation'], 'published_at' => now()]); + + $baseData = [ + 'notificationable_type' => get_class($organization), + 'notificationable_id' => $organization->id, + ]; + + $alternateData = [ + 'notificationable_type' => User::class, + 'notificationable_id' => $user->id, + ]; + + $response = $this->actingAs($user)->post(localized_route('notification-list.add'), array_merge($baseData, empty($data) ? $alternateData : $data)); + + if (isset($errors)) { + $response->assertSessionHasErrors($errors); + } else { + $response->assertForbidden(); + } +})->with('addNotificaitonableRequestValidationErrors'); + +test('remove notificationable validation errors', function ($data, $errors) { + $user = User::factory()->create(); + $organization = Organization::factory()->create(['name' => ['en' => 'Umbrella Corporation'], 'published_at' => now()]); + + $baseData = [ + 'notificationable_type' => get_class($organization), + 'notificationable_id' => $organization->id, + ]; + + $response = $this->actingAs($user)->post(localized_route('notification-list.remove'), array_merge($baseData, $data)); + + $response->assertSessionHasErrors($errors); +})->with('removeNotificaitonableRequestValidationErrors'); diff --git a/tests/Feature/TranslationTest.php b/tests/Feature/TranslationTest.php index 8db21e0e7..6bf2156b0 100644 --- a/tests/Feature/TranslationTest.php +++ b/tests/Feature/TranslationTest.php @@ -17,8 +17,32 @@ $individual = $individual->fresh(); expect(in_array('asl', $individual->languages))->toBeTrue(); + expect(flash()->class)->toBe('success'); + expect(flash()->message)->toBe(__('Language :language added.', ['language' => get_language_exonym('asl')])); }); +test('add translation validation errors', function ($data, $errors = null) { + $individual = Individual::factory()->create([ + 'name' => 'Tester', + 'roles' => ['consultant'], + ]); + + $baseData = [ + 'translatable_type' => get_class($individual), + 'translatable_id' => $individual->id, + 'new_language' => 'asl', + ]; + + $response = $this->actingAs($individual->user) + ->put(localized_route('translations.add'), array_merge($baseData, $data)); + + if (isset($errors)) { + $response->assertSessionHasErrors($errors); + } else { + $response->assertForbidden(); + } +})->with('addTranslationRequestValidationErrors'); + test('removing a translation succeeds for a valid translatable model', function () { $individual = Individual::factory()->create(['roles' => ['consultant']]); @@ -34,4 +58,28 @@ $individual = $individual->fresh(); expect(in_array('fr', $individual->languages))->toBeFalse(); + expect(flash()->class)->toBe('success'); + expect(flash()->message)->toBe(__('Language :language removed.', ['language' => get_language_exonym('fr')])); }); + +test('destroy translation validation errors', function ($data, $errors = null) { + $individual = Individual::factory()->create([ + 'name' => 'Tester', + 'roles' => ['consultant'], + ]); + + $baseData = [ + 'translatable_type' => get_class($individual), + 'translatable_id' => $individual->id, + 'new_language' => 'asl', + ]; + + $response = $this->actingAs($individual->user) + ->put(localized_route('translations.destroy'), array_merge($baseData, $data)); + + if (isset($errors)) { + $response->assertSessionHasErrors($errors); + } else { + $response->assertForbidden(); + } +})->with('destroyTranslationRequestValidationErrors'); diff --git a/tests/RequestFactories/MeetingRequestFactory.php b/tests/RequestFactories/MeetingRequestFactory.php new file mode 100644 index 000000000..e5aab680f --- /dev/null +++ b/tests/RequestFactories/MeetingRequestFactory.php @@ -0,0 +1,54 @@ + ['en' => $this->faker->words(3, true)], + 'date' => now()->addMonth(), + 'start_time' => '9:00', + 'end_time' => '13:00', + 'timezone' => $this->faker->timezone(), + ]; + } + + public function inPerson(): static + { + return $this->state([ + 'meeting_types' => [MeetingType::InPerson->value], + 'street_address' => $this->faker->streetAddress(), + 'unit_suite_floor' => $this->faker->boolean(50) ? $this->faker->secondaryAddress() : null, + 'locality' => $this->faker->city(), + 'region' => $this->faker->randomElement(ProvinceOrTerritory::class)->value, + 'postal_code' => $this->faker->regexify('[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJ-NPRSTV-Z] ?\d[ABCEGHJ-NPRSTV-Z]\d'), + 'directions' => $this->faker->boolean(50) ? ['en' => $this->faker->paragraph()] : null, + ]); + } + + public function phone(): static + { + return $this->state([ + 'meeting_types' => [MeetingType::Phone->value], + 'meeting_phone' => '1 (888) 867-0053', + 'additional_phone_information' => $this->faker->boolean(50) ? ['en' => $this->faker->paragraph()] : null, + ]); + } + + public function webConference(): static + { + return $this->state([ + 'meeting_types' => [MeetingType::WebConference->value], + 'meeting_software' => $this->faker->word(), + 'alternative_meeting_software' => $this->faker->boolean(50) ? $this->faker->boolean(50) : null, + 'meeting_url' => $this->faker->url(), + 'additional_video_information' => $this->faker->boolean(50) ? ['en' => $this->faker->paragraph()] : null, + ]); + } +} diff --git a/tests/RequestFactories/UpdateEngagementRequestFactory.php b/tests/RequestFactories/UpdateEngagementRequestFactory.php index 6a6643ca0..b3374d98b 100644 --- a/tests/RequestFactories/UpdateEngagementRequestFactory.php +++ b/tests/RequestFactories/UpdateEngagementRequestFactory.php @@ -2,6 +2,10 @@ namespace Tests\RequestFactories; +use App\Enums\AcceptedFormat; +use App\Enums\Availability; +use App\Enums\MeetingType; +use App\Enums\ProvinceOrTerritory; use Worksome\RequestFactories\RequestFactory; class UpdateEngagementRequestFactory extends RequestFactory @@ -11,7 +15,81 @@ public function definition(): array return [ 'name' => ['en' => 'Workshop'], 'description' => ['en' => $this->faker->paragraph()], - 'signup_by_date' => $this->faker->dateTimeBetween('+1 months', '+6 months')->format('Y-m-d'), + 'signup_by_date' => now()->addMonth(1), + 'paid' => $this->faker->boolean(50), ]; } + + public function meetingInPerson(): static + { + return $this->state([ + 'meeting_types' => [MeetingType::InPerson->value], + 'street_address' => $this->faker->streetAddress(), + 'unit_suite_floor' => $this->faker->boolean(50) ? $this->faker->secondaryAddress() : null, + 'locality' => $this->faker->city(), + 'region' => $this->faker->randomElement(ProvinceOrTerritory::class)->value, + 'postal_code' => $this->faker->regexify('[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJ-NPRSTV-Z] ?\d[ABCEGHJ-NPRSTV-Z]\d'), + 'directions' => $this->faker->boolean(50) ? ['en' => $this->faker->paragraph()] : null, + ]); + } + + public function meetingWebConference(): static + { + return $this->state([ + 'meeting_types' => [MeetingType::WebConference->value], + 'meeting_software' => $this->faker->word(), + 'alternative_meeting_software' => $this->faker->boolean(50) ? $this->faker->boolean(50) : null, + 'meeting_url' => $this->faker->url(), + 'additional_video_information' => $this->faker->boolean(50) ? ['en' => $this->faker->paragraph()] : null, + ]); + } + + public function meetingPhone(): static + { + return $this->state([ + 'meeting_types' => [MeetingType::Phone->value], + 'meeting_phone' => '1 (888) 867-0053', + 'additional_phone_information' => $this->faker->boolean(50) ? ['en' => $this->faker->paragraph()] : null, + ]); + } + + public function formatInterview(): static + { + return $this->state([ + 'window_start_date' => now()->addMonth(3), + 'window_end_date' => now()->addMonths(6), + 'window_start_time' => '9:00', + 'window_end_time' => '13:00', + 'timezone' => $this->faker->timezone(), + 'window_flexibility' => $this->faker->boolean(50) ? $this->faker->boolean(50) : null, + 'weekday_availabilities' => [ + 'monday' => $this->faker->randomElement(Availability::class)->value, + 'tuesday' => $this->faker->randomElement(Availability::class)->value, + 'wednesday' => $this->faker->randomElement(Availability::class)->value, + 'thursday' => $this->faker->randomElement(Availability::class)->value, + 'friday' => $this->faker->randomElement(Availability::class)->value, + 'saturday' => $this->faker->randomElement(Availability::class)->value, + 'sunday' => $this->faker->randomElement(Availability::class)->value, + ], + 'materials_by_date' => now()->addMonth(3), + 'complete_by_date' => now()->addMonth(6), + 'accepted_formats' => function (array $attributes) { + return empty($attributes['other_accepted_formats']) || $this->faker->boolean(50) ? $this->faker->randomElements(AcceptedFormat::class, null) : null; + }, + 'other_accepted_format' => function (array $attributes) { + return $attributes['other_accepted_formats'] ? ['en' => $this->faker->word()] : null; + }, + 'other_accepted_format' => ['en' => $this->faker->word()], + 'open_to_other_formats' => $this->faker->boolean(50) ? $this->faker->boolean(50) : null, + ]); + } + + public function formatAsync(): static + { + return $this->state([ + 'materials_by_date' => now()->addMonth(3), + 'complete_by_date' => now()->addMonth(6), + 'document_languages' => $this->faker->randomElements(array_keys(get_available_languages(true)), 10), + ]); + } } diff --git a/tests/RequestFactories/UpdateEngagementSelectionCriteriaRequestFactory.php b/tests/RequestFactories/UpdateEngagementSelectionCriteriaRequestFactory.php index 24652b4ea..ffa3294ec 100644 --- a/tests/RequestFactories/UpdateEngagementSelectionCriteriaRequestFactory.php +++ b/tests/RequestFactories/UpdateEngagementSelectionCriteriaRequestFactory.php @@ -2,6 +2,7 @@ namespace Tests\RequestFactories; +use App\Enums\LocationType; use App\Enums\ProvinceOrTerritory; use Worksome\RequestFactories\RequestFactory; @@ -10,12 +11,14 @@ class UpdateEngagementSelectionCriteriaRequestFactory extends RequestFactory public function definition(): array { return [ - 'location_type' => 'regions', - 'regions' => array_column(ProvinceOrTerritory::cases(), 'value'), - 'cross_disability_and_deaf' => 1, - 'intersectional' => 1, - 'ideal_participants' => 25, - 'minimum_participants' => 15, + 'location_type' => LocationType::Regions->value, + 'regions' => $this->faker->randomElements(ProvinceOrTerritory::class, null), + 'cross_disability_and_deaf' => true, + 'intersectional' => true, + 'ideal_participants' => $this->faker->numberBetween(10, 50), + 'minimum_participants' => function (array $attributes) { + return $this->faker->numberBetween(10, $attributes['ideal_participants']); + }, ]; } } diff --git a/tests/RequestFactories/UpdateIndividualRequestFactory.php b/tests/RequestFactories/UpdateIndividualRequestFactory.php new file mode 100644 index 000000000..abf31cdf1 --- /dev/null +++ b/tests/RequestFactories/UpdateIndividualRequestFactory.php @@ -0,0 +1,18 @@ + $this->faker->name(), + 'region' => $this->faker->randomElement(ProvinceOrTerritory::class)->value, + 'bio' => ['en' => $this->faker->paragraph()], + ]; + } +}