diff --git a/.DS_Store b/.DS_Store index 0203e71b2..6d1f51a96 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/CHANGELOG b/CHANGELOG index 3c3b5de33..23e866a11 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,6 @@ UNRELEASED CHANGES: -* +* Add the ability to set as many contact fields to a contact as needed RELEASED VERSIONS: diff --git a/app/Account.php b/app/Account.php index 918814982..952bd61e2 100644 --- a/app/Account.php +++ b/app/Account.php @@ -215,7 +215,7 @@ class Account extends Model } /** - * Get the tags records associated with the contact. + * Get the tags records associated with the account. * * @return HasMany */ @@ -225,7 +225,7 @@ class Account extends Model } /** - * Get the calls records associated with the contact. + * Get the calls records associated with the account. * * @return HasMany */ @@ -234,6 +234,26 @@ class Account extends Model return $this->hasMany(Call::class)->orderBy('called_at', 'desc'); } + /** + * Get the Contact Field types records associated with the account. + * + * @return HasMany + */ + public function contactFieldTypes() + { + return $this->hasMany('App\ContactFieldType'); + } + + /** + * Get the Contact Field records associated with the contact. + * + * @return HasMany + */ + public function contactFields() + { + return $this->hasMany('App\ContactField'); + } + /** * Check if the account can be downgraded, based on a set of rules. * @@ -332,4 +352,37 @@ class Account extends Model return true; } + + /** + * Populates the Contact Field Types table right after an account is + * created. + */ + public function populateContactFieldTypeTable($ignoreMigratedTable = false) + { + $defaultContactFieldTypes = DB::table('default_contact_field_types')->get(); + + foreach ($defaultContactFieldTypes as $defaultContactFieldType) { + if ($ignoreMigratedTable == false) { + $contactFieldType = ContactFieldType::create([ + 'account_id' => $this->id, + 'name' => $defaultContactFieldType->name, + 'fontawesome_icon' => (is_null($defaultContactFieldType->fontawesome_icon) ? null : $defaultContactFieldType->fontawesome_icon), + 'protocol' => (is_null($defaultContactFieldType->protocol) ? null : $defaultContactFieldType->protocol), + 'delible' => $defaultContactFieldType->delible, + 'type' => (is_null($defaultContactFieldType->type) ? null : $defaultContactFieldType->type), + ]); + } else { + if ($defaultContactFieldType->migrated == 0) { + $contactFieldType = ContactFieldType::create([ + 'account_id' => $this->id, + 'name' => $defaultContactFieldType->name, + 'fontawesome_icon' => (is_null($defaultContactFieldType->fontawesome_icon) ? null : $defaultContactFieldType->fontawesome_icon), + 'protocol' => (is_null($defaultContactFieldType->protocol) ? null : $defaultContactFieldType->protocol), + 'delible' => $defaultContactFieldType->delible, + 'type' => (is_null($defaultContactFieldType->type) ? null : $defaultContactFieldType->type), + ]); + } + } + } + } } diff --git a/app/Address.php b/app/Address.php new file mode 100644 index 000000000..bde556788 --- /dev/null +++ b/app/Address.php @@ -0,0 +1,144 @@ +belongsTo(Account::class); + } + + /** + * Get the contact record associated with the gift. + * + * @return BelongsTo + */ + public function contact() + { + return $this->belongsTo(Contact::class); + } + + /** + * Get the Country records associated with the contact. + * + * @return BelongsTo + */ + public function country() + { + return $this->belongsTo('App\Country'); + } + + /** + * Get the address in a format like 'Lives in Scranton, MS'. + * + * @return string + */ + public function getPartialAddress() + { + $address = $this->city; + + if (is_null($address)) { + return; + } + + if (! is_null($this->province)) { + $address = $address.', '.$this->province; + } + + return $address; + } + + /** + * Get the address in a format like 'Lives in Scranton, MS'. + * + * @return string + */ + public function getFullAddress() + { + $address = ''; + + if (! is_null($this->street)) { + $address = $this->street; + } + + if (! is_null($this->city)) { + $address .= ' '.$this->city; + } + + if (! is_null($this->province)) { + $address .= ' '.$this->province; + } + + if (! is_null($this->postal_code)) { + $address .= ' '.$this->postal_code; + } + + if (! is_null($this->country_id)) { + $address .= ' '.$this->country->country; + } + + if (is_null($address)) { + return; + } + + // trim extra whitespaces inside the address + $address = preg_replace('/\s+/', ' ', $address); + + return $address; + } + + /** + * Get the country of the contact. + * + * @return string or null + */ + public function getCountryName() + { + if ($this->country) { + return $this->country->country; + } + } + + /** + * Get the country ISO of the contact. + * + * @return string or null + */ + public function getCountryISO() + { + if ($this->country) { + return $this->country->iso; + } + } + + /** + * Get an URL for Google Maps for the address. + * + * @return string + */ + public function getGoogleMapAddress() + { + $address = $this->getFullAddress(); + $address = urlencode($address); + + return "https://www.google.ca/maps/place/{$address}"; + } +} diff --git a/app/Console/Commands/ImportVCards.php b/app/Console/Commands/ImportVCards.php index 1f4fa6f00..007a3e9be 100644 --- a/app/Console/Commands/ImportVCards.php +++ b/app/Console/Commands/ImportVCards.php @@ -3,8 +3,11 @@ namespace App\Console\Commands; use App\User; +use App\Address; use App\Contact; use App\Country; +use App\ContactField; +use App\ContactFieldType; use Sabre\VObject\Reader; use Illuminate\Console\Command; use Sabre\VObject\Component\VCard; @@ -107,29 +110,53 @@ class ImportVCards extends Command $contact->birthdate = new \DateTime((string) $vcard->BDAY); } - $contact->email = $this->formatValue($vcard->EMAIL); - $contact->phone_number = $this->formatValue($vcard->TEL); + $contact->job = $this->formatValue($vcard->ORG); + + $contact->setAvatarColor(); + + $contact->save(); if ($vcard->ADR) { - $contact->street = $this->formatValue($vcard->ADR->getParts()[2]); - $contact->city = $this->formatValue($vcard->ADR->getParts()[3]); - $contact->province = $this->formatValue($vcard->ADR->getParts()[4]); - $contact->postal_code = $this->formatValue($vcard->ADR->getParts()[5]); + $address = new Address(); + $address->street = $this->formatValue($vcard->ADR->getParts()[2]); + $address->city = $this->formatValue($vcard->ADR->getParts()[3]); + $address->province = $this->formatValue($vcard->ADR->getParts()[4]); + $address->postal_code = $this->formatValue($vcard->ADR->getParts()[5]); $country = Country::where('country', $vcard->ADR->getParts()[6]) ->orWhere('iso', strtolower($vcard->ADR->getParts()[6])) ->first(); if ($country) { - $contact->country_id = $country->id; + $address->country_id = $country->id; } + + $address->contact_id = $contact->id; + $address->account_id = $contact->account_id; + $address->save(); } - $contact->job = $this->formatValue($vcard->ORG); + if (! is_null($this->formatValue($vcard->EMAIL))) { + // Saves the email + $contactFieldType = ContactFieldType::where('type', 'email')->first(); + $contactField = new ContactField; + $contactField->account_id = $contact->account_id; + $contactField->contact_id = $contact->id; + $contactField->data = $this->formatValue($vcard->EMAIL); + $contactField->contact_field_type_id = $contactFieldType->id; + $contactField->save(); + } - $contact->setAvatarColor(); - - $contact->save(); + if (! is_null($this->formatValue($vcard->TEL))) { + // Saves the phone number + $contactFieldType = ContactFieldType::where('type', 'phone')->first(); + $contactField = new ContactField; + $contactField->account_id = $contact->account_id; + $contactField->contact_id = $contact->id; + $contactField->data = $this->formatValue($vcard->TEL); + $contactField->contact_field_type_id = $contactFieldType->id; + $contactField->save(); + } $contact->logEvent('contact', $contact->id, 'create'); @@ -164,12 +191,22 @@ class ImportVCards extends Command { $email = (string) $vcard->EMAIL; - $contact = Contact::where([ + $contactFieldType = ContactFieldType::where([ ['account_id', $user->account_id], - ['email', $email], + ['type', 'email'], ])->first(); - return $email && $contact; + $contactField = null; + + if ($contactFieldType) { + $contactField = ContactField::where([ + ['account_id', $user->account_id], + ['data', $email], + ['contact_field_type_id', $contactFieldType->id], + ])->first(); + } + + return $email && $contactField; } /** diff --git a/app/Console/Commands/ResetTestDB.php b/app/Console/Commands/ResetTestDB.php index a5003f65e..198eaff46 100644 --- a/app/Console/Commands/ResetTestDB.php +++ b/app/Console/Commands/ResetTestDB.php @@ -44,8 +44,8 @@ class ResetTestDB extends Command \Schema::drop($table_array[key($table_array)]); } - $this->call('migrate'); - $this->call('db:seed'); + //$this->call('migrate'); + //$this->call('db:seed'); $this->info('Local database has been reset'); } else { $this->info('Can\'t execute this command in this environment'); diff --git a/app/Contact.php b/app/Contact.php index 6bad19630..a3f2bffe2 100644 --- a/app/Contact.php +++ b/app/Contact.php @@ -12,6 +12,7 @@ use Illuminate\Database\Eloquent\Builder; use App\Http\Resources\Tag\Tag as TagResource; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use App\Http\Resources\Address\AddressShort as AddressShortResource; use App\Http\Resources\Contact\PartnerShort as PartnerShortResource; use App\Http\Resources\Contact\OffspringShort as OffspringShortResource; use App\Http\Resources\Contact\ProgenitorShort as ProgenitorShortResource; @@ -32,11 +33,6 @@ class Contact extends Model 'first_name', 'middle_name', 'last_name', - 'email', - 'street', - 'city', - 'postal_code', - 'province', 'food_preferencies', 'job', 'company', @@ -68,18 +64,9 @@ class Contact extends Model 'is_birthdate_approximate', 'account_id', 'is_partial', - 'phone_number', - 'email', 'job', 'company', - 'street', - 'city', - 'province', - 'postal_code', - 'country_id', 'food_preferencies', - 'facebook_profile_url', - 'twitter_profile_url', 'linkedin_profile_url', 'is_dead', 'deceased_date', @@ -139,16 +126,6 @@ class Contact extends Model return $this->hasMany('App\ActivityStatistic'); } - /** - * Get the contact records associated with the contact. - * - * @return BelongsTo - */ - public function country() - { - return $this->belongsTo('App\Country'); - } - /** * Get the debt records associated with the contact. * @@ -269,6 +246,26 @@ class Contact extends Model return $this->hasMany('App\Progenitor', 'is_the_parent_of'); } + /** + * Get the Contact Field records associated with the contact. + * + * @return HasMany + */ + public function contactFields() + { + return $this->hasMany('App\ContactField'); + } + + /** + * Get the Address Field records associated with the contact. + * + * @return HasMany + */ + public function addresses() + { + return $this->hasMany('App\Address'); + } + /** * Sort the contacts according a given criteria. * @param Builder $builder @@ -473,63 +470,6 @@ class Contact extends Model return $this->is_birthdate_approximate; } - /** - * Get the address in a format like 'Lives in Scranton, MS'. - * - * @return string - */ - public function getPartialAddress() - { - $address = $this->city; - - if (is_null($address)) { - return; - } - - if (! is_null($this->province)) { - $address = $address.', '.$this->province; - } - - return $address; - } - - /** - * Get the country of the contact. - * - * @return string or null - */ - public function getCountryName() - { - if ($this->country) { - return $this->country->country; - } - } - - /** - * Get the country ISO of the contact. - * - * @return string or null - */ - public function getCountryISO() - { - if ($this->country) { - return $this->country->iso; - } - } - - /** - * Get an URL for Google Maps for the address. - * - * @return string - */ - public function getGoogleMapAddress() - { - $address = $this->getFullAddress(); - $address = urlencode($address); - - return "https://www.google.ca/maps/place/{$address}"; - } - /** * Get the current Significant Others, if they exists, or return null otherwise. * @@ -849,6 +789,14 @@ class Contact extends Model return TagResource::collection($this->tags); } + /** + * Get the list of addresses for this contact. + */ + public function getAddressesForAPI() + { + return AddressShortResource::collection($this->addresses); + } + /** * Update the last called info on the contact, if the call has been made * in the most recent date. diff --git a/app/ContactField.php b/app/ContactField.php new file mode 100644 index 000000000..a150b2866 --- /dev/null +++ b/app/ContactField.php @@ -0,0 +1,46 @@ +belongsTo(Account::class); + } + + /** + * Get the contact record associated with the gift. + * + * @return BelongsTo + */ + public function contact() + { + return $this->belongsTo(Contact::class); + } + + /** + * Get the contact record associated with the gift. + * + * @return BelongsTo + */ + public function contactFieldType() + { + return $this->belongsTo(ContactFieldType::class); + } +} diff --git a/app/ContactFieldType.php b/app/ContactFieldType.php new file mode 100644 index 000000000..cf48ff0a8 --- /dev/null +++ b/app/ContactFieldType.php @@ -0,0 +1,28 @@ +belongsTo(Account::class); + } +} diff --git a/app/Http/Controllers/Api/ApiAddressController.php b/app/Http/Controllers/Api/ApiAddressController.php new file mode 100644 index 000000000..60bed5154 --- /dev/null +++ b/app/Http/Controllers/Api/ApiAddressController.php @@ -0,0 +1,167 @@ +user()->account_id) + ->where('id', $id) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + return new AddressResource($address); + } + + /** + * Store the address. + * @param Request $request + * @return \Illuminate\Http\Response + */ + public function store(Request $request) + { + // Validates basic fields to create the entry + $validator = Validator::make($request->all(), [ + 'name' => 'max:255|required', + 'street' => 'max:255|nullable', + 'city' => 'max:255|nullable', + 'province' => 'max:255|nullable', + 'postal_code' => 'max:255|nullable', + 'country_id' => 'integer|nullable', + 'contact_id' => 'required|integer', + ]); + + if ($validator->fails()) { + return $this->setErrorCode(32) + ->respondWithError($validator->errors()->all()); + } + + try { + $contact = Contact::where('account_id', auth()->user()->account_id) + ->where('id', $request->input('contact_id')) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + try { + $address = Address::create( + $request->all() + + [ + 'account_id' => auth()->user()->account->id, + ] + ); + } catch (QueryException $e) { + return $this->respondNotTheRightParameters(); + } + + return new AddressResource($address); + } + + /** + * Update the address. + * @param Request $request + * @param int $addressId + * @return \Illuminate\Http\Response + */ + public function update(Request $request, $addressId) + { + try { + $address = Address::where('account_id', auth()->user()->account_id) + ->where('id', $addressId) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + // Validates basic fields to create the entry + $validator = Validator::make($request->all(), [ + 'name' => 'max:255|required', + 'street' => 'max:255|nullable', + 'city' => 'max:255|nullable', + 'province' => 'max:255|nullable', + 'postal_code' => 'max:255|nullable', + 'country_id' => 'integer|nullable', + 'contact_id' => 'required|integer', + ]); + + if ($validator->fails()) { + return $this->setErrorCode(32) + ->respondWithError($validator->errors()->all()); + } + + try { + $contact = Contact::where('account_id', auth()->user()->account_id) + ->where('id', $request->input('contact_id')) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + try { + $address->update($request->all()); + } catch (QueryException $e) { + return $this->respondNotTheRightParameters(); + } + + return new AddressResource($address); + } + + /** + * Delete a address. + * @param Request $request + * @return \Illuminate\Http\Response + */ + public function destroy(Request $request, $addressId) + { + try { + $address = Address::where('account_id', auth()->user()->account_id) + ->where('id', $addressId) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + $address->delete(); + + return $this->respondObjectDeleted($address->id); + } + + /** + * Get the list of addresses for the given contact. + * + * @return \Illuminate\Http\Response + */ + public function addresses(Request $request, $contactId) + { + try { + $contact = Contact::where('account_id', auth()->user()->account_id) + ->where('id', $contactId) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + $addresses = $contact->addresses() + ->paginate($this->getLimitPerPage()); + + return AddressResource::collection($addresses); + } +} diff --git a/app/Http/Controllers/Api/ApiContactController.php b/app/Http/Controllers/Api/ApiContactController.php index bf3adb137..021714485 100644 --- a/app/Http/Controllers/Api/ApiContactController.php +++ b/app/Http/Controllers/Api/ApiContactController.php @@ -70,11 +70,6 @@ class ApiContactController extends ApiController 'phone_number' => 'nullable|max:255', 'job' => 'nullable|max:255', 'company' => 'nullable|max:255', - 'street' => 'nullable|max:255', - 'city' => 'nullable|max:255', - 'province' => 'nullable|max:255', - 'postal_code' => 'nullable|max:255', - 'country_id' => 'nullable|integer|max:255', 'food_preferencies' => 'nullable|max:100000', 'facebook_profile_url' => 'nullable|max:255', 'twitter_profile_url' => 'nullable|max:255', @@ -179,11 +174,6 @@ class ApiContactController extends ApiController 'phone_number' => 'nullable|max:255', 'job' => 'nullable|max:255', 'company' => 'nullable|max:255', - 'street' => 'nullable|max:255', - 'city' => 'nullable|max:255', - 'province' => 'nullable|max:255', - 'postal_code' => 'nullable|max:255', - 'country_id' => 'nullable|integer|max:255', 'food_preferencies' => 'nullable|max:100000', 'facebook_profile_url' => 'nullable|max:255', 'twitter_profile_url' => 'nullable|max:255', @@ -284,6 +274,7 @@ class ApiContactController extends ApiController $contact->reminders->each->delete(); $contact->tags->each->delete(); $contact->tasks->each->delete(); + $contact->addresses->each->delete(); // delete all relationships $relationships = Relationship::where('contact_id', $contact->id) diff --git a/app/Http/Controllers/Api/ApiContactFieldController.php b/app/Http/Controllers/Api/ApiContactFieldController.php new file mode 100644 index 000000000..6348a62a5 --- /dev/null +++ b/app/Http/Controllers/Api/ApiContactFieldController.php @@ -0,0 +1,168 @@ +user()->account_id) + ->where('id', $id) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + return new ContactFieldResource($contactField); + } + + /** + * Store the contactField. + * @param Request $request + * @return \Illuminate\Http\Response + */ + public function store(Request $request) + { + // Validates basic fields to create the entry + $validator = Validator::make($request->all(), [ + 'data' => 'max:255|required', + 'contact_field_type_id' => 'integer|required', + 'contact_id' => 'required|integer', + ]); + + if ($validator->fails()) { + return $this->setErrorCode(32) + ->respondWithError($validator->errors()->all()); + } + + try { + $contact = Contact::where('account_id', auth()->user()->account_id) + ->where('id', $request->input('contact_id')) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + try { + $contactFieldType = ContactFieldType::where('account_id', auth()->user()->account_id) + ->where('id', $request->input('contact_field_type_id')) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + try { + $contactField = ContactField::create( + $request->all() + + [ + 'account_id' => auth()->user()->account->id, + ] + ); + } catch (QueryException $e) { + return $this->respondNotTheRightParameters(); + } + + return new ContactFieldResource($contactField); + } + + /** + * Update the contactField. + * @param Request $request + * @param int $contactFieldId + * @return \Illuminate\Http\Response + */ + public function update(Request $request, $contactFieldId) + { + try { + $contactField = ContactField::where('account_id', auth()->user()->account_id) + ->where('id', $contactFieldId) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + // Validates basic fields to create the entry + $validator = Validator::make($request->all(), [ + 'data' => 'max:255|required', + 'contact_field_type_id' => 'integer|required', + 'contact_id' => 'required|integer', + ]); + + if ($validator->fails()) { + return $this->setErrorCode(32) + ->respondWithError($validator->errors()->all()); + } + + try { + $contact = Contact::where('account_id', auth()->user()->account_id) + ->where('id', $request->input('contact_id')) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + try { + $contactField->update($request->all()); + } catch (QueryException $e) { + return $this->respondNotTheRightParameters(); + } + + return new ContactFieldResource($contactField); + } + + /** + * Delete a contactField. + * @param Request $request + * @return \Illuminate\Http\Response + */ + public function destroy(Request $request, $contactFieldId) + { + try { + $contactField = ContactField::where('account_id', auth()->user()->account_id) + ->where('id', $contactFieldId) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + $contactField->delete(); + + return $this->respondObjectDeleted($contactField->id); + } + + /** + * Get the list of contact fields for the given contact. + * + * @return \Illuminate\Http\Response + */ + public function contactFields(Request $request, $contactId) + { + try { + $contact = Contact::where('account_id', auth()->user()->account_id) + ->where('id', $contactId) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + $contactFields = $contact->contactFields() + ->paginate($this->getLimitPerPage()); + + return ContactFieldResource::collection($contactFields); + } +} diff --git a/app/Http/Controllers/Api/Misc/ApiCountryController.php b/app/Http/Controllers/Api/Misc/ApiCountryController.php new file mode 100644 index 000000000..666a5488f --- /dev/null +++ b/app/Http/Controllers/Api/Misc/ApiCountryController.php @@ -0,0 +1,23 @@ +get(); + + return CountryResource::collection($countries); + } +} diff --git a/app/Http/Controllers/Api/Settings/ApiContactFieldTypeController.php b/app/Http/Controllers/Api/Settings/ApiContactFieldTypeController.php new file mode 100644 index 000000000..a60ab039e --- /dev/null +++ b/app/Http/Controllers/Api/Settings/ApiContactFieldTypeController.php @@ -0,0 +1,153 @@ +user()->account->contactFieldTypes() + ->paginate($this->getLimitPerPage()); + + return ContactFieldTypeResource::collection($contactFieldTypes); + } + + /** + * Get the detail of a given contact field type. + * @param Request $request + * @return \Illuminate\Http\Response + */ + public function show(Request $request, $contactFieldTypeId) + { + try { + $contactFieldType = ContactFieldType::where('account_id', auth()->user()->account_id) + ->where('id', $contactFieldTypeId) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + return new ContactFieldTypeResource($contactFieldType); + } + + /** + * Store the contactfieldtype. + * @param Request $request + * @return \Illuminate\Http\Response + */ + public function store(Request $request) + { + // Validates basic fields to create the entry + $validator = Validator::make($request->all(), [ + 'name' => 'required|max:255', + 'fontawesome_icon' => 'nullable|max:255', + 'protocol' => 'nullable|max:255', + 'delible' => 'integer', + 'type' => 'nullable|max:255', + ]); + + if ($validator->fails()) { + return $this->setErrorCode(32) + ->respondWithError($validator->errors()->all()); + } + + try { + $contactFieldType = ContactFieldType::create( + $request->all() + + ['account_id' => auth()->user()->account->id] + ); + } catch (QueryException $e) { + return $this->respondNotTheRightParameters(); + } + + return new ContactFieldTypeResource($contactFieldType); + } + + /** + * Update the contact field type. + * @param Request $request + * @param int + * @return \Illuminate\Http\Response + */ + public function update(Request $request, $contactFieldTypeId) + { + try { + $contactFieldType = ContactFieldType::where('account_id', auth()->user()->account_id) + ->where('id', $contactFieldTypeId) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + // Validates basic fields to create the entry + $validator = Validator::make($request->all(), [ + 'name' => 'required|max:255', + 'fontawesome_icon' => 'nullable|max:255', + 'protocol' => 'nullable|max:255', + 'delible' => 'integer', + 'type' => 'nullable|max:255', + ]); + + if ($validator->fails()) { + return $this->setErrorCode(32) + ->respondWithError($validator->errors()->all()); + } + + // Update the contactfieldtype itself + try { + $contactFieldType->update( + $request->only([ + 'name', + 'fontawesome_icon', + 'protocol', + 'delible', + 'type', + ]) + ); + } catch (QueryException $e) { + return $this->respondNotTheRightParameters(); + } + + return new ContactFieldTypeResource($contactFieldType); + } + + /** + * Delete an contactfieldtype. + * @param Request $request + * @return \Illuminate\Http\Response + */ + public function destroy(Request $request, $contactFieldTypeId) + { + try { + $contactFieldType = ContactFieldType::where('account_id', auth()->user()->account_id) + ->where('id', $contactFieldTypeId) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respondNotFound(); + } + + $contactFields = auth()->user()->account->contactFields + ->where('contact_field_type_id', $contactFieldTypeId); + + foreach ($contactFields as $contactField) { + $contactField->delete(); + } + + $contactFieldType->delete(); + + return $this->respondObjectDeleted($contactFieldType->id); + } +} diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 8e8aeda02..433279793 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -99,6 +99,8 @@ class RegisterController extends Controller $user->account_id = $account->id; $user->save(); + $account->populateContactFieldTypeTable(); + // send me an alert dispatch(new SendNewUserAlert($user)); diff --git a/app/Http/Controllers/People/AddressesController.php b/app/Http/Controllers/People/AddressesController.php new file mode 100644 index 000000000..a0623fddc --- /dev/null +++ b/app/Http/Controllers/People/AddressesController.php @@ -0,0 +1,88 @@ +addresses as $address) { + $data = [ + 'id' => $address->id, + 'name' => $address->name, + 'googleMapAddress' => $address->getGoogleMapAddress(), + 'address' => $address->getFullAddress(), + 'country_id' => $address->country_id, + 'name' => $address->name, + 'street' => $address->street, + 'city' => $address->city, + 'province' => $address->province, + 'postal_code' => $address->postal_code, + 'edit' => false, + ]; + $contactAddresses->push($data); + } + + return $contactAddresses; + } + + /** + * Get all the countries. + */ + public function getCountries() + { + return Country::all(); + } + + /** + * Store the address. + */ + public function store(AddressesRequest $request, Contact $contact) + { + $address = $contact->addresses()->create([ + 'account_id' => auth()->user()->account->id, + 'country_id' => ($request->get('country_id') == 0 ? null : $request->get('country_id')), + 'name' => ($request->get('name') == '' ? null : $request->get('name')), + 'street' => ($request->get('street') == '' ? null : $request->get('street')), + 'city' => ($request->get('city') == '' ? null : $request->get('city')), + 'province' => ($request->get('province') == '' ? null : $request->get('province')), + 'postal_code' => ($request->get('postal_code') == '' ? null : $request->get('postal_code')), + ]); + + return $address; + } + + /** + * Edit the contact field. + */ + public function edit(AddressesRequest $request, Contact $contact, Address $address) + { + $address->update([ + 'country_id' => ($request->get('country_id') == 0 ? null : $request->get('country_id')), + 'name' => ($request->get('name') == '' ? null : $request->get('name')), + 'street' => ($request->get('street') == '' ? null : $request->get('street')), + 'city' => ($request->get('city') == '' ? null : $request->get('city')), + 'province' => ($request->get('province') == '' ? null : $request->get('province')), + 'postal_code' => ($request->get('postal_code') == '' ? null : $request->get('postal_code')), + ]); + + return $address; + } + + public function destroy(Contact $contact, Address $address) + { + $address->delete(); + } +} diff --git a/app/Http/Controllers/People/ContactFieldsController.php b/app/Http/Controllers/People/ContactFieldsController.php new file mode 100644 index 000000000..85830363b --- /dev/null +++ b/app/Http/Controllers/People/ContactFieldsController.php @@ -0,0 +1,85 @@ +contactFields as $contactField) { + $data = [ + 'id' => $contactField->id, + 'data' => $contactField->data, + 'name' => $contactField->contactFieldType->name, + 'fontawesome_icon' => (is_null($contactField->contactFieldType->fontawesome_icon) ? null : $contactField->contactFieldType->fontawesome_icon), + 'protocol' => (is_null($contactField->contactFieldType->protocol) ? null : $contactField->contactFieldType->protocol), + 'contact_field_type_id' => $contactField->contact_field_type_id, + 'edit' => false, + ]; + $contactInformationData->push($data); + } + + return $contactInformationData; + } + + /** + * Get all the contact field types. + * @param Contact $contact + */ + public function getContactFieldTypes(Contact $contact) + { + return auth()->user()->account->contactFieldTypes; + } + + /** + * Store the contact field. + */ + public function storeContactField(ContactFieldsRequest $request, Contact $contact) + { + $contactField = $contact->contactFields()->create( + $request->only([ + 'contact_field_type_id', + 'data', + ]) + + [ + 'account_id' => auth()->user()->account->id, + ] + ); + + return $contactField; + } + + /** + * Edit the contact field. + */ + public function editContactField(ContactFieldsRequest $request, Contact $contact, ContactField $contactField) + { + $contactField->update( + $request->only([ + 'contact_field_type_id', + 'data', + ]) + + [ + 'account_id' => auth()->user()->account->id, + ] + ); + + return $contactField; + } + + public function destroyContactField(Contact $contact, ContactField $contactField) + { + $contactField->delete(); + } +} diff --git a/app/Http/Controllers/PeopleController.php b/app/Http/Controllers/PeopleController.php index d61fa494e..bdbd37906 100644 --- a/app/Http/Controllers/PeopleController.php +++ b/app/Http/Controllers/PeopleController.php @@ -186,60 +186,6 @@ class PeopleController extends Controller $contact->avatar_file_name = $request->avatar->store('avatars', config('filesystems.default')); } - if ($request->input('email') != '') { - $contact->email = $request->input('email'); - } else { - $contact->email = null; - } - - if ($request->input('phone') != '') { - $contact->phone_number = $request->input('phone'); - } else { - $contact->phone_number = null; - } - - if ($request->input('facebook') != '') { - $contact->facebook_profile_url = $request->input('facebook'); - } else { - $contact->facebook_profile_url = null; - } - - if ($request->input('twitter') != '') { - $contact->twitter_profile_url = $request->input('twitter'); - } else { - $contact->twitter_profile_url = null; - } - - if ($request->input('street') != '') { - $contact->street = $request->input('street'); - } else { - $contact->street = null; - } - - if ($request->input('postalcode') != '') { - $contact->postal_code = $request->input('postalcode'); - } else { - $contact->postal_code = null; - } - - if ($request->input('province') != '') { - $contact->province = $request->input('province'); - } else { - $contact->province = null; - } - - if ($request->input('city') != '') { - $contact->city = $request->input('city'); - } else { - $contact->city = null; - } - - if ($request->input('country') != '---') { - $contact->country_id = $request->input('country'); - } else { - $contact->country_id = null; - } - // Is the person deceased? if ($request->input('markPersonDeceased') != '') { $contact->is_dead = true; @@ -322,6 +268,8 @@ class PeopleController extends Controller $contact->reminders->each->delete(); $contact->tags->each->delete(); $contact->tasks->each->delete(); + $contact->contactFields->each->delete(); + $contact->addresses->each->delete(); // delete all relationships $relationships = Relationship::where('contact_id', $contact->id) diff --git a/app/Http/Controllers/Settings/PersonalizationController.php b/app/Http/Controllers/Settings/PersonalizationController.php new file mode 100644 index 000000000..bf44bd479 --- /dev/null +++ b/app/Http/Controllers/Settings/PersonalizationController.php @@ -0,0 +1,129 @@ +user()->account->contactFieldTypes; + } + + /** + * Store a newly created resource in storage. + * + * @param Request $request + * @return string + */ + public function storeContactFieldType(Request $request) + { + Validator::make($request->all(), [ + 'name' => 'required|max:255', + 'icon' => 'max:255|nullable', + 'protocol' => 'max:255|nullable', + ])->validate(); + + $contactFieldType = auth()->user()->account->contactFieldTypes()->create( + $request->only([ + 'name', + 'protocol', + ]) + + [ + 'fontawesome_icon' => $request->get('icon'), + 'account_id' => auth()->user()->account->id, + ] + ); + + return $contactFieldType; + } + + /** + * Edit a newly created resource in storage. + * + * @param ContactFieldTypeRequest $request + * @param string $contactFieldTypeId + * @return \Illuminate\Http\Response + */ + public function editContactFieldType(Request $request, $contactFieldTypeId) + { + try { + $contactFieldType = ContactFieldType::where('account_id', auth()->user()->account_id) + ->where('id', $contactFieldTypeId) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respond([ + 'errors' => [ + 'message' => trans('app.error_unauthorized'), + ], + ]); + } + + Validator::make($request->all(), [ + 'name' => 'required|max:255', + 'icon' => 'max:255|nullable', + 'protocol' => 'max:255|nullable', + ])->validate(); + + $contactFieldType->update( + $request->only([ + 'name', + 'protocol', + ]) + + [ + 'fontawesome_icon' => $request->get('icon'), + ] + ); + + return $contactFieldType; + } + + public function destroyContactFieldType(Request $request, $contactFieldTypeId) + { + try { + $contactFieldType = ContactFieldType::where('account_id', auth()->user()->account_id) + ->where('id', $contactFieldTypeId) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->respond([ + 'errors' => [ + 'message' => trans('app.error_unauthorized'), + ], + ]); + } + + if ($contactFieldType->delible == false) { + return $this->respond([ + 'errors' => [ + 'message' => trans('app.error_unauthorized'), + ], + ]); + } + + // find all the contact fields that have this contact field types + $contactFields = auth()->user()->account->contactFields + ->where('contact_field_type_id', $contactFieldTypeId); + + foreach ($contactFields as $contactField) { + $contactField->delete(); + } + + $contactFieldType->delete(); + } +} diff --git a/app/Http/Requests/People/AddressesRequest.php b/app/Http/Requests/People/AddressesRequest.php new file mode 100644 index 000000000..e7d84b232 --- /dev/null +++ b/app/Http/Requests/People/AddressesRequest.php @@ -0,0 +1,35 @@ + 'integer|nullable', + 'name' => 'max:255|nullable', + 'street' => 'max:255|nullable', + 'city' => 'max:255|nullable', + 'province' => 'max:255|nullable', + 'postal_code' => 'max:255|nullable', + ]; + } +} diff --git a/app/Http/Requests/People/ContactFieldsRequest.php b/app/Http/Requests/People/ContactFieldsRequest.php new file mode 100644 index 000000000..5d9573fb2 --- /dev/null +++ b/app/Http/Requests/People/ContactFieldsRequest.php @@ -0,0 +1,31 @@ + 'required', + 'data' => 'max:255|required', + ]; + } +} diff --git a/app/Http/Resources/Address/Address.php b/app/Http/Resources/Address/Address.php new file mode 100644 index 000000000..151ab21a1 --- /dev/null +++ b/app/Http/Resources/Address/Address.php @@ -0,0 +1,36 @@ + $this->id, + 'object' => 'address', + 'name' => $this->name, + 'street' => $this->street, + 'city' => $this->city, + 'province' => $this->province, + 'postal_code' => $this->postal_code, + 'country' => new CountryResource($this->country), + 'account' => [ + 'id' => $this->account_id, + ], + 'contact' => new ContactShortResource($this->contact), + 'created_at' => (is_null($this->created_at) ? null : $this->created_at->format(config('api.timestamp_format'))), + 'updated_at' => (is_null($this->updated_at) ? null : $this->updated_at->format(config('api.timestamp_format'))), + ]; + } +} diff --git a/app/Http/Resources/Address/AddressCollection.php b/app/Http/Resources/Address/AddressCollection.php new file mode 100644 index 000000000..8123c2a9e --- /dev/null +++ b/app/Http/Resources/Address/AddressCollection.php @@ -0,0 +1,24 @@ + $this->collection, + 'links' => [ + 'self' => 'link-value', + ], + ]; + } +} diff --git a/app/Http/Resources/Address/AddressShort.php b/app/Http/Resources/Address/AddressShort.php new file mode 100644 index 000000000..a815a1cef --- /dev/null +++ b/app/Http/Resources/Address/AddressShort.php @@ -0,0 +1,31 @@ + $this->id, + 'object' => 'address', + 'name' => $this->name, + 'street' => $this->street, + 'city' => $this->city, + 'province' => $this->province, + 'postal_code' => $this->postal_code, + 'country' => new CountryResource($this->country), + 'created_at' => (is_null($this->created_at) ? null : $this->created_at->format(config('api.timestamp_format'))), + 'updated_at' => (is_null($this->updated_at) ? null : $this->updated_at->format(config('api.timestamp_format'))), + ]; + } +} diff --git a/app/Http/Resources/Contact/Contact.php b/app/Http/Resources/Contact/Contact.php index 374532764..8ef2b39b9 100644 --- a/app/Http/Resources/Contact/Contact.php +++ b/app/Http/Resources/Contact/Contact.php @@ -80,18 +80,8 @@ class Contact extends Resource 'twitter_profile_url' => $this->twitter_profile_url, 'linkedin_profile_url' => $this->linkedin_profile_url, ], - 'addresses' => [ - [ - 'name' => 'home', - 'street' => $this->street, - 'city' => $this->city, - 'province' => $this->province, - 'postal_code' => $this->postal_code, - 'country_id' => $this->country_id, - 'country_name' => $this->getCountryName(), - ], - ], ]), + 'addresses' => $this->when(! $this->is_partial, $this->getAddressesForAPI()), 'tags' => $this->when(! $this->is_partial, $this->getTagsForAPI()), 'statistics' => $this->when(! $this->is_partial, [ 'number_of_calls' => $this->calls->count(), diff --git a/app/Http/Resources/ContactField/ContactField.php b/app/Http/Resources/ContactField/ContactField.php new file mode 100644 index 000000000..86b412533 --- /dev/null +++ b/app/Http/Resources/ContactField/ContactField.php @@ -0,0 +1,32 @@ + $this->id, + 'object' => 'contactfield', + 'data' => $this->data, + 'contact_field_type' => new ContactFieldTypeResource($this->contactFieldType), + 'account' => [ + 'id' => $this->account->id, + ], + 'contact' => new ContactShortResource($this->contact), + 'created_at' => $this->created_at->format(config('api.timestamp_format')), + 'updated_at' => (is_null($this->updated_at) ? null : $this->updated_at->format(config('api.timestamp_format'))), + ]; + } +} diff --git a/app/Http/Resources/Country/Country.php b/app/Http/Resources/Country/Country.php new file mode 100644 index 000000000..f8473fcb8 --- /dev/null +++ b/app/Http/Resources/Country/Country.php @@ -0,0 +1,24 @@ + $this->id, + 'object' => 'country', + 'name' => $this->country, + 'iso' => $this->iso, + ]; + } +} diff --git a/app/Http/Resources/Country/CountryCollection.php b/app/Http/Resources/Country/CountryCollection.php new file mode 100644 index 000000000..9b5816464 --- /dev/null +++ b/app/Http/Resources/Country/CountryCollection.php @@ -0,0 +1,24 @@ + $this->collection, + 'links' => [ + 'self' => 'link-value', + ], + ]; + } +} diff --git a/app/Http/Resources/Settings/ContactFieldType/ContactFieldType.php b/app/Http/Resources/Settings/ContactFieldType/ContactFieldType.php new file mode 100644 index 000000000..0ea5f5af2 --- /dev/null +++ b/app/Http/Resources/Settings/ContactFieldType/ContactFieldType.php @@ -0,0 +1,32 @@ + $this->id, + 'object' => 'contactfieldtype', + 'name' => $this->name, + 'fontawesome_icon' => $this->fontawesome_icon, + 'protocol' => $this->protocol, + 'delible' => (bool) $this->delible, + 'type' => $this->type, + 'account' => [ + 'id' => $this->account->id, + ], + 'created_at' => $this->created_at->format(config('api.timestamp_format')), + 'updated_at' => (is_null($this->updated_at) ? null : $this->updated_at->format(config('api.timestamp_format'))), + ]; + } +} diff --git a/app/Http/Resources/Settings/ContactFieldType/ContactFieldTypeCollection.php b/app/Http/Resources/Settings/ContactFieldType/ContactFieldTypeCollection.php new file mode 100644 index 000000000..9dd277d48 --- /dev/null +++ b/app/Http/Resources/Settings/ContactFieldType/ContactFieldTypeCollection.php @@ -0,0 +1,24 @@ + $this->collection, + 'links' => [ + 'self' => 'link-value', + ], + ]; + } +} diff --git a/app/Instance.php b/app/Instance.php index 1697793df..561a1a285 100644 --- a/app/Instance.php +++ b/app/Instance.php @@ -2,8 +2,20 @@ namespace App; +use DB; use Illuminate\Database\Eloquent\Model; class Instance extends Model { + /** + * Once migrations have been run to add a new default contact field type, + * we need to mark the field as being migrated so we don't create another + * default contact field type if another migration will change this table + * in the future. + */ + public function markDefaultContactFieldTypeAsMigrated() + { + DB::table('default_contact_field_types') + ->update(['migrated' => 1]); + } } diff --git a/app/Jobs/AddContactFromVCard.php b/app/Jobs/AddContactFromVCard.php index 4e29625e0..b03c5da52 100644 --- a/app/Jobs/AddContactFromVCard.php +++ b/app/Jobs/AddContactFromVCard.php @@ -3,11 +3,14 @@ namespace App\Jobs; use App\User; +use App\Address; use App\Contact; use App\Country; use App\Reminder; use App\ImportJob; +use App\ContactField; use App\ImportJobReport; +use App\ContactFieldType; use Sabre\VObject\Reader; use Illuminate\Bus\Queueable; use Sabre\VObject\Component\VCard; @@ -90,29 +93,53 @@ class AddContactFromVCard implements ShouldQueue $contact->birthdate = new \DateTime((string) $vcard->BDAY); } - $contact->email = $this->formatValue($vcard->EMAIL); - $contact->phone_number = $this->formatValue($vcard->TEL); + $contact->job = $this->formatValue($vcard->ORG); + + $contact->setAvatarColor(); + + $contact->save(); if ($vcard->ADR) { - $contact->street = $this->formatValue($vcard->ADR->getParts()[2]); - $contact->city = $this->formatValue($vcard->ADR->getParts()[3]); - $contact->province = $this->formatValue($vcard->ADR->getParts()[4]); - $contact->postal_code = $this->formatValue($vcard->ADR->getParts()[5]); + $address = new Address(); + $address->street = $this->formatValue($vcard->ADR->getParts()[2]); + $address->city = $this->formatValue($vcard->ADR->getParts()[3]); + $address->province = $this->formatValue($vcard->ADR->getParts()[4]); + $address->postal_code = $this->formatValue($vcard->ADR->getParts()[5]); $country = Country::where('country', $vcard->ADR->getParts()[6]) ->orWhere('iso', strtolower($vcard->ADR->getParts()[6])) ->first(); if ($country) { - $contact->country_id = $country->id; + $address->country_id = $country->id; } + + $address->contact_id = $contact->id; + $address->account_id = $contact->account_id; + $address->save(); } - $contact->job = $this->formatValue($vcard->ORG); + if (! is_null($this->formatValue($vcard->EMAIL))) { + // Saves the email + $contactFieldType = ContactFieldType::where('type', 'email')->first(); + $contactField = new ContactField; + $contactField->account_id = $contact->account_id; + $contactField->contact_id = $contact->id; + $contactField->data = $this->formatValue($vcard->EMAIL); + $contactField->contact_field_type_id = $contactFieldType->id; + $contactField->save(); + } - $contact->setAvatarColor(); - - $contact->save(); + if (! is_null($this->formatValue($vcard->TEL))) { + // Saves the phone number + $contactFieldType = ContactFieldType::where('type', 'phone')->first(); + $contactField = new ContactField; + $contactField->account_id = $contact->account_id; + $contactField->contact_id = $contact->id; + $contactField->data = $this->formatValue($vcard->TEL); + $contactField->contact_field_type_id = $contactFieldType->id; + $contactField->save(); + } // if birthdate is known, we need to create reminders if (! $contact->isBirthdateApproximate()) { @@ -185,12 +212,22 @@ class AddContactFromVCard implements ShouldQueue { $email = (string) $vcard->EMAIL; - $contact = Contact::where([ + $contactFieldType = ContactFieldType::where([ ['account_id', $account_id], - ['email', $email], + ['type', 'email'], ])->first(); - return $email && $contact; + $contactField = null; + + if ($contactFieldType) { + $contactField = ContactField::where([ + ['account_id', $account_id], + ['data', $email], + ['contact_field_type_id', $contactFieldType->id], + ])->first(); + } + + return $email && $contactField; } private function fileImportJobReport(VCard $vcard, $status, $reason = null) diff --git a/app/Jobs/ExportAccountAsSQL.php b/app/Jobs/ExportAccountAsSQL.php index b4d382431..22ff45283 100644 --- a/app/Jobs/ExportAccountAsSQL.php +++ b/app/Jobs/ExportAccountAsSQL.php @@ -34,6 +34,8 @@ class ExportAccountAsSQL 'oauth_clients', 'oauth_personal_access_clients', 'oauth_refresh_tokens', + 'api_usage', + 'default_contact_field_types', ]; protected $ignoredColumns = [ diff --git a/app/Jobs/ResizeAvatars.php b/app/Jobs/ResizeAvatars.php index ceed96915..4a6d0deec 100644 --- a/app/Jobs/ResizeAvatars.php +++ b/app/Jobs/ResizeAvatars.php @@ -35,10 +35,14 @@ class ResizeAvatars implements ShouldQueue public function handle() { if ($this->contact->has_avatar == 'true') { - $avatar_file = Storage::disk($this->contact->avatar_location)->get($this->contact->avatar_file_name); - $avatar_path = Storage::disk($this->contact->avatar_location)->url($this->contact->avatar_file_name); - $avatar_filename_without_extension = pathinfo($avatar_path, PATHINFO_FILENAME); - $avatar_extension = pathinfo($avatar_path, PATHINFO_EXTENSION); + try { + $avatar_file = Storage::disk($this->contact->avatar_location)->get($this->contact->avatar_file_name); + $avatar_path = Storage::disk($this->contact->avatar_location)->url($this->contact->avatar_file_name); + $avatar_filename_without_extension = pathinfo($avatar_path, PATHINFO_FILENAME); + $avatar_extension = pathinfo($avatar_path, PATHINFO_EXTENSION); + } catch (FileNotFoundException $e) { + return; + } $size = 110; $avatar_cropped_path = 'avatars/'.$avatar_filename_without_extension.'_'.$size.'.'.$avatar_extension; diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index f0b8387c5..b06ae748b 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -15,10 +15,6 @@ class AppServiceProvider extends ServiceProvider */ public function boot() { - View::composer( - 'partials.components.country-select', 'App\Http\ViewComposers\CountrySelectViewComposer' - ); - View::composer( 'partials.components.currency-select', 'App\Http\ViewComposers\CurrencySelectViewComposer' ); diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index ad5d8623b..629b86f27 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -11,6 +11,7 @@ use App\Contact; use App\Activity; use App\Reminder; use App\Offspring; +use App\ContactField; use App\Relationship; use Illuminate\Routing\Router; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; @@ -41,6 +42,13 @@ class RouteServiceProvider extends ServiceProvider ->firstOrFail(); }); + Route::bind('contactfield', function ($value, $route) { + return ContactField::where('account_id', auth()->user()->account_id) + ->where('contact_id', $route->parameter('contact')->id) + ->where('id', $value) + ->firstOrFail(); + }); + Route::bind('activity', function ($value, $route) { return Activity::where('account_id', auth()->user()->account_id) ->where('id', $value) diff --git a/composer.lock b/composer.lock index 12477d834..cde6066b5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "23ddf9eaafe1d1d25485868a3016425f", + "content-hash": "9692967b533183e31586508a19ddff6d", "packages": [ { "name": "aws/aws-sdk-php", - "version": "3.36.34", + "version": "3.38.1", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "adc4e9928730cb65b9b7914084cbf1d8c988419a" + "reference": "9f704274f4748d2039a16d45b3388ed8dde74e89" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/adc4e9928730cb65b9b7914084cbf1d8c988419a", - "reference": "adc4e9928730cb65b9b7914084cbf1d8c988419a", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/9f704274f4748d2039a16d45b3388ed8dde74e89", + "reference": "9f704274f4748d2039a16d45b3388ed8dde74e89", "shasum": "" }, "require": { @@ -84,7 +84,7 @@ "s3", "sdk" ], - "time": "2017-10-26T20:45:00+00:00" + "time": "2017-11-09T19:15:59+00:00" }, { "name": "barryvdh/laravel-debugbar", @@ -1366,16 +1366,16 @@ }, { "name": "laravel/dusk", - "version": "v1.1.0", + "version": "v1.1.1", "source": { "type": "git", "url": "https://github.com/laravel/dusk.git", - "reference": "6b81e97ae1ce384e3d8dbd020b2b9751c1449889" + "reference": "87d57bbcb878e569aa8750e1d487ce923561f3e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/dusk/zipball/6b81e97ae1ce384e3d8dbd020b2b9751c1449889", - "reference": "6b81e97ae1ce384e3d8dbd020b2b9751c1449889", + "url": "https://api.github.com/repos/laravel/dusk/zipball/87d57bbcb878e569aa8750e1d487ce923561f3e3", + "reference": "87d57bbcb878e569aa8750e1d487ce923561f3e3", "shasum": "" }, "require": { @@ -1394,7 +1394,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1413,25 +1413,26 @@ } ], "description": "Laravel Dusk provides simple end-to-end testing and browser automation.", + "homepage": "https://laravel.com", "keywords": [ "laravel", "testing", "webdriver" ], - "time": "2017-04-23T17:13:04+00:00" + "time": "2017-10-31T21:41:42+00:00" }, { "name": "laravel/framework", - "version": "v5.5.19", + "version": "v5.5.20", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "c678100e84934ec85c9f8bc26bd0a60222682719" + "reference": "ce0019d22a83b1b240330ea4115ae27a4d75d79c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/c678100e84934ec85c9f8bc26bd0a60222682719", - "reference": "c678100e84934ec85c9f8bc26bd0a60222682719", + "url": "https://api.github.com/repos/laravel/framework/zipball/ce0019d22a83b1b240330ea4115ae27a4d75d79c", + "reference": "ce0019d22a83b1b240330ea4115ae27a4d75d79c", "shasum": "" }, "require": { @@ -1513,7 +1514,7 @@ "nexmo/client": "Required to use the Nexmo transport (~1.0).", "pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).", "predis/predis": "Required to use the redis cache and queue drivers (~1.0).", - "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~2.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~3.0).", "symfony/css-selector": "Required to use some of the crawler integration testing tools (~3.3).", "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (~3.3).", "symfony/psr-http-message-bridge": "Required to psr7 bridging features (~1.0)." @@ -1549,7 +1550,7 @@ "framework", "laravel" ], - "time": "2017-10-25T19:10:45+00:00" + "time": "2017-11-07T14:24:50+00:00" }, { "name": "laravel/passport", @@ -1622,16 +1623,16 @@ }, { "name": "laravel/socialite", - "version": "v3.0.7", + "version": "v3.0.9", "source": { "type": "git", "url": "https://github.com/laravel/socialite.git", - "reference": "d79174513dbf14359b53e44394cf71373ae03433" + "reference": "fc1c8d415699e502f3e61cbc61e3250d5bd942eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/socialite/zipball/d79174513dbf14359b53e44394cf71373ae03433", - "reference": "d79174513dbf14359b53e44394cf71373ae03433", + "url": "https://api.github.com/repos/laravel/socialite/zipball/fc1c8d415699e502f3e61cbc61e3250d5bd942eb", + "reference": "fc1c8d415699e502f3e61cbc61e3250d5bd942eb", "shasum": "" }, "require": { @@ -1680,7 +1681,7 @@ "laravel", "oauth" ], - "time": "2017-07-22T14:44:37+00:00" + "time": "2017-11-06T16:02:48+00:00" }, { "name": "lcobucci/jwt", @@ -2192,7 +2193,7 @@ }, { "name": "mtdowling/cron-expression", - "version": "v1.2.0", + "version": "v1.2.1", "source": { "type": "git", "url": "https://github.com/mtdowling/cron-expression.git", @@ -2891,12 +2892,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "9660ad3b85be3e3b90eacb9be3fcf7d12be60a90" + "reference": "5de810cf96008ab760a0590fb49078e12ab80cf9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/9660ad3b85be3e3b90eacb9be3fcf7d12be60a90", - "reference": "9660ad3b85be3e3b90eacb9be3fcf7d12be60a90", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/5de810cf96008ab760a0590fb49078e12ab80cf9", + "reference": "5de810cf96008ab760a0590fb49078e12ab80cf9", "shasum": "" }, "conflict": { @@ -2904,7 +2905,7 @@ "amphp/artax": ">=2,<2.0.6|<1.0.6", "aws/aws-sdk-php": ">=3,<3.2.1", "bugsnag/bugsnag-laravel": ">=2,<2.0.2", - "cakephp/cakephp": ">=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.0.15|>=1.3,<1.3.18|>=3.1,<3.1.4", + "cakephp/cakephp": ">=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.0.15|>=3.1,<3.1.4|>=1.3,<1.3.18", "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<2.1", "codeigniter/framework": "<=3.0.6", @@ -2924,7 +2925,7 @@ "dompdf/dompdf": ">=0.6,<0.6.2", "drupal/core": ">=8,<8.3.7", "drupal/drupal": ">=8,<8.3.7", - "ezsystems/ezpublish-legacy": ">=5.4,<5.4.10.1|>=5.3,<5.3.12.2|>=2017.8,<2017.8.1.1", + "ezsystems/ezpublish-legacy": ">=2017.8,<2017.8.1.1|>=5.4,<5.4.10.1|>=5.3,<5.3.12.2", "firebase/php-jwt": "<2", "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", @@ -2944,6 +2945,7 @@ "oro/crm": ">=1.7,<1.7.4", "oro/platform": ">=1.7,<1.7.4", "phpmailer/phpmailer": ">=5,<5.2.24", + "phpunit/phpunit": ">=5.0.10,<5.6.3|>=4.8.19,<4.8.28", "phpxmlrpc/extras": "<6.0.1", "pusher/pusher-php-server": "<2.2.1", "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", @@ -2964,8 +2966,8 @@ "symfony/http-foundation": ">=2,<2.3.27|>=2.4,<2.5.11|>=2.6,<2.6.6", "symfony/http-kernel": ">=2,<2.3.29|>=2.4,<2.5.12|>=2.6,<2.6.8", "symfony/routing": ">=2,<2.0.19", - "symfony/security": ">=2.3,<2.3.37|>=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8.23,<2.8.25|>=3.2.10,<3.2.12|>=3.3.3,<3.3.5|>=2,<2.0.25|>=2.1,<2.1.13|>=2.2,<2.2.9", - "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8.23,<2.8.25|>=3.2.10,<3.2.12|>=3.3.3,<3.3.5|>=2.8,<2.8.6|>=3,<3.0.6", + "symfony/security": ">=2.7.30,<2.7.32|>=2.8.23,<2.8.25|>=3.2.10,<3.2.12|>=3.3.3,<3.3.5|>=2,<2.0.25|>=2.3,<2.3.37|>=2.4,<2.6.13|>=2.7,<2.7.9|>=2.1,<2.1.13|>=2.2,<2.2.9", + "symfony/security-core": ">=2.8,<2.8.6|>=3,<3.0.6|>=2.7.30,<2.7.32|>=2.8.23,<2.8.25|>=3.2.10,<3.2.12|>=3.3.3,<3.3.5|>=2.4,<2.6.13|>=2.7,<2.7.9", "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.13|>=2.8,<2.8.6|>=3,<3.0.6", "symfony/serializer": ">=2,<2.0.11", "symfony/symfony": ">=2,<2.3.41|>=2.4,<2.7.13|>=2.8,<2.8.6|>=3,<3.0.6|>=2.7.30,<2.7.32|>=2.8.23,<2.8.25|>=3.2.10,<3.2.12|>=3.3.3,<3.3.5", @@ -2974,11 +2976,11 @@ "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1,<2.1.2|>=2.1.0-beta1,<2.1.3", + "thelia/thelia": ">=2.1.0-beta1,<2.1.3|>=2.1,<2.1.2", "twig/twig": "<1.20", - "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.22|>=8,<8.7.5", - "typo3/flow": ">=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5|>=1,<1.0.4", - "typo3/neos": ">=1.2,<1.2.13|>=2,<2.0.4|>=1.1,<1.1.3", + "typo3/cms": ">=8,<8.7.5|>=7,<7.6.22|>=6.2,<6.2.30", + "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", + "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", "willdurand/js-translation-bundle": "<2.1.1", "yiisoft/yii": ">=1.1.14,<1.1.15", "yiisoft/yii2": "<2.0.5", @@ -3022,7 +3024,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2017-10-29T18:43:15+00:00" + "time": "2017-11-11T03:27:01+00:00" }, { "name": "sabberworm/php-css-parser", @@ -3281,16 +3283,16 @@ }, { "name": "sentry/sentry", - "version": "1.8.0", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/getsentry/sentry-php.git", - "reference": "b3a03c1eb2877f0c66885641a52216dcbf313a11" + "reference": "3e4bb1486cd4e09869cb3342aef374788d540f1c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/b3a03c1eb2877f0c66885641a52216dcbf313a11", - "reference": "b3a03c1eb2877f0c66885641a52216dcbf313a11", + "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/3e4bb1486cd4e09869cb3342aef374788d540f1c", + "reference": "3e4bb1486cd4e09869cb3342aef374788d540f1c", "shasum": "" }, "require": { @@ -3317,7 +3319,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8.x-dev" + "dev-master": "1.9.x-dev" } }, "autoload": { @@ -3341,7 +3343,7 @@ "log", "logging" ], - "time": "2017-10-29T21:19:48+00:00" + "time": "2017-11-09T17:44:23+00:00" }, { "name": "sentry/sentry-laravel", @@ -3399,16 +3401,16 @@ }, { "name": "stripe/stripe-php", - "version": "v5.5.0", + "version": "v5.6.0", "source": { "type": "git", "url": "https://github.com/stripe/stripe-php.git", - "reference": "a523748f2db82beacfac7b22e0642e326aa3be64" + "reference": "0922533c9db11292c7a0aeafc27638f8f31b7fb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stripe/stripe-php/zipball/a523748f2db82beacfac7b22e0642e326aa3be64", - "reference": "a523748f2db82beacfac7b22e0642e326aa3be64", + "url": "https://api.github.com/repos/stripe/stripe-php/zipball/0922533c9db11292c7a0aeafc27638f8f31b7fb6", + "reference": "0922533c9db11292c7a0aeafc27638f8f31b7fb6", "shasum": "" }, "require": { @@ -3450,7 +3452,7 @@ "payment processing", "stripe" ], - "time": "2017-10-27T16:27:13+00:00" + "time": "2017-10-31T18:52:25+00:00" }, { "name": "swiftmailer/swiftmailer", @@ -3509,16 +3511,16 @@ }, { "name": "symfony/console", - "version": "v3.3.10", + "version": "v3.3.11", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "116bc56e45a8e5572e51eb43ab58c769a352366c" + "reference": "fd684d68f83568d8293564b4971928a2c4bdfc5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/116bc56e45a8e5572e51eb43ab58c769a352366c", - "reference": "116bc56e45a8e5572e51eb43ab58c769a352366c", + "url": "https://api.github.com/repos/symfony/console/zipball/fd684d68f83568d8293564b4971928a2c4bdfc5c", + "reference": "fd684d68f83568d8293564b4971928a2c4bdfc5c", "shasum": "" }, "require": { @@ -3573,7 +3575,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-10-02T06:42:24+00:00" + "time": "2017-11-07T14:16:22+00:00" }, { "name": "symfony/css-selector", @@ -3630,16 +3632,16 @@ }, { "name": "symfony/debug", - "version": "v3.3.10", + "version": "v3.3.11", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "eb95d9ce8f18dcc1b3dfff00cb624c402be78ffd" + "reference": "74557880e2846b5c84029faa96b834da37e29810" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/eb95d9ce8f18dcc1b3dfff00cb624c402be78ffd", - "reference": "eb95d9ce8f18dcc1b3dfff00cb624c402be78ffd", + "url": "https://api.github.com/repos/symfony/debug/zipball/74557880e2846b5c84029faa96b834da37e29810", + "reference": "74557880e2846b5c84029faa96b834da37e29810", "shasum": "" }, "require": { @@ -3682,20 +3684,20 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2017-10-02T06:42:24+00:00" + "time": "2017-11-10T16:38:39+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v3.3.10", + "version": "v3.3.11", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "d7ba037e4b8221956ab1e221c73c9e27e05dd423" + "reference": "271d8c27c3ec5ecee6e2ac06016232e249d638d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d7ba037e4b8221956ab1e221c73c9e27e05dd423", - "reference": "d7ba037e4b8221956ab1e221c73c9e27e05dd423", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/271d8c27c3ec5ecee6e2ac06016232e249d638d9", + "reference": "271d8c27c3ec5ecee6e2ac06016232e249d638d9", "shasum": "" }, "require": { @@ -3745,20 +3747,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2017-10-02T06:42:24+00:00" + "time": "2017-11-05T15:47:03+00:00" }, { "name": "symfony/finder", - "version": "v3.3.10", + "version": "v3.3.11", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "773e19a491d97926f236942484cb541560ce862d" + "reference": "138af5ec075d4b1d1bd19de08c38a34bb2d7d880" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/773e19a491d97926f236942484cb541560ce862d", - "reference": "773e19a491d97926f236942484cb541560ce862d", + "url": "https://api.github.com/repos/symfony/finder/zipball/138af5ec075d4b1d1bd19de08c38a34bb2d7d880", + "reference": "138af5ec075d4b1d1bd19de08c38a34bb2d7d880", "shasum": "" }, "require": { @@ -3794,20 +3796,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2017-10-02T06:42:24+00:00" + "time": "2017-11-05T15:47:03+00:00" }, { "name": "symfony/http-foundation", - "version": "v3.3.10", + "version": "v3.3.11", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "22cf9c2b1d9f67cc8e75ae7f4eaa60e4c1eff1f8" + "reference": "873ccdf8c1cae20da0184862820c434e20fdc8ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/22cf9c2b1d9f67cc8e75ae7f4eaa60e4c1eff1f8", - "reference": "22cf9c2b1d9f67cc8e75ae7f4eaa60e4c1eff1f8", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/873ccdf8c1cae20da0184862820c434e20fdc8ce", + "reference": "873ccdf8c1cae20da0184862820c434e20fdc8ce", "shasum": "" }, "require": { @@ -3847,20 +3849,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2017-10-05T23:10:23+00:00" + "time": "2017-11-05T19:07:00+00:00" }, { "name": "symfony/http-kernel", - "version": "v3.3.10", + "version": "v3.3.11", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "654f047a78756964bf91b619554f956517394018" + "reference": "f38c96b8d88a37b4f6bc8ae46a48b018d4894dd0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/654f047a78756964bf91b619554f956517394018", - "reference": "654f047a78756964bf91b619554f956517394018", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f38c96b8d88a37b4f6bc8ae46a48b018d4894dd0", + "reference": "f38c96b8d88a37b4f6bc8ae46a48b018d4894dd0", "shasum": "" }, "require": { @@ -3868,7 +3870,7 @@ "psr/log": "~1.0", "symfony/debug": "~2.8|~3.0", "symfony/event-dispatcher": "~2.8|~3.0", - "symfony/http-foundation": "~3.3" + "symfony/http-foundation": "^3.3.11" }, "conflict": { "symfony/config": "<2.8", @@ -3933,7 +3935,7 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2017-10-05T23:40:19+00:00" + "time": "2017-11-10T20:08:13+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -3996,16 +3998,16 @@ }, { "name": "symfony/process", - "version": "v3.3.10", + "version": "v3.3.11", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "fdf89e57a723a29baf536e288d6e232c059697b1" + "reference": "e14bb64d7559e6923fb13ee3b3d8fa763a2c0930" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/fdf89e57a723a29baf536e288d6e232c059697b1", - "reference": "fdf89e57a723a29baf536e288d6e232c059697b1", + "url": "https://api.github.com/repos/symfony/process/zipball/e14bb64d7559e6923fb13ee3b3d8fa763a2c0930", + "reference": "e14bb64d7559e6923fb13ee3b3d8fa763a2c0930", "shasum": "" }, "require": { @@ -4041,7 +4043,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-10-02T06:42:24+00:00" + "time": "2017-11-05T15:47:03+00:00" }, { "name": "symfony/psr-http-message-bridge", @@ -4105,16 +4107,16 @@ }, { "name": "symfony/routing", - "version": "v3.3.10", + "version": "v3.3.11", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "2e26fa63da029dab49bf9377b3b4f60a8fecb009" + "reference": "cf7fa1dfcfee2c96969bfa1c0341e5627ecb1e95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/2e26fa63da029dab49bf9377b3b4f60a8fecb009", - "reference": "2e26fa63da029dab49bf9377b3b4f60a8fecb009", + "url": "https://api.github.com/repos/symfony/routing/zipball/cf7fa1dfcfee2c96969bfa1c0341e5627ecb1e95", + "reference": "cf7fa1dfcfee2c96969bfa1c0341e5627ecb1e95", "shasum": "" }, "require": { @@ -4179,20 +4181,20 @@ "uri", "url" ], - "time": "2017-10-02T07:25:00+00:00" + "time": "2017-11-07T14:16:22+00:00" }, { "name": "symfony/translation", - "version": "v3.3.10", + "version": "v3.3.11", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "409bf229cd552bf7e3faa8ab7e3980b07672073f" + "reference": "373e553477e55cd08f8b86b74db766c75b987fdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/409bf229cd552bf7e3faa8ab7e3980b07672073f", - "reference": "409bf229cd552bf7e3faa8ab7e3980b07672073f", + "url": "https://api.github.com/repos/symfony/translation/zipball/373e553477e55cd08f8b86b74db766c75b987fdb", + "reference": "373e553477e55cd08f8b86b74db766c75b987fdb", "shasum": "" }, "require": { @@ -4244,20 +4246,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2017-10-02T06:42:24+00:00" + "time": "2017-11-07T14:12:55+00:00" }, { "name": "symfony/var-dumper", - "version": "v3.3.10", + "version": "v3.3.11", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "03e3693a36701f1c581dd24a6d6eea2eba2113f6" + "reference": "805de6bd6869073e60610df1b14ab7d969c61b01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/03e3693a36701f1c581dd24a6d6eea2eba2113f6", - "reference": "03e3693a36701f1c581dd24a6d6eea2eba2113f6", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/805de6bd6869073e60610df1b14ab7d969c61b01", + "reference": "805de6bd6869073e60610df1b14ab7d969c61b01", "shasum": "" }, "require": { @@ -4312,7 +4314,7 @@ "debug", "dump" ], - "time": "2017-10-02T06:42:24+00:00" + "time": "2017-11-07T14:16:22+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -5048,16 +5050,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "5.2.2", + "version": "5.2.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "8ed1902a57849e117b5651fc1a5c48110946c06b" + "reference": "8e1d2397d8adf59a3f12b2878a3aaa66d1ab189d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/8ed1902a57849e117b5651fc1a5c48110946c06b", - "reference": "8ed1902a57849e117b5651fc1a5c48110946c06b", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/8e1d2397d8adf59a3f12b2878a3aaa66d1ab189d", + "reference": "8e1d2397d8adf59a3f12b2878a3aaa66d1ab189d", "shasum": "" }, "require": { @@ -5066,7 +5068,7 @@ "php": "^7.0", "phpunit/php-file-iterator": "^1.4.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^1.4.11 || ^2.0", + "phpunit/php-token-stream": "^2.0", "sebastian/code-unit-reverse-lookup": "^1.0.1", "sebastian/environment": "^3.0", "sebastian/version": "^2.0.1", @@ -5108,7 +5110,7 @@ "testing", "xunit" ], - "time": "2017-08-03T12:40:43+00:00" + "time": "2017-11-03T13:47:33+00:00" }, { "name": "phpunit/php-file-iterator", @@ -5298,16 +5300,16 @@ }, { "name": "phpunit/phpunit", - "version": "6.4.3", + "version": "6.4.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "06b28548fd2b4a20c3cd6e247dc86331a7d4db13" + "reference": "562f7dc75d46510a4ed5d16189ae57fbe45a9932" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/06b28548fd2b4a20c3cd6e247dc86331a7d4db13", - "reference": "06b28548fd2b4a20c3cd6e247dc86331a7d4db13", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/562f7dc75d46510a4ed5d16189ae57fbe45a9932", + "reference": "562f7dc75d46510a4ed5d16189ae57fbe45a9932", "shasum": "" }, "require": { @@ -5378,7 +5380,7 @@ "testing", "xunit" ], - "time": "2017-10-16T13:18:59+00:00" + "time": "2017-11-08T11:26:09+00:00" }, { "name": "phpunit/phpunit-mock-objects", @@ -5486,30 +5488,30 @@ }, { "name": "sebastian/comparator", - "version": "2.0.2", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "ae068fede81d06e7bb9bb46a367210a3d3e1fe6a" + "reference": "1174d9018191e93cb9d719edec01257fc05f8158" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/ae068fede81d06e7bb9bb46a367210a3d3e1fe6a", - "reference": "ae068fede81d06e7bb9bb46a367210a3d3e1fe6a", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1174d9018191e93cb9d719edec01257fc05f8158", + "reference": "1174d9018191e93cb9d719edec01257fc05f8158", "shasum": "" }, "require": { "php": "^7.0", "sebastian/diff": "^2.0", - "sebastian/exporter": "^3.0" + "sebastian/exporter": "^3.1" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^6.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "2.1.x-dev" } }, "autoload": { @@ -5540,13 +5542,13 @@ } ], "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", + "homepage": "https://github.com/sebastianbergmann/comparator", "keywords": [ "comparator", "compare", "equality" ], - "time": "2017-08-03T07:14:59+00:00" + "time": "2017-11-03T07:16:52+00:00" }, { "name": "sebastian/diff", @@ -6153,7 +6155,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.0", + "php": "^7.1", "ext-intl": "*" }, "platform-dev": [] diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php index d7bdebfc4..461de4475 100644 --- a/database/factories/ModelFactory.php +++ b/database/factories/ModelFactory.php @@ -136,3 +136,9 @@ $factory->define(App\Invitation::class, function (Faker\Generator $faker) { 'account_id' => 1, ]; }); + +$factory->define(App\Address::class, function (Faker\Generator $faker) { + return [ + 'account_id' => 1, + ]; +}); diff --git a/database/migrations/2017_11_10_174654_create_contact_fields_table.php b/database/migrations/2017_11_10_174654_create_contact_fields_table.php new file mode 100644 index 000000000..81a658867 --- /dev/null +++ b/database/migrations/2017_11_10_174654_create_contact_fields_table.php @@ -0,0 +1,106 @@ +increments('id'); + $table->integer('account_id')->unsigned(); + $table->string('name'); + $table->string('fontawesome_icon')->nullable(); + $table->string('protocol')->nullable(); + $table->boolean('delible')->default(1); + $table->string('type')->nullable(); + $table->timestamps(); + + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + }); + + Schema::create('contact_fields', function (Blueprint $table) { + $table->increments('id'); + $table->integer('account_id')->unsigned(); + $table->integer('contact_id')->unsigned(); + $table->integer('contact_field_type_id')->unsigned(); + $table->string('data'); + $table->timestamps(); + + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $table->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade'); + $table->foreign('contact_field_type_id')->references('id')->on('contact_field_types')->onDelete('cascade'); + }); + + Schema::create('addresses', function (Blueprint $table) { + $table->increments('id'); + $table->integer('account_id')->unsigned(); + $table->integer('contact_id')->unsigned(); + $table->string('name')->nullable(); + $table->string('street')->nullable(); + $table->string('city')->nullable(); + $table->string('province')->nullable(); + $table->string('postal_code')->nullable(); + $table->integer('country_id')->nullable(); + $table->timestamps(); + + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $table->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade'); + }); + + Schema::create('default_contact_field_types', function (Blueprint $table) { + $table->increments('id'); + $table->string('name'); + $table->string('fontawesome_icon')->nullable(); + $table->string('protocol')->nullable(); + $table->boolean('migrated')->default(0); + $table->boolean('delible')->default(1); + $table->string('type')->nullable(); + $table->timestamps(); + }); + + $id = DB::table('default_contact_field_types')->insertGetId([ + 'name' => 'Email', + 'fontawesome_icon' => 'fa fa-envelope-open-o', + 'protocol' => 'mailto:', + 'delible' => false, + 'type' => 'email', + ]); + + $id = DB::table('default_contact_field_types')->insertGetId([ + 'name' => 'Phone', + 'fontawesome_icon' => 'fa fa-volume-control-phone', + 'protocol' => 'tel:', + 'delible' => false, + 'type' => 'phone', + ]); + + $id = DB::table('default_contact_field_types')->insertGetId([ + 'name' => 'Facebook', + 'fontawesome_icon' => 'fa fa-facebook-official', + ]); + + $id = DB::table('default_contact_field_types')->insertGetId([ + 'name' => 'Twitter', + 'fontawesome_icon' => 'fa fa-twitter-square', + ]); + + $id = DB::table('default_contact_field_types')->insertGetId([ + 'name' => 'Whatsapp', + 'fontawesome_icon' => 'fa fa-whatsapp', + ]); + + $id = DB::table('default_contact_field_types')->insertGetId([ + 'name' => 'Telegram', + 'fontawesome_icon' => 'fa fa-telegram', + 'protocol' => 'telegram:', + ]); + } +} diff --git a/database/migrations/2017_11_10_181043_migrate_contacts_information.php b/database/migrations/2017_11_10_181043_migrate_contacts_information.php new file mode 100644 index 000000000..b3b4a25d6 --- /dev/null +++ b/database/migrations/2017_11_10_181043_migrate_contacts_information.php @@ -0,0 +1,92 @@ +get(); + + foreach ($accounts as $account) { + $contacts = DB::table('contacts')->where('account_id', $account->id)->get(); + + $account->populateContactFieldTypeTable(); + + // EMAIL + $emailId = DB::table('contact_field_types')->where('account_id', $account->id) + ->where('type', 'email') + ->first(); + + // PHONE NUMBER + $idPhoneNumber = DB::table('contact_field_types')->where('account_id', $account->id) + ->where('type', 'phone') + ->first(); + + // FACEBOOK + $idFacebook = DB::table('contact_field_types')->where('account_id', $account->id) + ->where('name', 'Facebook') + ->first(); + + // TWITTER + $idTwitter = DB::table('contact_field_types')->where('account_id', $account->id) + ->where('name', 'Twitter') + ->first(); + + foreach ($contacts as $contact) { + if (! is_null($contact->email)) { + DB::table('contact_fields')->insert([ + 'account_id' => $account->id, + 'contact_id' => $contact->id, + 'contact_field_type_id' => $emailId->id, + 'data' => $contact->email, + 'created_at' => \Carbon\Carbon::now(), + ]); + } + + if (! is_null($contact->phone_number)) { + DB::table('contact_fields')->insert([ + 'account_id' => $account->id, + 'contact_id' => $contact->id, + 'contact_field_type_id' => $idPhoneNumber->id, + 'data' => $contact->phone_number, + 'created_at' => \Carbon\Carbon::now(), + ]); + } + + if (! is_null($contact->facebook_profile_url)) { + DB::table('contact_fields')->insert([ + 'account_id' => $account->id, + 'contact_id' => $contact->id, + 'contact_field_type_id' => $idFacebook->id, + 'data' => $contact->facebook_profile_url, + 'created_at' => \Carbon\Carbon::now(), + ]); + } + + if (! is_null($contact->twitter_profile_url)) { + DB::table('contact_fields')->insert([ + 'account_id' => $account->id, + 'contact_id' => $contact->id, + 'contact_field_type_id' => $idTwitter->id, + 'data' => $contact->twitter_profile_url, + 'created_at' => \Carbon\Carbon::now(), + ]); + } + } + + \Log::info('ACCOUNT PASSED: '.$account->id); + } + + $instance = Instance::first(); + $instance->markDefaultContactFieldTypeAsMigrated(); + \Log::info('PASSED'); + } +} diff --git a/database/migrations/2017_11_10_202620_move_addresses_from_contact_to_addresses.php b/database/migrations/2017_11_10_202620_move_addresses_from_contact_to_addresses.php new file mode 100644 index 000000000..81c598cec --- /dev/null +++ b/database/migrations/2017_11_10_202620_move_addresses_from_contact_to_addresses.php @@ -0,0 +1,30 @@ +select('account_id', 'id', 'street', 'city', 'province', 'postal_code', 'country_id')->get(); + foreach ($contacts as $contact) { + if (! is_null($contact->street) or ! is_null($contact->city) or ! is_null($contact->province) or ! is_null($contact->postal_code) or ! is_null($contact->country_id)) { + $id = DB::table('addresses')->insertGetId([ + 'account_id' => $contact->account_id, + 'contact_id' => $contact->id, + 'name' => 'default', + 'street' => (is_null($contact->street) ? null : $contact->street), + 'city' => (is_null($contact->city) ? null : $contact->city), + 'province' => (is_null($contact->province) ? null : $contact->province), + 'postal_code' => (is_null($contact->postal_code) ? null : $contact->postal_code), + 'country_id' => (is_null($contact->country_id) ? null : $contact->country_id), + ]); + } + } + } +} diff --git a/database/migrations/2017_11_10_204035_delete_contact_fields_from_contacts.php b/database/migrations/2017_11_10_204035_delete_contact_fields_from_contacts.php new file mode 100644 index 000000000..e3edf2da0 --- /dev/null +++ b/database/migrations/2017_11_10_204035_delete_contact_fields_from_contacts.php @@ -0,0 +1,29 @@ +dropIndex('unique_for_each_account_email_pair'); + $table->dropColumn('email'); + $table->dropColumn('phone_number'); + $table->dropColumn('street'); + $table->dropColumn('city'); + $table->dropColumn('province'); + $table->dropColumn('postal_code'); + $table->dropColumn('country_id'); + $table->dropColumn('facebook_profile_url'); + $table->dropColumn('twitter_profile_url'); + }); + } +} diff --git a/database/seeds/FakeContentTableSeeder.php b/database/seeds/FakeContentTableSeeder.php index 540f73cff..c341d482c 100644 --- a/database/seeds/FakeContentTableSeeder.php +++ b/database/seeds/FakeContentTableSeeder.php @@ -1,5 +1,6 @@ str_random(30), ]); + $account = Account::find($accountID); + $account->populateContactFieldTypeTable(); + // populate user table $userId = DB::table('users')->insertGetId([ 'account_id' => $accountID, @@ -59,25 +63,6 @@ class FakeContentTableSeeder extends Seeder $contact = Contact::find($contactID); $contact->setAvatarColor(); - // add email - if (rand(1, 2) == 1) { - $contact->email = $faker->email; - } - - // add phonenumber - if (rand(1, 2) == 1) { - $contact->phone_number = $faker->phoneNumber; - } - - // add address - if (rand(1, 2) == 1) { - $contact->street = $faker->streetAddress; - $contact->postal_code = $faker->postcode; - $contact->province = $faker->state; - $contact->city = $faker->city; - $countryID = '1'; - } - // add food preferencies if (rand(1, 2) == 1) { $contact->food_preferencies = $faker->realText(); diff --git a/docs/contribute/contribute.md b/docs/contribute/contribute.md index b781a2ab8..0e3cef553 100644 --- a/docs/contribute/contribute.md +++ b/docs/contribute/contribute.md @@ -90,13 +90,21 @@ the application. To compile those front-end assets, use `npm run dev`. To monitor changes and compile assets on the fly, use `npm run watch`. -#### Bootstrap 4 +#### CSS -At the current time, we are using Bootstrap 4 Alpha 2. Not everything though - -we do use only what we need. I would have wanted to use something completely -custom, but why reinvent the wheel? Anyway, make sure you don't update this -dependency with Bower. If you do, make sure that everything is thoroughly tested -as when Bootstrap changes version, a lot of changes are introduced. +At the current time, we are using a mix of Bootstrap 4 and [Tachyons](https://tachyons.io). +We aim to use a maximum of [Atomic CSS](https://adamwathan.me/css-utility-classes-and-separation-of-concerns/) +in place of having bloated, super hard to maintain CSS files. This is why, +over time, we'll get rid of Bootstrap entirely. + +#### JS and Vue + +We are also using [Vue.js](https://vuejs.org/) in some places of the +application, and we'll use it more and more over time. Vue is very simple to +learn and use, and with [Vue Components](https://vuejs.org/v2/guide/components.html), +we can easily create isolated, reusable components in the app. If you want to +add a new feature, you don't need to use Vue.js - you can use plain HTML views +served by the backend. But with Vue.js, it'll be a nicer experience. ### Backend diff --git a/public/js/app.js b/public/js/app.js index 39829f477..07edeec7c 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -2432,6 +2432,838 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol /***/ }), +/***/ "./node_modules/babel-loader/lib/index.js?{\"cacheDirectory\":true,\"presets\":[[\"env\",{\"modules\":false,\"targets\":{\"browsers\":[\"> 2%\"],\"uglify\":true}}]],\"plugins\":[\"transform-object-rest-spread\"]}!./node_modules/vue-loader/lib/selector.js?type=script&index=0&bustCache!./resources/assets/js/components/people/Addresses.vue": +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +var _methods; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// + +/* harmony default export */ __webpack_exports__["default"] = ({ + /* + * The component's data. + */ + data: function data() { + return { + contactAddresses: [], + countries: [], + + editMode: false, + addMode: false, + + createForm: { + country_id: 0, + name: '', + street: '', + city: '', + province: '', + postal_code: '' + }, + + updateForm: { + id: '', + country_id: 0, + name: '', + street: '', + city: '', + province: '', + postal_code: '' + } + }; + }, + + + /** + * Prepare the component (Vue 1.x). + */ + ready: function ready() { + this.prepareComponent(); + }, + + + /** + * Prepare the component (Vue 2.x). + */ + mounted: function mounted() { + this.prepareComponent(); + }, + + + props: ['contactId'], + + methods: (_methods = { + /** + * Prepare the component. + */ + prepareComponent: function prepareComponent() { + this.getAddresses(); + this.getCountries(); + }, + getAddresses: function getAddresses() { + var _this = this; + + axios.get('/people/' + this.contactId + '/addresses').then(function (response) { + _this.contactAddresses = response.data; + }); + }, + getCountries: function getCountries() { + var _this2 = this; + + axios.get('/people/' + this.contactId + '/countries').then(function (response) { + _this2.countries = response.data; + }); + }, + store: function store() { + this.persistClient('post', '/people/' + this.contactId + '/contactfield', this.createForm); + + this.addMode = false; + }, + reinitialize: function reinitialize() { + this.createForm.country_id = ''; + this.createForm.name = ''; + this.createForm.street = ''; + this.createForm.city = ''; + this.createForm.province = ''; + this.createForm.postal_code = ''; + }, + toggleAdd: function toggleAdd() { + this.addMode = true; + this.reinitialize(); + }, + toggleEdit: function toggleEdit(contactAddress) { + Vue.set(contactAddress, 'edit', !contactAddress.edit); + this.updateForm.id = contactAddress.id; + this.updateForm.country_id = contactAddress.country_id; + this.updateForm.name = contactAddress.name; + this.updateForm.street = contactAddress.street; + this.updateForm.city = contactAddress.city; + this.updateForm.province = contactAddress.province; + this.updateForm.postal_code = contactAddress.postal_code; + } + }, _defineProperty(_methods, 'store', function store() { + this.persistClient('post', '/people/' + this.contactId + '/addresses', this.createForm); + + this.addMode = false; + }), _defineProperty(_methods, 'update', function update(contactAddress) { + this.persistClient('put', '/people/' + this.contactId + '/addresses/' + contactAddress.id, this.updateForm); + }), _defineProperty(_methods, 'trash', function trash(contactAddress) { + this.updateForm.id = contactAddress.id; + + this.persistClient('delete', '/people/' + this.contactId + '/addresses/' + contactAddress.id, this.updateForm); + + if (this.contactAddresses.length <= 1) { + this.editMode = false; + } + }), _defineProperty(_methods, 'persistClient', function persistClient(method, uri, form) { + var _this3 = this; + + form.errors = {}; + + axios[method](uri, form).then(function (response) { + _this3.getAddresses(); + }).catch(function (error) { + if (_typeof(error.response.data) === 'object') { + form.errors = _.flatten(_.toArray(error.response.data)); + } else { + form.errors = ['Something went wrong. Please try again.']; + } + }); + }), _methods) +}); + +/***/ }), + +/***/ "./node_modules/babel-loader/lib/index.js?{\"cacheDirectory\":true,\"presets\":[[\"env\",{\"modules\":false,\"targets\":{\"browsers\":[\"> 2%\"],\"uglify\":true}}]],\"plugins\":[\"transform-object-rest-spread\"]}!./node_modules/vue-loader/lib/selector.js?type=script&index=0&bustCache!./resources/assets/js/components/people/ContactInformation.vue": +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// + +/* harmony default export */ __webpack_exports__["default"] = ({ + /* + * The component's data. + */ + data: function data() { + return { + contactInformationData: [], + contactFieldTypes: [], + + editMode: false, + addMode: false, + updateMode: false, + + createForm: { + contact_field_type_id: '', + data: '', + errors: [] + }, + + updateForm: { + id: '', + contact_field_type_id: '', + data: '', + edit: false, + errors: [] + } + }; + }, + + + /** + * Prepare the component (Vue 1.x). + */ + ready: function ready() { + this.prepareComponent(); + }, + + + /** + * Prepare the component (Vue 2.x). + */ + mounted: function mounted() { + this.prepareComponent(); + }, + + + props: ['contactId'], + + methods: { + /** + * Prepare the component. + */ + prepareComponent: function prepareComponent() { + this.getContactInformationData(); + this.getContactFieldTypes(); + }, + getContactInformationData: function getContactInformationData() { + var _this = this; + + axios.get('/people/' + this.contactId + '/contactfield').then(function (response) { + _this.contactInformationData = response.data; + }); + }, + getContactFieldTypes: function getContactFieldTypes() { + var _this2 = this; + + axios.get('/people/' + this.contactId + '/contactfieldtypes').then(function (response) { + _this2.contactFieldTypes = response.data; + }); + }, + store: function store() { + this.persistClient('post', '/people/' + this.contactId + '/contactfield', this.createForm); + + this.addMode = false; + }, + toggleAdd: function toggleAdd() { + this.addMode = true; + this.createForm.data = ''; + this.createForm.contact_field_type_id = ''; + }, + toggleEdit: function toggleEdit(contactField) { + Vue.set(contactField, 'edit', !contactField.edit); + this.updateForm.id = contactField.id; + this.updateForm.data = contactField.data; + this.updateForm.contact_field_type_id = contactField.contact_field_type_id; + }, + update: function update(contactField) { + this.persistClient('put', '/people/' + this.contactId + '/contactfield/' + contactField.id, this.updateForm); + }, + trash: function trash(contactField) { + this.updateForm.id = contactField.id; + + this.persistClient('delete', '/people/' + this.contactId + '/contactfield/' + contactField.id, this.updateForm); + + if (this.contactInformationData.length <= 1) { + this.editMode = false; + } + }, + persistClient: function persistClient(method, uri, form) { + var _this3 = this; + + form.errors = {}; + + axios[method](uri, form).then(function (response) { + _this3.getContactInformationData(); + }).catch(function (error) { + if (_typeof(error.response.data) === 'object') { + form.errors = _.flatten(_.toArray(error.response.data)); + } else { + form.errors = ['Something went wrong. Please try again.']; + } + }); + } + } +}); + +/***/ }), + +/***/ "./node_modules/babel-loader/lib/index.js?{\"cacheDirectory\":true,\"presets\":[[\"env\",{\"modules\":false,\"targets\":{\"browsers\":[\"> 2%\"],\"uglify\":true}}]],\"plugins\":[\"transform-object-rest-spread\"]}!./node_modules/vue-loader/lib/selector.js?type=script&index=0&bustCache!./resources/assets/js/components/settings/ContactFieldTypes.vue": +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// + +/* harmony default export */ __webpack_exports__["default"] = ({ + /* + * The component's data. + */ + data: function data() { + return { + contactFieldTypes: [], + + submitted: false, + edited: false, + deleted: false, + + createForm: { + name: '', + protocol: '', + icon: '', + errors: [] + }, + + editForm: { + id: '', + name: '', + protocol: '', + icon: '', + errors: [] + } + }; + }, + + + /** + * Prepare the component (Vue 1.x). + */ + ready: function ready() { + this.prepareComponent(); + }, + + + /** + * Prepare the component (Vue 2.x). + */ + mounted: function mounted() { + this.prepareComponent(); + }, + + + methods: { + /** + * Prepare the component. + */ + prepareComponent: function prepareComponent() { + this.getContactFieldTypes(); + + $('#modal-create-contact-field-type').on('shown.bs.modal', function () { + $('#name').focus(); + }); + + $('#modal-edit-contact-field-type').on('shown.bs.modal', function () { + $('#name').focus(); + }); + }, + getContactFieldTypes: function getContactFieldTypes() { + var _this = this; + + axios.get('/settings/personalization/contactfieldtypes/').then(function (response) { + _this.contactFieldTypes = response.data; + }); + }, + add: function add() { + $('#modal-create-contact-field-type').modal('show'); + }, + store: function store() { + this.persistClient('post', '/settings/personalization/contactfieldtypes', this.createForm, '#modal-create-contact-field-type', this.submitted); + }, + edit: function edit(contactFieldType) { + this.editForm.id = contactFieldType.id; + this.editForm.name = contactFieldType.name; + this.editForm.protocol = contactFieldType.protocol; + this.editForm.icon = contactFieldType.fontawesome_icon; + + $('#modal-edit-contact-field-type').modal('show'); + }, + update: function update() { + this.persistClient('put', '/settings/personalization/contactfieldtypes/' + this.editForm.id, this.editForm, '#modal-edit-contact-field-type', this.edited); + }, + showDelete: function showDelete(contactFieldType) { + this.editForm.id = contactFieldType.id; + + $('#modal-delete-contact-field-type').modal('show'); + }, + trash: function trash() { + this.persistClient('delete', '/settings/personalization/contactfieldtypes/' + this.editForm.id, this.editForm, '#modal-delete-contact-field-type', this.deleted); + }, + persistClient: function persistClient(method, uri, form, modal, success) { + var _this2 = this; + + form.errors = {}; + + axios[method](uri, form).then(function (response) { + _this2.getContactFieldTypes(); + + form.id = ''; + form.name = ''; + form.protocol = ''; + form.icon = ''; + form.errors = []; + + $(modal).modal('hide'); + + success = true; + }).catch(function (error) { + if (_typeof(error.response.data) === 'object') { + form.errors = _.flatten(_.toArray(error.response.data)); + } else { + form.errors = ['Something went wrong. Please try again.']; + } + }); + } + } +}); + +/***/ }), + /***/ "./node_modules/bootstrap/dist/js/umd/alert.js": /***/ (function(module, exports, __webpack_require__) { @@ -4602,6 +5434,21 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ }); +/***/ }), + +/***/ "./node_modules/css-loader/index.js?sourceMap!./node_modules/vue-loader/lib/style-compiler/index.js?{\"vue\":true,\"id\":\"data-v-06458126\",\"scoped\":true,\"hasInlineConfig\":true}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0&bustCache!./resources/assets/js/components/people/ContactInformation.vue": +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__("./node_modules/css-loader/lib/css-base.js")(true); +// imports + + +// module +exports.push([module.i, "\n", "", {"version":3,"sources":[],"names":[],"mappings":"","file":"ContactInformation.vue","sourceRoot":""}]); + +// exports + + /***/ }), /***/ "./node_modules/css-loader/index.js?sourceMap!./node_modules/vue-loader/lib/style-compiler/index.js?{\"vue\":true,\"id\":\"data-v-2ff4435c\",\"scoped\":true,\"hasInlineConfig\":true}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0&bustCache!./resources/assets/js/components/passport/PersonalAccessTokens.vue": @@ -4617,6 +5464,36 @@ exports.push([module.i, "\n.m-b-none[data-v-2ff4435c] {\n margin-bottom: 0;\n // exports +/***/ }), + +/***/ "./node_modules/css-loader/index.js?sourceMap!./node_modules/vue-loader/lib/style-compiler/index.js?{\"vue\":true,\"id\":\"data-v-4666559e\",\"scoped\":true,\"hasInlineConfig\":true}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0&bustCache!./resources/assets/js/components/people/Addresses.vue": +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__("./node_modules/css-loader/lib/css-base.js")(true); +// imports + + +// module +exports.push([module.i, "\n", "", {"version":3,"sources":[],"names":[],"mappings":"","file":"Addresses.vue","sourceRoot":""}]); + +// exports + + +/***/ }), + +/***/ "./node_modules/css-loader/index.js?sourceMap!./node_modules/vue-loader/lib/style-compiler/index.js?{\"vue\":true,\"id\":\"data-v-553e50c2\",\"scoped\":true,\"hasInlineConfig\":true}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0&bustCache!./resources/assets/js/components/settings/ContactFieldTypes.vue": +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__("./node_modules/css-loader/lib/css-base.js")(true); +// imports + + +// module +exports.push([module.i, "\n", "", {"version":3,"sources":[],"names":[],"mappings":"","file":"ContactFieldTypes.vue","sourceRoot":""}]); + +// exports + + /***/ }), /***/ "./node_modules/css-loader/index.js?sourceMap!./node_modules/vue-loader/lib/style-compiler/index.js?{\"vue\":true,\"id\":\"data-v-e79f7702\",\"scoped\":true,\"hasInlineConfig\":true}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0&bustCache!./resources/assets/js/components/passport/AuthorizedClients.vue": @@ -32646,6 +33523,409 @@ module.exports = function normalizeComponent ( } +/***/ }), + +/***/ "./node_modules/vue-loader/lib/template-compiler/index.js?{\"id\":\"data-v-06458126\",\"hasScoped\":true,\"buble\":{\"transforms\":{}}}!./node_modules/vue-loader/lib/selector.js?type=template&index=0&bustCache!./resources/assets/js/components/people/ContactInformation.vue": +/***/ (function(module, exports, __webpack_require__) { + +var render = function() { + var _vm = this + var _h = _vm.$createElement + var _c = _vm._self._c || _h + return _c( + "div", + { + staticClass: "br2 pa3 mb3 f6", + class: [_vm.editMode ? "bg-washed-yellow b--yellow ba" : "bg-near-white"] + }, + [ + _c("div", { staticClass: "w-100 dt" }, [ + _c("div", { staticClass: "dtc" }, [ + _c("h3", { staticClass: "f6 ttu normal" }, [ + _vm._v(_vm._s(_vm.trans("people.contact_info_title"))) + ]) + ]), + _vm._v(" "), + _vm.contactInformationData.length > 0 + ? _c("div", { staticClass: "dtc tr" }, [ + !_vm.editMode + ? _c( + "a", + { + staticClass: "pointer", + on: { + click: function($event) { + _vm.editMode = true + } + } + }, + [_vm._v(_vm._s(_vm.trans("app.edit")))] + ) + : _vm._e(), + _vm._v(" "), + _vm.editMode + ? _c( + "a", + { + staticClass: "pointer", + on: { + click: function($event) { + ;[(_vm.editMode = false), (_vm.addMode = false)] + } + } + }, + [_vm._v(_vm._s(_vm.trans("app.done")))] + ) + : _vm._e() + ]) + : _vm._e() + ]), + _vm._v(" "), + _vm.contactInformationData.length == 0 && !_vm.addMode + ? _c("p", { staticClass: "mb0" }, [ + _c("a", { staticClass: "pointer", on: { click: _vm.toggleAdd } }, [ + _vm._v(_vm._s(_vm.trans("app.add"))) + ]) + ]) + : _vm._e(), + _vm._v(" "), + _vm.contactInformationData.length > 0 + ? _c( + "ul", + [ + _vm._l(_vm.contactInformationData, function(contactInformation) { + return _c("li", { staticClass: "mb2" }, [ + _c( + "div", + { + directives: [ + { + name: "show", + rawName: "v-show", + value: !contactInformation.edit, + expression: "!contactInformation.edit" + } + ], + staticClass: "w-100 dt" + }, + [ + _c("div", { staticClass: "dtc" }, [ + contactInformation.fontawesome_icon + ? _c("i", { + staticClass: "pr2 f6 light-silver", + class: contactInformation.fontawesome_icon + }) + : _vm._e(), + _vm._v(" "), + !contactInformation.fontawesome_icon + ? _c("i", { + staticClass: "pr2 fa fa-address-card-o f6 gray" + }) + : _vm._e(), + _vm._v(" "), + contactInformation.protocol + ? _c( + "a", + { + attrs: { + href: + contactInformation.protocol + + contactInformation.data + } + }, + [_vm._v(_vm._s(contactInformation.data))] + ) + : _vm._e(), + _vm._v(" "), + !contactInformation.protocol + ? _c( + "a", + { attrs: { href: contactInformation.data } }, + [_vm._v(_vm._s(contactInformation.data))] + ) + : _vm._e() + ]), + _vm._v(" "), + _vm.editMode + ? _c("div", { staticClass: "dtc tr" }, [ + _c("i", { + staticClass: "fa fa-pencil-square-o pointer pr2", + on: { + click: function($event) { + _vm.toggleEdit(contactInformation) + } + } + }), + _vm._v(" "), + _c("i", { + staticClass: "fa fa-trash-o pointer", + on: { + click: function($event) { + _vm.trash(contactInformation) + } + } + }) + ]) + : _vm._e() + ] + ), + _vm._v(" "), + _c( + "div", + { + directives: [ + { + name: "show", + rawName: "v-show", + value: contactInformation.edit, + expression: "contactInformation.edit" + } + ], + staticClass: "w-100" + }, + [ + _c("form", { staticClass: "measure center" }, [ + _c("div", { staticClass: "mt3" }, [ + _c("label", { staticClass: "db fw6 lh-copy f6" }, [ + _vm._v( + "\n " + + _vm._s( + _vm.trans("people.contact_info_form_content") + ) + + "\n " + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.updateForm.data, + expression: "updateForm.data" + } + ], + staticClass: "pa2 db w-100", + attrs: { type: "text" }, + domProps: { value: _vm.updateForm.data }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set( + _vm.updateForm, + "data", + $event.target.value + ) + } + } + }) + ]), + _vm._v(" "), + _c("div", { staticClass: "lh-copy mt3" }, [ + _c( + "a", + { + staticClass: "btn btn-primary", + on: { + click: function($event) { + $event.preventDefault() + _vm.update(contactInformation) + } + } + }, + [_vm._v(_vm._s(_vm.trans("app.save")))] + ), + _vm._v(" "), + _c( + "a", + { + staticClass: "btn", + on: { + click: function($event) { + _vm.toggleEdit(contactInformation) + } + } + }, + [_vm._v(_vm._s(_vm.trans("app.cancel")))] + ) + ]) + ]) + ] + ) + ]) + }), + _vm._v(" "), + _vm.editMode && !_vm.addMode + ? _c("li", [ + _c( + "a", + { staticClass: "pointer", on: { click: _vm.toggleAdd } }, + [_vm._v(_vm._s(_vm.trans("app.add")))] + ) + ]) + : _vm._e() + ], + 2 + ) + : _vm._e(), + _vm._v(" "), + _vm.addMode + ? _c("div", [ + _c("form", { staticClass: "measure center" }, [ + _c("div", { staticClass: "mt3" }, [ + _c("label", { staticClass: "db fw6 lh-copy f6" }, [ + _vm._v( + "\n " + + _vm._s( + _vm.trans("people.contact_info_form_contact_type") + ) + + " " + ), + _c( + "a", + { + staticClass: "fr normal", + attrs: { + href: "/settings/personalization", + target: "_blank" + } + }, + [ + _vm._v( + _vm._s( + _vm.trans("people.contact_info_form_personalize") + ) + ) + ] + ) + ]), + _vm._v(" "), + _c( + "select", + { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.createForm.contact_field_type_id, + expression: "createForm.contact_field_type_id" + } + ], + staticClass: "db w-100 h2", + on: { + change: function($event) { + var $$selectedVal = Array.prototype.filter + .call($event.target.options, function(o) { + return o.selected + }) + .map(function(o) { + var val = "_value" in o ? o._value : o.value + return val + }) + _vm.$set( + _vm.createForm, + "contact_field_type_id", + $event.target.multiple + ? $$selectedVal + : $$selectedVal[0] + ) + } + } + }, + _vm._l(_vm.contactFieldTypes, function(contactFieldType) { + return _c( + "option", + { domProps: { value: contactFieldType.id } }, + [ + _vm._v( + "\n " + + _vm._s(contactFieldType.name) + + "\n " + ) + ] + ) + }) + ) + ]), + _vm._v(" "), + _c("div", { staticClass: "mt3" }, [ + _c("label", { staticClass: "db fw6 lh-copy f6" }, [ + _vm._v( + "\n " + + _vm._s(_vm.trans("people.contact_info_form_content")) + + "\n " + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.createForm.data, + expression: "createForm.data" + } + ], + staticClass: "pa2 db w-100", + attrs: { type: "text" }, + domProps: { value: _vm.createForm.data }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set(_vm.createForm, "data", $event.target.value) + } + } + }) + ]), + _vm._v(" "), + _c("div", { staticClass: "lh-copy mt3" }, [ + _c( + "a", + { + staticClass: "btn btn-primary", + on: { + click: function($event) { + $event.preventDefault() + _vm.store($event) + } + } + }, + [_vm._v(_vm._s(_vm.trans("app.add")))] + ), + _vm._v(" "), + _c( + "a", + { + staticClass: "btn", + on: { + click: function($event) { + _vm.addMode = false + } + } + }, + [_vm._v(_vm._s(_vm.trans("app.cancel")))] + ) + ]) + ]) + ]) + : _vm._e() + ] + ) +} +var staticRenderFns = [] +render._withStripped = true +module.exports = { render: render, staticRenderFns: staticRenderFns } +if (false) { + module.hot.accept() + if (module.hot.data) { + require("vue-hot-reload-api") .rerender("data-v-06458126", module.exports) + } +} + /***/ }), /***/ "./node_modules/vue-loader/lib/template-compiler/index.js?{\"id\":\"data-v-2ff4435c\",\"hasScoped\":true,\"buble\":{\"transforms\":{}}}!./node_modules/vue-loader/lib/selector.js?type=template&index=0&bustCache!./resources/assets/js/components/passport/PersonalAccessTokens.vue": @@ -33020,6 +34300,1578 @@ if (false) { /***/ }), +/***/ "./node_modules/vue-loader/lib/template-compiler/index.js?{\"id\":\"data-v-4666559e\",\"hasScoped\":true,\"buble\":{\"transforms\":{}}}!./node_modules/vue-loader/lib/selector.js?type=template&index=0&bustCache!./resources/assets/js/components/people/Addresses.vue": +/***/ (function(module, exports, __webpack_require__) { + +var render = function() { + var _vm = this + var _h = _vm.$createElement + var _c = _vm._self._c || _h + return _c( + "div", + { + staticClass: "br2 pa3 mb3 f6", + class: [_vm.editMode ? "bg-washed-yellow b--yellow ba" : "bg-near-white"] + }, + [ + _c("div", { staticClass: "w-100 dt" }, [ + _c("div", { staticClass: "dtc" }, [ + _c("h3", { staticClass: "f6 ttu normal" }, [ + _vm._v(_vm._s(_vm.trans("people.contact_address_title"))) + ]) + ]), + _vm._v(" "), + _vm.contactAddresses.length > 0 + ? _c("div", { staticClass: "dtc tr" }, [ + !_vm.editMode + ? _c( + "a", + { + staticClass: "pointer", + on: { + click: function($event) { + _vm.editMode = true + } + } + }, + [_vm._v(_vm._s(_vm.trans("app.edit")))] + ) + : _vm._e(), + _vm._v(" "), + _vm.editMode + ? _c( + "a", + { + staticClass: "pointer", + on: { + click: function($event) { + ;[(_vm.editMode = false), (_vm.addMode = false)] + } + } + }, + [_vm._v(_vm._s(_vm.trans("app.done")))] + ) + : _vm._e() + ]) + : _vm._e() + ]), + _vm._v(" "), + _vm.contactAddresses.length == 0 && !_vm.addMode + ? _c("p", { staticClass: "mb0" }, [ + _c("a", { staticClass: "pointer", on: { click: _vm.toggleAdd } }, [ + _vm._v(_vm._s(_vm.trans("app.add"))) + ]) + ]) + : _vm._e(), + _vm._v(" "), + _vm.contactAddresses.length > 0 + ? _c( + "ul", + [ + _vm._l(_vm.contactAddresses, function(contactAddress) { + return _c("li", { staticClass: "mb2" }, [ + _c( + "div", + { + directives: [ + { + name: "show", + rawName: "v-show", + value: !contactAddress.edit, + expression: "!contactAddress.edit" + } + ], + staticClass: "w-100 dt" + }, + [ + _c("div", { staticClass: "dtc" }, [ + _c("i", { + staticClass: "f6 light-silver fa fa-globe pr2" + }), + _vm._v(" "), + !_vm.editMode + ? _c( + "a", + { + attrs: { + href: contactAddress.googleMapAddress, + target: "_blank" + } + }, + [_vm._v(_vm._s(contactAddress.address))] + ) + : _vm._e(), + _vm._v(" "), + _vm.editMode + ? _c("span", [_vm._v(_vm._s(contactAddress.address))]) + : _vm._e(), + _vm._v(" "), + _c("span", { staticClass: "light-silver" }, [ + _vm._v("(" + _vm._s(contactAddress.name) + ")") + ]), + _vm._v(" "), + _vm.editMode + ? _c("div", { staticClass: "fr" }, [ + _c("i", { + staticClass: + "fa fa-pencil-square-o pointer pr2", + on: { + click: function($event) { + _vm.toggleEdit(contactAddress) + } + } + }), + _vm._v(" "), + _c("i", { + staticClass: "fa fa-trash-o pointer", + on: { + click: function($event) { + _vm.trash(contactAddress) + } + } + }) + ]) + : _vm._e() + ]) + ] + ), + _vm._v(" "), + _c( + "div", + { + directives: [ + { + name: "show", + rawName: "v-show", + value: contactAddress.edit, + expression: "contactAddress.edit" + } + ], + staticClass: "w-100" + }, + [ + _c("form", { staticClass: "measure center" }, [ + _c("div", { staticClass: "mt3" }, [ + _c("label", { staticClass: "db fw6 lh-copy f6" }, [ + _vm._v( + "\n " + + _vm._s( + _vm.trans("people.contact_address_form_name") + ) + + "\n " + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.updateForm.name, + expression: "updateForm.name" + } + ], + staticClass: "pa2 db w-100", + attrs: { type: "text" }, + domProps: { value: _vm.updateForm.name }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set( + _vm.updateForm, + "name", + $event.target.value + ) + } + } + }) + ]), + _vm._v(" "), + _c("div", { staticClass: "mt3" }, [ + _c("label", { staticClass: "db fw6 lh-copy f6" }, [ + _vm._v( + "\n " + + _vm._s( + _vm.trans( + "people.contact_address_form_street" + ) + ) + + "\n " + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.updateForm.street, + expression: "updateForm.street" + } + ], + staticClass: "pa2 db w-100", + attrs: { type: "text" }, + domProps: { value: _vm.updateForm.street }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set( + _vm.updateForm, + "street", + $event.target.value + ) + } + } + }) + ]), + _vm._v(" "), + _c("div", { staticClass: "mt3" }, [ + _c("label", { staticClass: "db fw6 lh-copy f6" }, [ + _vm._v( + "\n " + + _vm._s( + _vm.trans("people.contact_address_form_city") + ) + + "\n " + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.updateForm.city, + expression: "updateForm.city" + } + ], + staticClass: "pa2 db w-100", + attrs: { type: "text" }, + domProps: { value: _vm.updateForm.city }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set( + _vm.updateForm, + "city", + $event.target.value + ) + } + } + }) + ]), + _vm._v(" "), + _c("div", { staticClass: "mt3" }, [ + _c("label", { staticClass: "db fw6 lh-copy f6" }, [ + _vm._v( + "\n " + + _vm._s( + _vm.trans( + "people.contact_address_form_province" + ) + ) + + "\n " + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.updateForm.province, + expression: "updateForm.province" + } + ], + staticClass: "pa2 db w-100", + attrs: { type: "text" }, + domProps: { value: _vm.updateForm.province }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set( + _vm.updateForm, + "province", + $event.target.value + ) + } + } + }) + ]), + _vm._v(" "), + _c("div", { staticClass: "mt3" }, [ + _c("label", { staticClass: "db fw6 lh-copy f6" }, [ + _vm._v( + "\n " + + _vm._s( + _vm.trans( + "people.contact_address_form_postal_code" + ) + ) + + "\n " + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.updateForm.postal_code, + expression: "updateForm.postal_code" + } + ], + staticClass: "pa2 db w-100", + attrs: { type: "text" }, + domProps: { value: _vm.updateForm.postal_code }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set( + _vm.updateForm, + "postal_code", + $event.target.value + ) + } + } + }) + ]), + _vm._v(" "), + _c("div", { staticClass: "mt3" }, [ + _c("label", { staticClass: "db fw6 lh-copy f6" }, [ + _vm._v( + "\n " + + _vm._s( + _vm.trans( + "people.contact_address_form_country" + ) + ) + + "\n " + ) + ]), + _vm._v(" "), + _c( + "select", + { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.updateForm.country_id, + expression: "updateForm.country_id" + } + ], + staticClass: "db w-100 h2", + on: { + change: function($event) { + var $$selectedVal = Array.prototype.filter + .call($event.target.options, function(o) { + return o.selected + }) + .map(function(o) { + var val = + "_value" in o ? o._value : o.value + return val + }) + _vm.$set( + _vm.updateForm, + "country_id", + $event.target.multiple + ? $$selectedVal + : $$selectedVal[0] + ) + } + } + }, + _vm._l(_vm.countries, function(country) { + return _c( + "option", + { domProps: { value: country.id } }, + [ + _vm._v( + "\n " + + _vm._s(country.country) + + "\n " + ) + ] + ) + }) + ) + ]), + _vm._v(" "), + _c("div", { staticClass: "lh-copy mt3" }, [ + _c( + "a", + { + staticClass: "btn btn-primary", + on: { + click: function($event) { + $event.preventDefault() + _vm.update(contactAddress) + } + } + }, + [_vm._v(_vm._s(_vm.trans("app.add")))] + ), + _vm._v(" "), + _c( + "a", + { + staticClass: "btn", + on: { + click: function($event) { + _vm.toggleEdit(contactAddress) + } + } + }, + [_vm._v(_vm._s(_vm.trans("app.cancel")))] + ) + ]) + ]) + ] + ) + ]) + }), + _vm._v(" "), + _vm.editMode && !_vm.addMode + ? _c("li", [ + _c( + "a", + { staticClass: "pointer", on: { click: _vm.toggleAdd } }, + [_vm._v(_vm._s(_vm.trans("app.add")))] + ) + ]) + : _vm._e() + ], + 2 + ) + : _vm._e(), + _vm._v(" "), + _vm.addMode + ? _c("div", [ + _c("form", { staticClass: "measure center" }, [ + _c("div", { staticClass: "mt3" }, [ + _c("label", { staticClass: "db fw6 lh-copy f6" }, [ + _vm._v( + "\n " + + _vm._s(_vm.trans("people.contact_address_form_name")) + + "\n " + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.createForm.name, + expression: "createForm.name" + } + ], + staticClass: "pa2 db w-100", + attrs: { type: "text" }, + domProps: { value: _vm.createForm.name }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set(_vm.createForm, "name", $event.target.value) + } + } + }) + ]), + _vm._v(" "), + _c("div", { staticClass: "mt3" }, [ + _c("label", { staticClass: "db fw6 lh-copy f6" }, [ + _vm._v( + "\n " + + _vm._s(_vm.trans("people.contact_address_form_street")) + + "\n " + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.createForm.street, + expression: "createForm.street" + } + ], + staticClass: "pa2 db w-100", + attrs: { type: "text" }, + domProps: { value: _vm.createForm.street }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set(_vm.createForm, "street", $event.target.value) + } + } + }) + ]), + _vm._v(" "), + _c("div", { staticClass: "mt3" }, [ + _c("label", { staticClass: "db fw6 lh-copy f6" }, [ + _vm._v( + "\n " + + _vm._s(_vm.trans("people.contact_address_form_city")) + + "\n " + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.createForm.city, + expression: "createForm.city" + } + ], + staticClass: "pa2 db w-100", + attrs: { type: "text" }, + domProps: { value: _vm.createForm.city }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set(_vm.createForm, "city", $event.target.value) + } + } + }) + ]), + _vm._v(" "), + _c("div", { staticClass: "mt3" }, [ + _c("label", { staticClass: "db fw6 lh-copy f6" }, [ + _vm._v( + "\n " + + _vm._s( + _vm.trans("people.contact_address_form_province") + ) + + "\n " + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.createForm.province, + expression: "createForm.province" + } + ], + staticClass: "pa2 db w-100", + attrs: { type: "text" }, + domProps: { value: _vm.createForm.province }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set(_vm.createForm, "province", $event.target.value) + } + } + }) + ]), + _vm._v(" "), + _c("div", { staticClass: "mt3" }, [ + _c("label", { staticClass: "db fw6 lh-copy f6" }, [ + _vm._v( + "\n " + + _vm._s( + _vm.trans("people.contact_address_form_postal_code") + ) + + "\n " + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.createForm.postal_code, + expression: "createForm.postal_code" + } + ], + staticClass: "pa2 db w-100", + attrs: { type: "text" }, + domProps: { value: _vm.createForm.postal_code }, + on: { + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set( + _vm.createForm, + "postal_code", + $event.target.value + ) + } + } + }) + ]), + _vm._v(" "), + _c("div", { staticClass: "mt3" }, [ + _c("label", { staticClass: "db fw6 lh-copy f6" }, [ + _vm._v( + "\n " + + _vm._s(_vm.trans("people.contact_address_form_country")) + + "\n " + ) + ]), + _vm._v(" "), + _c( + "select", + { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.createForm.country_id, + expression: "createForm.country_id" + } + ], + staticClass: "db w-100 h2", + on: { + change: function($event) { + var $$selectedVal = Array.prototype.filter + .call($event.target.options, function(o) { + return o.selected + }) + .map(function(o) { + var val = "_value" in o ? o._value : o.value + return val + }) + _vm.$set( + _vm.createForm, + "country_id", + $event.target.multiple + ? $$selectedVal + : $$selectedVal[0] + ) + } + } + }, + [ + _c("option", { attrs: { value: "0" } }), + _vm._v(" "), + _vm._l(_vm.countries, function(country) { + return _c("option", { domProps: { value: country.id } }, [ + _vm._v( + "\n " + + _vm._s(country.country) + + "\n " + ) + ]) + }) + ], + 2 + ) + ]), + _vm._v(" "), + _c("div", { staticClass: "lh-copy mt3" }, [ + _c( + "a", + { + staticClass: "btn btn-primary", + on: { + click: function($event) { + $event.preventDefault() + _vm.store($event) + } + } + }, + [_vm._v(_vm._s(_vm.trans("app.add")))] + ), + _vm._v(" "), + _c( + "a", + { + staticClass: "btn", + on: { + click: function($event) { + _vm.addMode = false + } + } + }, + [_vm._v(_vm._s(_vm.trans("app.cancel")))] + ) + ]) + ]) + ]) + : _vm._e() + ] + ) +} +var staticRenderFns = [] +render._withStripped = true +module.exports = { render: render, staticRenderFns: staticRenderFns } +if (false) { + module.hot.accept() + if (module.hot.data) { + require("vue-hot-reload-api") .rerender("data-v-4666559e", module.exports) + } +} + +/***/ }), + +/***/ "./node_modules/vue-loader/lib/template-compiler/index.js?{\"id\":\"data-v-553e50c2\",\"hasScoped\":true,\"buble\":{\"transforms\":{}}}!./node_modules/vue-loader/lib/selector.js?type=template&index=0&bustCache!./resources/assets/js/components/settings/ContactFieldTypes.vue": +/***/ (function(module, exports, __webpack_require__) { + +var render = function() { + var _vm = this + var _h = _vm.$createElement + var _c = _vm._self._c || _h + return _c("div", [ + _c("h3", { staticClass: "with-actions" }, [ + _vm._v( + "\n " + + _vm._s( + _vm.trans("settings.personalization_contact_field_type_title") + ) + + "\n " + ), + _c("a", { staticClass: "btn fr nt2", on: { click: _vm.add } }, [ + _vm._v( + _vm._s(_vm.trans("settings.personalization_contact_field_type_add")) + ) + ]) + ]), + _vm._v(" "), + _c("p", [ + _vm._v( + _vm._s( + _vm.trans("settings.personalization_contact_field_type_description") + ) + ) + ]), + _vm._v(" "), + _vm.submitted + ? _c( + "div", + { staticClass: "pa2 ba b--yellow mb3 mt3 br2 bg-washed-yellow" }, + [ + _vm._v( + "\n " + + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_add_success" + ) + ) + + "\n " + ) + ] + ) + : _vm._e(), + _vm._v(" "), + _vm.edited + ? _c( + "div", + { staticClass: "pa2 ba b--yellow mb3 mt3 br2 bg-washed-yellow" }, + [ + _vm._v( + "\n " + + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_edit_success" + ) + ) + + "\n " + ) + ] + ) + : _vm._e(), + _vm._v(" "), + _vm.deleted + ? _c( + "div", + { staticClass: "pa2 ba b--yellow mb3 mt3 br2 bg-washed-yellow" }, + [ + _vm._v( + "\n " + + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_delete_success" + ) + ) + + "\n " + ) + ] + ) + : _vm._e(), + _vm._v(" "), + _c( + "div", + { staticClass: "dt dt--fixed w-100 collapse br--top br--bottom" }, + [ + _c("div", { staticClass: "dt-row" }, [ + _c("div", { staticClass: "dtc" }, [ + _c("div", { staticClass: "pa2 b" }, [ + _vm._v( + "\n " + + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_table_name" + ) + ) + + "\n " + ) + ]) + ]), + _vm._v(" "), + _c("div", { staticClass: "dtc" }, [ + _c("div", { staticClass: "pa2 b" }, [ + _vm._v( + "\n " + + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_table_protocol" + ) + ) + + "\n " + ) + ]) + ]), + _vm._v(" "), + _c("div", { staticClass: "dtc tr" }, [ + _c("div", { staticClass: "pa2 b" }, [ + _vm._v( + "\n " + + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_table_actions" + ) + ) + + "\n " + ) + ]) + ]) + ]), + _vm._v(" "), + _vm._l(_vm.contactFieldTypes, function(contactFieldType) { + return _c("div", { staticClass: "dt-row bb b--light-gray" }, [ + _c("div", { staticClass: "dtc" }, [ + _c("div", { staticClass: "pa2" }, [ + contactFieldType.fontawesome_icon + ? _c("i", { + staticClass: "pr2", + class: contactFieldType.fontawesome_icon + }) + : _vm._e(), + _vm._v(" "), + !contactFieldType.fontawesome_icon + ? _c("i", { staticClass: "pr2 fa fa-address-card-o" }) + : _vm._e(), + _vm._v( + "\n " + _vm._s(contactFieldType.name) + "\n " + ) + ]) + ]), + _vm._v(" "), + _c("div", { staticClass: "dtc" }, [ + _c("code", { staticClass: "f7" }, [ + _vm._v( + "\n " + + _vm._s(contactFieldType.protocol) + + "\n " + ) + ]) + ]), + _vm._v(" "), + _c("div", { staticClass: "dtc tr" }, [ + _c("div", { staticClass: "pa2" }, [ + _c("i", { + staticClass: "fa fa-pencil-square-o pointer pr2", + on: { + click: function($event) { + _vm.edit(contactFieldType) + } + } + }), + _vm._v(" "), + contactFieldType.delible + ? _c("i", { + staticClass: "fa fa-trash-o pointer", + on: { + click: function($event) { + _vm.showDelete(contactFieldType) + } + } + }) + : _vm._e() + ]) + ]) + ]) + }) + ], + 2 + ), + _vm._v(" "), + _c( + "div", + { + staticClass: "modal", + attrs: { id: "modal-create-contact-field-type", tabindex: "-1" } + }, + [ + _c("div", { staticClass: "modal-dialog" }, [ + _c("div", { staticClass: "modal-content" }, [ + _c("div", { staticClass: "modal-header" }, [ + _c("h5", { staticClass: "modal-title" }, [ + _vm._v( + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_modal_title" + ) + ) + ) + ]), + _vm._v(" "), + _vm._m(0) + ]), + _vm._v(" "), + _c("div", { staticClass: "modal-body" }, [ + _vm.createForm.errors.length > 0 + ? _c("div", { staticClass: "alert alert-danger" }, [ + _c("p", [_vm._v(_vm._s(_vm.trans("app.error_title")))]), + _vm._v(" "), + _c("br"), + _vm._v(" "), + _c( + "ul", + _vm._l(_vm.createForm.errors, function(error) { + return _c("li", [ + _vm._v( + "\n " + + _vm._s(error) + + "\n " + ) + ]) + }) + ) + ]) + : _vm._e(), + _vm._v(" "), + _c( + "form", + { + staticClass: "form-horizontal", + attrs: { role: "form" }, + on: { + submit: function($event) { + $event.preventDefault() + _vm.store($event) + } + } + }, + [ + _c("div", { staticClass: "form-group" }, [ + _c("div", { staticClass: "form-group" }, [ + _c("label", { attrs: { for: "name" } }, [ + _vm._v( + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_modal_name" + ) + ) + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.createForm.name, + expression: "createForm.name" + } + ], + staticClass: "form-control", + attrs: { + type: "text", + name: "name", + id: "name", + required: "" + }, + domProps: { value: _vm.createForm.name }, + on: { + keyup: function($event) { + if ( + !("button" in $event) && + _vm._k($event.keyCode, "enter", 13, $event.key) + ) { + return null + } + _vm.store($event) + }, + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set( + _vm.createForm, + "name", + $event.target.value + ) + } + } + }) + ]), + _vm._v(" "), + _c("div", { staticClass: "form-group" }, [ + _c("label", { attrs: { for: "protocol" } }, [ + _vm._v( + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_modal_protocol" + ) + ) + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.createForm.protocol, + expression: "createForm.protocol" + } + ], + staticClass: "form-control", + attrs: { + type: "text", + name: "protocol", + id: "protocol", + placeholder: "mailto:" + }, + domProps: { value: _vm.createForm.protocol }, + on: { + keyup: function($event) { + if ( + !("button" in $event) && + _vm._k($event.keyCode, "enter", 13, $event.key) + ) { + return null + } + _vm.store($event) + }, + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set( + _vm.createForm, + "protocol", + $event.target.value + ) + } + } + }), + _vm._v(" "), + _c("small", { staticClass: "form-text text-muted" }, [ + _vm._v( + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_modal_protocol_help" + ) + ) + ) + ]) + ]), + _vm._v(" "), + _c("div", { staticClass: "form-group" }, [ + _c("label", { attrs: { for: "icon" } }, [ + _vm._v( + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_modal_icon" + ) + ) + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.createForm.icon, + expression: "createForm.icon" + } + ], + staticClass: "form-control", + attrs: { + type: "text", + name: "icon", + id: "icon", + placeholder: "fa fa-address-book-o" + }, + domProps: { value: _vm.createForm.icon }, + on: { + keyup: function($event) { + if ( + !("button" in $event) && + _vm._k($event.keyCode, "enter", 13, $event.key) + ) { + return null + } + _vm.store($event) + }, + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set( + _vm.createForm, + "icon", + $event.target.value + ) + } + } + }), + _vm._v(" "), + _c("small", { staticClass: "form-text text-muted" }, [ + _vm._v( + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_modal_icon_help" + ) + ) + ) + ]) + ]) + ]) + ] + ) + ]), + _vm._v(" "), + _c("div", { staticClass: "modal-footer" }, [ + _c( + "button", + { + staticClass: "btn btn-secondary", + attrs: { type: "button", "data-dismiss": "modal" } + }, + [_vm._v(_vm._s(_vm.trans("app.cancel")))] + ), + _vm._v(" "), + _c( + "button", + { + staticClass: "btn btn-primary", + attrs: { type: "button" }, + on: { + click: function($event) { + $event.preventDefault() + _vm.store($event) + } + } + }, + [_vm._v(_vm._s(_vm.trans("app.save")))] + ) + ]) + ]) + ]) + ] + ), + _vm._v(" "), + _c( + "div", + { + staticClass: "modal", + attrs: { id: "modal-edit-contact-field-type", tabindex: "-1" } + }, + [ + _c("div", { staticClass: "modal-dialog" }, [ + _c("div", { staticClass: "modal-content" }, [ + _c("div", { staticClass: "modal-header" }, [ + _c("h5", { staticClass: "modal-title" }, [ + _vm._v( + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_modal_edit_title" + ) + ) + ) + ]), + _vm._v(" "), + _vm._m(1) + ]), + _vm._v(" "), + _c("div", { staticClass: "modal-body" }, [ + _vm.editForm.errors.length > 0 + ? _c("div", { staticClass: "alert alert-danger" }, [ + _c("p", [_vm._v(_vm._s(_vm.trans("app.error_title")))]), + _vm._v(" "), + _c("br"), + _vm._v(" "), + _c( + "ul", + _vm._l(_vm.editForm.errors, function(error) { + return _c("li", [ + _vm._v( + "\n " + + _vm._s(error[1]) + + "\n " + ) + ]) + }) + ) + ]) + : _vm._e(), + _vm._v(" "), + _c( + "form", + { + staticClass: "form-horizontal", + attrs: { role: "form" }, + on: { + submit: function($event) { + $event.preventDefault() + _vm.update($event) + } + } + }, + [ + _c("div", { staticClass: "form-group" }, [ + _c("div", { staticClass: "form-group" }, [ + _c("label", { attrs: { for: "name" } }, [ + _vm._v( + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_modal_name" + ) + ) + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.editForm.name, + expression: "editForm.name" + } + ], + staticClass: "form-control", + attrs: { + type: "text", + name: "name", + id: "name", + required: "" + }, + domProps: { value: _vm.editForm.name }, + on: { + keyup: function($event) { + if ( + !("button" in $event) && + _vm._k($event.keyCode, "enter", 13, $event.key) + ) { + return null + } + _vm.update($event) + }, + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set(_vm.editForm, "name", $event.target.value) + } + } + }) + ]), + _vm._v(" "), + _c("div", { staticClass: "form-group" }, [ + _c("label", { attrs: { for: "protocol" } }, [ + _vm._v( + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_modal_protocol" + ) + ) + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.editForm.protocol, + expression: "editForm.protocol" + } + ], + staticClass: "form-control", + attrs: { + type: "text", + name: "protocol", + id: "protocol", + placeholder: "mailto:" + }, + domProps: { value: _vm.editForm.protocol }, + on: { + keyup: function($event) { + if ( + !("button" in $event) && + _vm._k($event.keyCode, "enter", 13, $event.key) + ) { + return null + } + _vm.update($event) + }, + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set( + _vm.editForm, + "protocol", + $event.target.value + ) + } + } + }), + _vm._v(" "), + _c("small", { staticClass: "form-text text-muted" }, [ + _vm._v( + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_modal_protocol_help" + ) + ) + ) + ]) + ]), + _vm._v(" "), + _c("div", { staticClass: "form-group" }, [ + _c("label", { attrs: { for: "icon" } }, [ + _vm._v( + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_modal_icon" + ) + ) + ) + ]), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "model", + rawName: "v-model", + value: _vm.editForm.icon, + expression: "editForm.icon" + } + ], + staticClass: "form-control", + attrs: { + type: "text", + name: "icon", + id: "icon", + placeholder: "fa fa-address-book-o" + }, + domProps: { value: _vm.editForm.icon }, + on: { + keyup: function($event) { + if ( + !("button" in $event) && + _vm._k($event.keyCode, "enter", 13, $event.key) + ) { + return null + } + _vm.update($event) + }, + input: function($event) { + if ($event.target.composing) { + return + } + _vm.$set(_vm.editForm, "icon", $event.target.value) + } + } + }), + _vm._v(" "), + _c("small", { staticClass: "form-text text-muted" }, [ + _vm._v( + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_modal_icon_help" + ) + ) + ) + ]) + ]) + ]) + ] + ) + ]), + _vm._v(" "), + _c("div", { staticClass: "modal-footer" }, [ + _c( + "button", + { + staticClass: "btn btn-secondary", + attrs: { type: "button", "data-dismiss": "modal" } + }, + [_vm._v(_vm._s(_vm.trans("app.cancel")))] + ), + _vm._v(" "), + _c( + "button", + { + staticClass: "btn btn-primary", + attrs: { type: "button" }, + on: { + click: function($event) { + $event.preventDefault() + _vm.update($event) + } + } + }, + [_vm._v(_vm._s(_vm.trans("app.edit")))] + ) + ]) + ]) + ]) + ] + ), + _vm._v(" "), + _c( + "div", + { + staticClass: "modal", + attrs: { id: "modal-delete-contact-field-type", tabindex: "-1" } + }, + [ + _c("div", { staticClass: "modal-dialog" }, [ + _c("div", { staticClass: "modal-content" }, [ + _c("div", { staticClass: "modal-header" }, [ + _c("h5", { staticClass: "modal-title" }, [ + _vm._v( + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_modal_delete_title" + ) + ) + ) + ]), + _vm._v(" "), + _vm._m(2) + ]), + _vm._v(" "), + _c("div", { staticClass: "modal-body" }, [ + _c("p", [ + _vm._v( + _vm._s( + _vm.trans( + "settings.personalization_contact_field_type_modal_delete_description" + ) + ) + ) + ]) + ]), + _vm._v(" "), + _c("div", { staticClass: "modal-footer" }, [ + _c( + "button", + { + staticClass: "btn btn-secondary", + attrs: { type: "button", "data-dismiss": "modal" } + }, + [_vm._v(_vm._s(_vm.trans("app.cancel")))] + ), + _vm._v(" "), + _c( + "button", + { + staticClass: "btn btn-danger", + attrs: { type: "button" }, + on: { + click: function($event) { + $event.preventDefault() + _vm.trash($event) + } + } + }, + [_vm._v(_vm._s(_vm.trans("app.delete")))] + ) + ]) + ]) + ]) + ] + ) + ]) +} +var staticRenderFns = [ + function() { + var _vm = this + var _h = _vm.$createElement + var _c = _vm._self._c || _h + return _c( + "button", + { + staticClass: "close", + attrs: { type: "button", "data-dismiss": "modal" } + }, + [_c("span", { attrs: { "aria-hidden": "true" } }, [_vm._v("×")])] + ) + }, + function() { + var _vm = this + var _h = _vm.$createElement + var _c = _vm._self._c || _h + return _c( + "button", + { + staticClass: "close", + attrs: { type: "button", "data-dismiss": "modal" } + }, + [_c("span", { attrs: { "aria-hidden": "true" } }, [_vm._v("×")])] + ) + }, + function() { + var _vm = this + var _h = _vm.$createElement + var _c = _vm._self._c || _h + return _c( + "button", + { + staticClass: "close", + attrs: { type: "button", "data-dismiss": "modal" } + }, + [_c("span", { attrs: { "aria-hidden": "true" } }, [_vm._v("×")])] + ) + } +] +render._withStripped = true +module.exports = { render: render, staticRenderFns: staticRenderFns } +if (false) { + module.hot.accept() + if (module.hot.data) { + require("vue-hot-reload-api") .rerender("data-v-553e50c2", module.exports) + } +} + +/***/ }), + /***/ "./node_modules/vue-loader/lib/template-compiler/index.js?{\"id\":\"data-v-e79f7702\",\"hasScoped\":true,\"buble\":{\"transforms\":{}}}!./node_modules/vue-loader/lib/selector.js?type=template&index=0&bustCache!./resources/assets/js/components/passport/AuthorizedClients.vue": /***/ (function(module, exports, __webpack_require__) { @@ -33675,6 +36527,1612 @@ if (false) { /***/ }), +/***/ "./node_modules/vue-resource/dist/vue-resource.es2015.js": +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Url", function() { return Url; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Http", function() { return Http; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Resource", function() { return Resource; }); +/*! + * vue-resource v1.3.4 + * https://github.com/pagekit/vue-resource + * Released under the MIT License. + */ + +/** + * Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis) + */ + +var RESOLVED = 0; +var REJECTED = 1; +var PENDING = 2; + +function Promise$1(executor) { + + this.state = PENDING; + this.value = undefined; + this.deferred = []; + + var promise = this; + + try { + executor(function (x) { + promise.resolve(x); + }, function (r) { + promise.reject(r); + }); + } catch (e) { + promise.reject(e); + } +} + +Promise$1.reject = function (r) { + return new Promise$1(function (resolve, reject) { + reject(r); + }); +}; + +Promise$1.resolve = function (x) { + return new Promise$1(function (resolve, reject) { + resolve(x); + }); +}; + +Promise$1.all = function all(iterable) { + return new Promise$1(function (resolve, reject) { + var count = 0, result = []; + + if (iterable.length === 0) { + resolve(result); + } + + function resolver(i) { + return function (x) { + result[i] = x; + count += 1; + + if (count === iterable.length) { + resolve(result); + } + }; + } + + for (var i = 0; i < iterable.length; i += 1) { + Promise$1.resolve(iterable[i]).then(resolver(i), reject); + } + }); +}; + +Promise$1.race = function race(iterable) { + return new Promise$1(function (resolve, reject) { + for (var i = 0; i < iterable.length; i += 1) { + Promise$1.resolve(iterable[i]).then(resolve, reject); + } + }); +}; + +var p$1 = Promise$1.prototype; + +p$1.resolve = function resolve(x) { + var promise = this; + + if (promise.state === PENDING) { + if (x === promise) { + throw new TypeError('Promise settled with itself.'); + } + + var called = false; + + try { + var then = x && x['then']; + + if (x !== null && typeof x === 'object' && typeof then === 'function') { + then.call(x, function (x) { + if (!called) { + promise.resolve(x); + } + called = true; + + }, function (r) { + if (!called) { + promise.reject(r); + } + called = true; + }); + return; + } + } catch (e) { + if (!called) { + promise.reject(e); + } + return; + } + + promise.state = RESOLVED; + promise.value = x; + promise.notify(); + } +}; + +p$1.reject = function reject(reason) { + var promise = this; + + if (promise.state === PENDING) { + if (reason === promise) { + throw new TypeError('Promise settled with itself.'); + } + + promise.state = REJECTED; + promise.value = reason; + promise.notify(); + } +}; + +p$1.notify = function notify() { + var promise = this; + + nextTick(function () { + if (promise.state !== PENDING) { + while (promise.deferred.length) { + var deferred = promise.deferred.shift(), + onResolved = deferred[0], + onRejected = deferred[1], + resolve = deferred[2], + reject = deferred[3]; + + try { + if (promise.state === RESOLVED) { + if (typeof onResolved === 'function') { + resolve(onResolved.call(undefined, promise.value)); + } else { + resolve(promise.value); + } + } else if (promise.state === REJECTED) { + if (typeof onRejected === 'function') { + resolve(onRejected.call(undefined, promise.value)); + } else { + reject(promise.value); + } + } + } catch (e) { + reject(e); + } + } + } + }); +}; + +p$1.then = function then(onResolved, onRejected) { + var promise = this; + + return new Promise$1(function (resolve, reject) { + promise.deferred.push([onResolved, onRejected, resolve, reject]); + promise.notify(); + }); +}; + +p$1.catch = function (onRejected) { + return this.then(undefined, onRejected); +}; + +/** + * Promise adapter. + */ + +if (typeof Promise === 'undefined') { + window.Promise = Promise$1; +} + +function PromiseObj(executor, context) { + + if (executor instanceof Promise) { + this.promise = executor; + } else { + this.promise = new Promise(executor.bind(context)); + } + + this.context = context; +} + +PromiseObj.all = function (iterable, context) { + return new PromiseObj(Promise.all(iterable), context); +}; + +PromiseObj.resolve = function (value, context) { + return new PromiseObj(Promise.resolve(value), context); +}; + +PromiseObj.reject = function (reason, context) { + return new PromiseObj(Promise.reject(reason), context); +}; + +PromiseObj.race = function (iterable, context) { + return new PromiseObj(Promise.race(iterable), context); +}; + +var p = PromiseObj.prototype; + +p.bind = function (context) { + this.context = context; + return this; +}; + +p.then = function (fulfilled, rejected) { + + if (fulfilled && fulfilled.bind && this.context) { + fulfilled = fulfilled.bind(this.context); + } + + if (rejected && rejected.bind && this.context) { + rejected = rejected.bind(this.context); + } + + return new PromiseObj(this.promise.then(fulfilled, rejected), this.context); +}; + +p.catch = function (rejected) { + + if (rejected && rejected.bind && this.context) { + rejected = rejected.bind(this.context); + } + + return new PromiseObj(this.promise.catch(rejected), this.context); +}; + +p.finally = function (callback) { + + return this.then(function (value) { + callback.call(this); + return value; + }, function (reason) { + callback.call(this); + return Promise.reject(reason); + } + ); +}; + +/** + * Utility functions. + */ + +var ref = {}; +var hasOwnProperty = ref.hasOwnProperty; + +var ref$1 = []; +var slice = ref$1.slice; +var debug = false; +var ntick; + +var inBrowser = typeof window !== 'undefined'; + +var Util = function (ref) { + var config = ref.config; + var nextTick = ref.nextTick; + + ntick = nextTick; + debug = config.debug || !config.silent; +}; + +function warn(msg) { + if (typeof console !== 'undefined' && debug) { + console.warn('[VueResource warn]: ' + msg); + } +} + +function error(msg) { + if (typeof console !== 'undefined') { + console.error(msg); + } +} + +function nextTick(cb, ctx) { + return ntick(cb, ctx); +} + +function trim(str) { + return str ? str.replace(/^\s*|\s*$/g, '') : ''; +} + +function trimEnd(str, chars) { + + if (str && chars === undefined) { + return str.replace(/\s+$/, ''); + } + + if (!str || !chars) { + return str; + } + + return str.replace(new RegExp(("[" + chars + "]+$")), ''); +} + +function toLower(str) { + return str ? str.toLowerCase() : ''; +} + +function toUpper(str) { + return str ? str.toUpperCase() : ''; +} + +var isArray = Array.isArray; + +function isString(val) { + return typeof val === 'string'; +} + + + +function isFunction(val) { + return typeof val === 'function'; +} + +function isObject(obj) { + return obj !== null && typeof obj === 'object'; +} + +function isPlainObject(obj) { + return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; +} + +function isBlob(obj) { + return typeof Blob !== 'undefined' && obj instanceof Blob; +} + +function isFormData(obj) { + return typeof FormData !== 'undefined' && obj instanceof FormData; +} + +function when(value, fulfilled, rejected) { + + var promise = PromiseObj.resolve(value); + + if (arguments.length < 2) { + return promise; + } + + return promise.then(fulfilled, rejected); +} + +function options(fn, obj, opts) { + + opts = opts || {}; + + if (isFunction(opts)) { + opts = opts.call(obj); + } + + return merge(fn.bind({$vm: obj, $options: opts}), fn, {$options: opts}); +} + +function each(obj, iterator) { + + var i, key; + + if (isArray(obj)) { + for (i = 0; i < obj.length; i++) { + iterator.call(obj[i], obj[i], i); + } + } else if (isObject(obj)) { + for (key in obj) { + if (hasOwnProperty.call(obj, key)) { + iterator.call(obj[key], obj[key], key); + } + } + } + + return obj; +} + +var assign = Object.assign || _assign; + +function merge(target) { + + var args = slice.call(arguments, 1); + + args.forEach(function (source) { + _merge(target, source, true); + }); + + return target; +} + +function defaults(target) { + + var args = slice.call(arguments, 1); + + args.forEach(function (source) { + + for (var key in source) { + if (target[key] === undefined) { + target[key] = source[key]; + } + } + + }); + + return target; +} + +function _assign(target) { + + var args = slice.call(arguments, 1); + + args.forEach(function (source) { + _merge(target, source); + }); + + return target; +} + +function _merge(target, source, deep) { + for (var key in source) { + if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { + if (isPlainObject(source[key]) && !isPlainObject(target[key])) { + target[key] = {}; + } + if (isArray(source[key]) && !isArray(target[key])) { + target[key] = []; + } + _merge(target[key], source[key], deep); + } else if (source[key] !== undefined) { + target[key] = source[key]; + } + } +} + +/** + * Root Prefix Transform. + */ + +var root = function (options$$1, next) { + + var url = next(options$$1); + + if (isString(options$$1.root) && !/^(https?:)?\//.test(url)) { + url = trimEnd(options$$1.root, '/') + '/' + url; + } + + return url; +}; + +/** + * Query Parameter Transform. + */ + +var query = function (options$$1, next) { + + var urlParams = Object.keys(Url.options.params), query = {}, url = next(options$$1); + + each(options$$1.params, function (value, key) { + if (urlParams.indexOf(key) === -1) { + query[key] = value; + } + }); + + query = Url.params(query); + + if (query) { + url += (url.indexOf('?') == -1 ? '?' : '&') + query; + } + + return url; +}; + +/** + * URL Template v2.0.6 (https://github.com/bramstein/url-template) + */ + +function expand(url, params, variables) { + + var tmpl = parse(url), expanded = tmpl.expand(params); + + if (variables) { + variables.push.apply(variables, tmpl.vars); + } + + return expanded; +} + +function parse(template) { + + var operators = ['+', '#', '.', '/', ';', '?', '&'], variables = []; + + return { + vars: variables, + expand: function expand(context) { + return template.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g, function (_, expression, literal) { + if (expression) { + + var operator = null, values = []; + + if (operators.indexOf(expression.charAt(0)) !== -1) { + operator = expression.charAt(0); + expression = expression.substr(1); + } + + expression.split(/,/g).forEach(function (variable) { + var tmp = /([^:\*]*)(?::(\d+)|(\*))?/.exec(variable); + values.push.apply(values, getValues(context, operator, tmp[1], tmp[2] || tmp[3])); + variables.push(tmp[1]); + }); + + if (operator && operator !== '+') { + + var separator = ','; + + if (operator === '?') { + separator = '&'; + } else if (operator !== '#') { + separator = operator; + } + + return (values.length !== 0 ? operator : '') + values.join(separator); + } else { + return values.join(','); + } + + } else { + return encodeReserved(literal); + } + }); + } + }; +} + +function getValues(context, operator, key, modifier) { + + var value = context[key], result = []; + + if (isDefined(value) && value !== '') { + if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { + value = value.toString(); + + if (modifier && modifier !== '*') { + value = value.substring(0, parseInt(modifier, 10)); + } + + result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : null)); + } else { + if (modifier === '*') { + if (Array.isArray(value)) { + value.filter(isDefined).forEach(function (value) { + result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : null)); + }); + } else { + Object.keys(value).forEach(function (k) { + if (isDefined(value[k])) { + result.push(encodeValue(operator, value[k], k)); + } + }); + } + } else { + var tmp = []; + + if (Array.isArray(value)) { + value.filter(isDefined).forEach(function (value) { + tmp.push(encodeValue(operator, value)); + }); + } else { + Object.keys(value).forEach(function (k) { + if (isDefined(value[k])) { + tmp.push(encodeURIComponent(k)); + tmp.push(encodeValue(operator, value[k].toString())); + } + }); + } + + if (isKeyOperator(operator)) { + result.push(encodeURIComponent(key) + '=' + tmp.join(',')); + } else if (tmp.length !== 0) { + result.push(tmp.join(',')); + } + } + } + } else { + if (operator === ';') { + result.push(encodeURIComponent(key)); + } else if (value === '' && (operator === '&' || operator === '?')) { + result.push(encodeURIComponent(key) + '='); + } else if (value === '') { + result.push(''); + } + } + + return result; +} + +function isDefined(value) { + return value !== undefined && value !== null; +} + +function isKeyOperator(operator) { + return operator === ';' || operator === '&' || operator === '?'; +} + +function encodeValue(operator, value, key) { + + value = (operator === '+' || operator === '#') ? encodeReserved(value) : encodeURIComponent(value); + + if (key) { + return encodeURIComponent(key) + '=' + value; + } else { + return value; + } +} + +function encodeReserved(str) { + return str.split(/(%[0-9A-Fa-f]{2})/g).map(function (part) { + if (!/%[0-9A-Fa-f]/.test(part)) { + part = encodeURI(part); + } + return part; + }).join(''); +} + +/** + * URL Template (RFC 6570) Transform. + */ + +var template = function (options) { + + var variables = [], url = expand(options.url, options.params, variables); + + variables.forEach(function (key) { + delete options.params[key]; + }); + + return url; +}; + +/** + * Service for URL templating. + */ + +function Url(url, params) { + + var self = this || {}, options$$1 = url, transform; + + if (isString(url)) { + options$$1 = {url: url, params: params}; + } + + options$$1 = merge({}, Url.options, self.$options, options$$1); + + Url.transforms.forEach(function (handler) { + + if (isString(handler)) { + handler = Url.transform[handler]; + } + + if (isFunction(handler)) { + transform = factory(handler, transform, self.$vm); + } + + }); + + return transform(options$$1); +} + +/** + * Url options. + */ + +Url.options = { + url: '', + root: null, + params: {} +}; + +/** + * Url transforms. + */ + +Url.transform = {template: template, query: query, root: root}; +Url.transforms = ['template', 'query', 'root']; + +/** + * Encodes a Url parameter string. + * + * @param {Object} obj + */ + +Url.params = function (obj) { + + var params = [], escape = encodeURIComponent; + + params.add = function (key, value) { + + if (isFunction(value)) { + value = value(); + } + + if (value === null) { + value = ''; + } + + this.push(escape(key) + '=' + escape(value)); + }; + + serialize(params, obj); + + return params.join('&').replace(/%20/g, '+'); +}; + +/** + * Parse a URL and return its components. + * + * @param {String} url + */ + +Url.parse = function (url) { + + var el = document.createElement('a'); + + if (document.documentMode) { + el.href = url; + url = el.href; + } + + el.href = url; + + return { + href: el.href, + protocol: el.protocol ? el.protocol.replace(/:$/, '') : '', + port: el.port, + host: el.host, + hostname: el.hostname, + pathname: el.pathname.charAt(0) === '/' ? el.pathname : '/' + el.pathname, + search: el.search ? el.search.replace(/^\?/, '') : '', + hash: el.hash ? el.hash.replace(/^#/, '') : '' + }; +}; + +function factory(handler, next, vm) { + return function (options$$1) { + return handler.call(vm, options$$1, next); + }; +} + +function serialize(params, obj, scope) { + + var array = isArray(obj), plain = isPlainObject(obj), hash; + + each(obj, function (value, key) { + + hash = isObject(value) || isArray(value); + + if (scope) { + key = scope + '[' + (plain || hash ? key : '') + ']'; + } + + if (!scope && array) { + params.add(value.name, value.value); + } else if (hash) { + serialize(params, value, key); + } else { + params.add(key, value); + } + }); +} + +/** + * XDomain client (Internet Explorer). + */ + +var xdrClient = function (request) { + return new PromiseObj(function (resolve) { + + var xdr = new XDomainRequest(), handler = function (ref) { + var type = ref.type; + + + var status = 0; + + if (type === 'load') { + status = 200; + } else if (type === 'error') { + status = 500; + } + + resolve(request.respondWith(xdr.responseText, {status: status})); + }; + + request.abort = function () { return xdr.abort(); }; + + xdr.open(request.method, request.getUrl()); + + if (request.timeout) { + xdr.timeout = request.timeout; + } + + xdr.onload = handler; + xdr.onabort = handler; + xdr.onerror = handler; + xdr.ontimeout = handler; + xdr.onprogress = function () {}; + xdr.send(request.getBody()); + }); +}; + +/** + * CORS Interceptor. + */ + +var SUPPORTS_CORS = inBrowser && 'withCredentials' in new XMLHttpRequest(); + +var cors = function (request, next) { + + if (inBrowser) { + + var orgUrl = Url.parse(location.href); + var reqUrl = Url.parse(request.getUrl()); + + if (reqUrl.protocol !== orgUrl.protocol || reqUrl.host !== orgUrl.host) { + + request.crossOrigin = true; + request.emulateHTTP = false; + + if (!SUPPORTS_CORS) { + request.client = xdrClient; + } + } + } + + next(); +}; + +/** + * Form data Interceptor. + */ + +var form = function (request, next) { + + if (isFormData(request.body)) { + + request.headers.delete('Content-Type'); + + } else if (isObject(request.body) && request.emulateJSON) { + + request.body = Url.params(request.body); + request.headers.set('Content-Type', 'application/x-www-form-urlencoded'); + } + + next(); +}; + +/** + * JSON Interceptor. + */ + +var json = function (request, next) { + + var type = request.headers.get('Content-Type') || ''; + + if (isObject(request.body) && type.indexOf('application/json') === 0) { + request.body = JSON.stringify(request.body); + } + + next(function (response) { + + return response.bodyText ? when(response.text(), function (text) { + + type = response.headers.get('Content-Type') || ''; + + if (type.indexOf('application/json') === 0 || isJson(text)) { + + try { + response.body = JSON.parse(text); + } catch (e) { + response.body = null; + } + + } else { + response.body = text; + } + + return response; + + }) : response; + + }); +}; + +function isJson(str) { + + var start = str.match(/^\[|^\{(?!\{)/), end = {'[': /]$/, '{': /}$/}; + + return start && end[start[0]].test(str); +} + +/** + * JSONP client (Browser). + */ + +var jsonpClient = function (request) { + return new PromiseObj(function (resolve) { + + var name = request.jsonp || 'callback', callback = request.jsonpCallback || '_jsonp' + Math.random().toString(36).substr(2), body = null, handler, script; + + handler = function (ref) { + var type = ref.type; + + + var status = 0; + + if (type === 'load' && body !== null) { + status = 200; + } else if (type === 'error') { + status = 500; + } + + if (status && window[callback]) { + delete window[callback]; + document.body.removeChild(script); + } + + resolve(request.respondWith(body, {status: status})); + }; + + window[callback] = function (result) { + body = JSON.stringify(result); + }; + + request.abort = function () { + handler({type: 'abort'}); + }; + + request.params[name] = callback; + + if (request.timeout) { + setTimeout(request.abort, request.timeout); + } + + script = document.createElement('script'); + script.src = request.getUrl(); + script.type = 'text/javascript'; + script.async = true; + script.onload = handler; + script.onerror = handler; + + document.body.appendChild(script); + }); +}; + +/** + * JSONP Interceptor. + */ + +var jsonp = function (request, next) { + + if (request.method == 'JSONP') { + request.client = jsonpClient; + } + + next(); +}; + +/** + * Before Interceptor. + */ + +var before = function (request, next) { + + if (isFunction(request.before)) { + request.before.call(this, request); + } + + next(); +}; + +/** + * HTTP method override Interceptor. + */ + +var method = function (request, next) { + + if (request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(request.method)) { + request.headers.set('X-HTTP-Method-Override', request.method); + request.method = 'POST'; + } + + next(); +}; + +/** + * Header Interceptor. + */ + +var header = function (request, next) { + + var headers = assign({}, Http.headers.common, + !request.crossOrigin ? Http.headers.custom : {}, + Http.headers[toLower(request.method)] + ); + + each(headers, function (value, name) { + if (!request.headers.has(name)) { + request.headers.set(name, value); + } + }); + + next(); +}; + +/** + * XMLHttp client (Browser). + */ + +var xhrClient = function (request) { + return new PromiseObj(function (resolve) { + + var xhr = new XMLHttpRequest(), handler = function (event) { + + var response = request.respondWith( + 'response' in xhr ? xhr.response : xhr.responseText, { + status: xhr.status === 1223 ? 204 : xhr.status, // IE9 status bug + statusText: xhr.status === 1223 ? 'No Content' : trim(xhr.statusText) + } + ); + + each(trim(xhr.getAllResponseHeaders()).split('\n'), function (row) { + response.headers.append(row.slice(0, row.indexOf(':')), row.slice(row.indexOf(':') + 1)); + }); + + resolve(response); + }; + + request.abort = function () { return xhr.abort(); }; + + if (request.progress) { + if (request.method === 'GET') { + xhr.addEventListener('progress', request.progress); + } else if (/^(POST|PUT)$/i.test(request.method)) { + xhr.upload.addEventListener('progress', request.progress); + } + } + + xhr.open(request.method, request.getUrl(), true); + + if (request.timeout) { + xhr.timeout = request.timeout; + } + + if (request.responseType && 'responseType' in xhr) { + xhr.responseType = request.responseType; + } + + if (request.withCredentials || request.credentials) { + xhr.withCredentials = true; + } + + if (!request.crossOrigin) { + request.headers.set('X-Requested-With', 'XMLHttpRequest'); + } + + request.headers.forEach(function (value, name) { + xhr.setRequestHeader(name, value); + }); + + xhr.onload = handler; + xhr.onabort = handler; + xhr.onerror = handler; + xhr.ontimeout = handler; + xhr.send(request.getBody()); + }); +}; + +/** + * Http client (Node). + */ + +var nodeClient = function (request) { + + var client = __webpack_require__(1); + + return new PromiseObj(function (resolve) { + + var url = request.getUrl(); + var body = request.getBody(); + var method = request.method; + var headers = {}, handler; + + request.headers.forEach(function (value, name) { + headers[name] = value; + }); + + client(url, {body: body, method: method, headers: headers}).then(handler = function (resp) { + + var response = request.respondWith(resp.body, { + status: resp.statusCode, + statusText: trim(resp.statusMessage) + } + ); + + each(resp.headers, function (value, name) { + response.headers.set(name, value); + }); + + resolve(response); + + }, function (error$$1) { return handler(error$$1.response); }); + }); +}; + +/** + * Base client. + */ + +var Client = function (context) { + + var reqHandlers = [sendRequest], resHandlers = [], handler; + + if (!isObject(context)) { + context = null; + } + + function Client(request) { + return new PromiseObj(function (resolve, reject) { + + function exec() { + + handler = reqHandlers.pop(); + + if (isFunction(handler)) { + handler.call(context, request, next); + } else { + warn(("Invalid interceptor of type " + (typeof handler) + ", must be a function")); + next(); + } + } + + function next(response) { + + if (isFunction(response)) { + + resHandlers.unshift(response); + + } else if (isObject(response)) { + + resHandlers.forEach(function (handler) { + response = when(response, function (response) { + return handler.call(context, response) || response; + }, reject); + }); + + when(response, resolve, reject); + + return; + } + + exec(); + } + + exec(); + + }, context); + } + + Client.use = function (handler) { + reqHandlers.push(handler); + }; + + return Client; +}; + +function sendRequest(request, resolve) { + + var client = request.client || (inBrowser ? xhrClient : nodeClient); + + resolve(client(request)); +} + +/** + * HTTP Headers. + */ + +var Headers = function Headers(headers) { + var this$1 = this; + + + this.map = {}; + + each(headers, function (value, name) { return this$1.append(name, value); }); +}; + +Headers.prototype.has = function has (name) { + return getName(this.map, name) !== null; +}; + +Headers.prototype.get = function get (name) { + + var list = this.map[getName(this.map, name)]; + + return list ? list.join() : null; +}; + +Headers.prototype.getAll = function getAll (name) { + return this.map[getName(this.map, name)] || []; +}; + +Headers.prototype.set = function set (name, value) { + this.map[normalizeName(getName(this.map, name) || name)] = [trim(value)]; +}; + +Headers.prototype.append = function append (name, value){ + + var list = this.map[getName(this.map, name)]; + + if (list) { + list.push(trim(value)); + } else { + this.set(name, value); + } +}; + +Headers.prototype.delete = function delete$1 (name){ + delete this.map[getName(this.map, name)]; +}; + +Headers.prototype.deleteAll = function deleteAll (){ + this.map = {}; +}; + +Headers.prototype.forEach = function forEach (callback, thisArg) { + var this$1 = this; + + each(this.map, function (list, name) { + each(list, function (value) { return callback.call(thisArg, value, name, this$1); }); + }); +}; + +function getName(map, name) { + return Object.keys(map).reduce(function (prev, curr) { + return toLower(name) === toLower(curr) ? curr : prev; + }, null); +} + +function normalizeName(name) { + + if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { + throw new TypeError('Invalid character in header field name'); + } + + return trim(name); +} + +/** + * HTTP Response. + */ + +var Response = function Response(body, ref) { + var url = ref.url; + var headers = ref.headers; + var status = ref.status; + var statusText = ref.statusText; + + + this.url = url; + this.ok = status >= 200 && status < 300; + this.status = status || 0; + this.statusText = statusText || ''; + this.headers = new Headers(headers); + this.body = body; + + if (isString(body)) { + + this.bodyText = body; + + } else if (isBlob(body)) { + + this.bodyBlob = body; + + if (isBlobText(body)) { + this.bodyText = blobText(body); + } + } +}; + +Response.prototype.blob = function blob () { + return when(this.bodyBlob); +}; + +Response.prototype.text = function text () { + return when(this.bodyText); +}; + +Response.prototype.json = function json () { + return when(this.text(), function (text) { return JSON.parse(text); }); +}; + +Object.defineProperty(Response.prototype, 'data', { + + get: function get() { + return this.body; + }, + + set: function set(body) { + this.body = body; + } + +}); + +function blobText(body) { + return new PromiseObj(function (resolve) { + + var reader = new FileReader(); + + reader.readAsText(body); + reader.onload = function () { + resolve(reader.result); + }; + + }); +} + +function isBlobText(body) { + return body.type.indexOf('text') === 0 || body.type.indexOf('json') !== -1; +} + +/** + * HTTP Request. + */ + +var Request = function Request(options$$1) { + + this.body = null; + this.params = {}; + + assign(this, options$$1, { + method: toUpper(options$$1.method || 'GET') + }); + + if (!(this.headers instanceof Headers)) { + this.headers = new Headers(this.headers); + } +}; + +Request.prototype.getUrl = function getUrl (){ + return Url(this); +}; + +Request.prototype.getBody = function getBody (){ + return this.body; +}; + +Request.prototype.respondWith = function respondWith (body, options$$1) { + return new Response(body, assign(options$$1 || {}, {url: this.getUrl()})); +}; + +/** + * Service for sending network requests. + */ + +var COMMON_HEADERS = {'Accept': 'application/json, text/plain, */*'}; +var JSON_CONTENT_TYPE = {'Content-Type': 'application/json;charset=utf-8'}; + +function Http(options$$1) { + + var self = this || {}, client = Client(self.$vm); + + defaults(options$$1 || {}, self.$options, Http.options); + + Http.interceptors.forEach(function (handler) { + + if (isString(handler)) { + handler = Http.interceptor[handler]; + } + + if (isFunction(handler)) { + client.use(handler); + } + + }); + + return client(new Request(options$$1)).then(function (response) { + + return response.ok ? response : PromiseObj.reject(response); + + }, function (response) { + + if (response instanceof Error) { + error(response); + } + + return PromiseObj.reject(response); + }); +} + +Http.options = {}; + +Http.headers = { + put: JSON_CONTENT_TYPE, + post: JSON_CONTENT_TYPE, + patch: JSON_CONTENT_TYPE, + delete: JSON_CONTENT_TYPE, + common: COMMON_HEADERS, + custom: {} +}; + +Http.interceptor = {before: before, method: method, jsonp: jsonp, json: json, form: form, header: header, cors: cors}; +Http.interceptors = ['before', 'method', 'jsonp', 'json', 'form', 'header', 'cors']; + +['get', 'delete', 'head', 'jsonp'].forEach(function (method$$1) { + + Http[method$$1] = function (url, options$$1) { + return this(assign(options$$1 || {}, {url: url, method: method$$1})); + }; + +}); + +['post', 'put', 'patch'].forEach(function (method$$1) { + + Http[method$$1] = function (url, body, options$$1) { + return this(assign(options$$1 || {}, {url: url, method: method$$1, body: body})); + }; + +}); + +/** + * Service for interacting with RESTful services. + */ + +function Resource(url, params, actions, options$$1) { + + var self = this || {}, resource = {}; + + actions = assign({}, + Resource.actions, + actions + ); + + each(actions, function (action, name) { + + action = merge({url: url, params: assign({}, params)}, options$$1, action); + + resource[name] = function () { + return (self.$http || Http)(opts(action, arguments)); + }; + }); + + return resource; +} + +function opts(action, args) { + + var options$$1 = assign({}, action), params = {}, body; + + switch (args.length) { + + case 2: + + params = args[0]; + body = args[1]; + + break; + + case 1: + + if (/^(POST|PUT|PATCH)$/i.test(options$$1.method)) { + body = args[0]; + } else { + params = args[0]; + } + + break; + + case 0: + + break; + + default: + + throw 'Expected up to 2 arguments [params, body], got ' + args.length + ' arguments'; + } + + options$$1.body = body; + options$$1.params = assign({}, options$$1.params, params); + + return options$$1; +} + +Resource.actions = { + + get: {method: 'GET'}, + save: {method: 'POST'}, + query: {method: 'GET'}, + update: {method: 'PUT'}, + remove: {method: 'DELETE'}, + delete: {method: 'DELETE'} + +}; + +/** + * Install plugin. + */ + +function plugin(Vue) { + + if (plugin.installed) { + return; + } + + Util(Vue); + + Vue.url = Url; + Vue.http = Http; + Vue.resource = Resource; + Vue.Promise = PromiseObj; + + Object.defineProperties(Vue.prototype, { + + $url: { + get: function get() { + return options(Vue.url, this, this.$options.url); + } + }, + + $http: { + get: function get() { + return options(Vue.http, this, this.$options.http); + } + }, + + $resource: { + get: function get() { + return Vue.resource.bind(this); + } + }, + + $promise: { + get: function get() { + var this$1 = this; + + return function (executor) { return new Vue.Promise(executor, this$1); }; + } + } + + }); +} + +if (typeof window !== 'undefined' && window.Vue) { + window.Vue.use(plugin); +} + +/* harmony default export */ __webpack_exports__["default"] = (plugin); + + + +/***/ }), + +/***/ "./node_modules/vue-style-loader/index.js!./node_modules/css-loader/index.js?sourceMap!./node_modules/vue-loader/lib/style-compiler/index.js?{\"vue\":true,\"id\":\"data-v-06458126\",\"scoped\":true,\"hasInlineConfig\":true}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0&bustCache!./resources/assets/js/components/people/ContactInformation.vue": +/***/ (function(module, exports, __webpack_require__) { + +// style-loader: Adds some css to the DOM by adding a + + + + diff --git a/resources/assets/js/components/people/ContactInformation.vue b/resources/assets/js/components/people/ContactInformation.vue new file mode 100644 index 000000000..2b8adb85f --- /dev/null +++ b/resources/assets/js/components/people/ContactInformation.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/resources/assets/js/components/settings/ContactFieldTypes.vue b/resources/assets/js/components/settings/ContactFieldTypes.vue new file mode 100644 index 000000000..3fe27bcb4 --- /dev/null +++ b/resources/assets/js/components/settings/ContactFieldTypes.vue @@ -0,0 +1,327 @@ + + + + + diff --git a/resources/assets/js/contacts.js b/resources/assets/js/contacts.js index 2fc84536c..6c19948e5 100644 --- a/resources/assets/js/contacts.js +++ b/resources/assets/js/contacts.js @@ -49,4 +49,4 @@ $('#markPersonDeceased').click(function() { $('#checkboxDatePersonDeceased').click(function() { $('#reminderDeceased').toggle(this.checked); $('#datesSelector').toggle(this.checked); -}); \ No newline at end of file +}); diff --git a/resources/lang/cz/people.php b/resources/lang/cz/people.php index d3495d0b8..7dc58ffcb 100644 --- a/resources/lang/cz/people.php +++ b/resources/lang/cz/people.php @@ -40,7 +40,7 @@ return [ 'people_add_import' => 'Chcete importovat své kontakty?', // show - 'section_personal_information' => 'Osobní informace', + 'section_contact_information' => 'Contact information', 'section_personal_activities' => 'Aktivity', 'section_personal_reminders' => 'Upozornění', 'section_personal_tasks' => 'Úkoly', diff --git a/resources/lang/de/people.php b/resources/lang/de/people.php index 40e02a78f..e018d3f27 100644 --- a/resources/lang/de/people.php +++ b/resources/lang/de/people.php @@ -40,7 +40,7 @@ return [ 'people_add_import' => 'Möchtest du Kontakte importieren?', // show - 'section_personal_information' => 'Persönliche Informationen', + 'section_contact_information' => 'Contact information', 'section_personal_activities' => 'Aktivitäten', 'section_personal_reminders' => 'Erinnerungen', 'section_personal_tasks' => 'Aufgaben', diff --git a/resources/lang/en/app.php b/resources/lang/en/app.php index 7de736d9a..d1fd62c64 100644 --- a/resources/lang/en/app.php +++ b/resources/lang/en/app.php @@ -10,6 +10,7 @@ return [ 'upload' => 'Upload', 'close' => 'Close', 'remove' => 'Remove', + 'done' => 'Done', 'markdown_description' => 'Want to format your text in a nice way? We support Markdown to add bold, italic, lists and more.', 'markdown_link' => 'Read documentation', @@ -55,8 +56,12 @@ return [ 'breadcrumb_edit_note' => 'Edit a note', 'breadcrumb_api' => 'API', 'breadcrumb_edit_introductions' => 'How did you meet', + 'breadcrumb_settings_personalization' => 'Personalization', 'gender_male' => 'Man', 'gender_female' => 'Woman', 'gender_none' => 'Rather not say', + + 'error_title' => 'Whoops! Something went wrong.', + 'error_unauthorized' => 'You don\'t have the right to edit this resource.', ]; diff --git a/resources/lang/en/people.php b/resources/lang/en/people.php index 3a1cbd44b..61b4bcb8c 100644 --- a/resources/lang/en/people.php +++ b/resources/lang/en/people.php @@ -3,7 +3,7 @@ return [ //index - 'people_list_number_kids' => '{0} 0 kids|{1,1} 1 kid|{2,*} :count kids', + 'people_list_number_kids' => '{0} 0 kid|{1,1} 1 kid|{2,*} :count kids', 'people_list_last_updated' => 'Last consulted:', 'people_list_number_reminders' => '{0} 0 reminders|{1,1} 1 reminder|{2, *} :count reminders', 'people_list_blank_title' => 'You don\'t have anyone in your account yet', @@ -41,7 +41,7 @@ return [ 'people_edit_email_error' => 'There is already a contact in your account with this email address. Please choose another one.', // show - 'section_personal_information' => 'Personal information', + 'section_contact_information' => 'Contact information', 'section_personal_activities' => 'Activities', 'section_personal_reminders' => 'Reminders', 'section_personal_tasks' => 'Tasks', @@ -349,4 +349,25 @@ return [ 'deceased_add_reminder' => 'Add a reminder for this date', 'deceased_label' => 'Deceased', 'deceased_label_with_date' => 'Deceased on :date', + + // Contact information + 'contact_info_title' => 'Contact information', + 'contact_info_form_content' => 'Content', + 'contact_info_form_contact_type' => 'Contact type', + 'contact_info_form_personalize' => 'Personalize', + 'contact_info_address' => 'Lives in', + + // Addresses + 'contact_address_title' => 'Addresses', + 'contact_address_form_name' => 'Label (optional)', + 'contact_address_form_street' => 'Street (optional)', + 'contact_address_form_city' => 'City (optional)', + 'contact_address_form_province' => 'Province (optional)', + 'contact_address_form_postal_code' => 'Postal code (optional)', + 'contact_address_form_country' => 'Country (optional)', + 'contact_address_form_' => '', + 'contact_address_form_' => '', + 'contact_address_form_' => '', + 'contact_address_form_' => '', + 'contact_address_form_' => '', ]; diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index 72c42d85d..94e3dc759 100644 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -2,6 +2,7 @@ return [ 'sidebar_settings' => 'Account settings', + 'sidebar_personalization' => 'Personalization', 'sidebar_settings_export' => 'Export data', 'sidebar_settings_users' => 'Users', 'sidebar_settings_subscriptions' => 'Subscription', @@ -146,4 +147,24 @@ return [ 'api_authorized_clients' => 'List of authorized clients', 'api_authorized_clients_desc' => 'This section lists all the clients you\'ve authorized to access your application. You can revoke this authorization at anytime.', + 'personalization_title' => 'Here you can find different settings to configure your account. These features are more for "power users" who want maximum control over Monica.', + 'personalization_contact_field_type_title' => 'Contact field types', + 'personalization_contact_field_type_add' => 'Add new field type', + 'personalization_contact_field_type_description' => 'Here you can configure all the different types of contact fields that you can associate to all your contacts. If in the future, a new social network appears, you will be able to add this new type of ways of contacting your contacts right here.', + 'personalization_contact_field_type_table_name' => 'Name', + 'personalization_contact_field_type_table_protocol' => 'Protocol', + 'personalization_contact_field_type_table_actions' => 'Actions', + 'personalization_contact_field_type_modal_title' => 'Add a new contact field type', + 'personalization_contact_field_type_modal_edit_title' => 'Edit an existing contact field type', + 'personalization_contact_field_type_modal_delete_title' => 'Delete an existing contact field type', + 'personalization_contact_field_type_modal_delete_description' => 'Are you sure you want to delete this contact field type? Deleting this type of contact field will delete ALL the data with this type for all your contacts.', + 'personalization_contact_field_type_modal_name' => 'Name', + 'personalization_contact_field_type_modal_protocol' => 'Protocol (optional)', + 'personalization_contact_field_type_modal_protocol_help' => 'Each new contact field type can be clickable. If a protocol is set, we will use it to trigger the action that is set.', + 'personalization_contact_field_type_modal_icon' => 'Icon (optional)', + 'personalization_contact_field_type_modal_icon_help' => 'You can associate an icon with this contact field type. You need to add a reference to a Font Awesome icon.', + 'personalization_contact_field_type_delete_success' => 'The contact field type has been deleted with success.', + 'personalization_contact_field_type_add_success' => 'The contact field type has been successfully added.', + 'personalization_contact_field_type_edit_success' => 'The contact field type has been successfully updated.', + ]; diff --git a/resources/lang/fr/people.php b/resources/lang/fr/people.php index 7025591b7..eed904801 100644 --- a/resources/lang/fr/people.php +++ b/resources/lang/fr/people.php @@ -40,7 +40,7 @@ return [ 'people_add_import' => 'Do you want to import your contacts?', // show - 'section_personal_information' => 'Informations personnelles', + 'section_contact_information' => 'Contact information', 'section_personal_activities' => 'Activités', 'section_personal_reminders' => 'Rappels', 'section_personal_tasks' => 'Tâches', diff --git a/resources/lang/it/people.php b/resources/lang/it/people.php index 8d609ca72..3e4087d0d 100644 --- a/resources/lang/it/people.php +++ b/resources/lang/it/people.php @@ -40,7 +40,7 @@ return [ 'people_add_import' => 'Vuoi importare i tuoi contatti?', // show - 'section_personal_information' => 'Informazioni personali', + 'section_contact_information' => 'Contact information', 'section_personal_activities' => 'Attività', 'section_personal_reminders' => 'Promemoria', 'section_personal_tasks' => 'Cose da fare', diff --git a/resources/lang/pt-br/people.php b/resources/lang/pt-br/people.php index f70f5c141..0deb4cfad 100644 --- a/resources/lang/pt-br/people.php +++ b/resources/lang/pt-br/people.php @@ -40,7 +40,7 @@ return [ 'people_add_import' => 'Do you want to import your contacts?', // show - 'section_personal_information' => 'Informação pessoal', + 'section_contact_information' => 'Contact information', 'section_personal_activities' => 'Atividades', 'section_personal_reminders' => 'Lembretes', 'section_personal_tasks' => 'Tarefas', diff --git a/resources/lang/ru/people.php b/resources/lang/ru/people.php index 7bdc8f8bd..2e63bb14c 100644 --- a/resources/lang/ru/people.php +++ b/resources/lang/ru/people.php @@ -40,7 +40,7 @@ return [ 'people_add_import' => 'Вы хотите импортировать ваши контакты?', // show - 'section_personal_information' => 'Личные данные', + 'section_contact_information' => 'Contact information', 'section_personal_activities' => 'Активности', 'section_personal_reminders' => 'Напоминания', 'section_personal_tasks' => 'Задачи', diff --git a/resources/views/dashboard/index.blade.php b/resources/views/dashboard/index.blade.php index db0b1bc6e..6b78eb82c 100644 --- a/resources/views/dashboard/index.blade.php +++ b/resources/views/dashboard/index.blade.php @@ -1,15 +1,5 @@ @extends('layouts.skeleton') -{{-- Temp Fix for Bootstrap Tabs: Issue #26 --}} -@push('scripts') - -@endpush - @section('content')
diff --git a/resources/views/layouts/skeleton.blade.php b/resources/views/layouts/skeleton.blade.php index e0f002bac..1890c7518 100644 --- a/resources/views/layouts/skeleton.blade.php +++ b/resources/views/layouts/skeleton.blade.php @@ -14,6 +14,18 @@ 'csrfToken' => csrf_token(), ]); ?> + user()->account_id }}> diff --git a/resources/views/partials/components/country-select.blade.php b/resources/views/partials/components/country-select.blade.php deleted file mode 100644 index 73fcc0c7e..000000000 --- a/resources/views/partials/components/country-select.blade.php +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/resources/views/people/_header.blade.php b/resources/views/people/_header.blade.php index 86a0ae384..31d5e800a 100644 --- a/resources/views/people/_header.blade.php +++ b/resources/views/people/_header.blade.php @@ -27,6 +27,9 @@

{{ $contact->getCompleteName(auth()->user()->name_order) }} + @if (! is_null($contact->birthdate)) + ( {{ $contact->getAge() }}) + @endif