Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add contact archiving #1769

Merged
merged 29 commits into from Oct 27, 2018
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
12e9b12
Add is_active column
asbiin Sep 2, 2018
68972b2
Add contact archiving
asbiin Sep 2, 2018
f95864b
Apply fixes from StyleCI
asbiin Sep 2, 2018
8c476a2
Merge remote-tracking branch 'origin/master' into feat/contact-archiving
asbiin Sep 5, 2018
cf274a2
Update makefile
asbiin Sep 5, 2018
8a6a068
Update changelog
asbiin Sep 5, 2018
5b0b7e6
Move button elsewhere
asbiin Sep 5, 2018
c1f676f
Fix message
asbiin Sep 10, 2018
2efc834
chore(assets): Update assets
MonicaBot Sep 10, 2018
ef65a4d
Merge remote-tracking branch 'origin/master' into feat/contact-archiving
asbiin Sep 10, 2018
7b6f5b0
Merge branch 'feat/contact-archiving' of github.com:monicahq/monica i…
asbiin Sep 10, 2018
781dc8e
chore(assets): Update assets
MonicaBot Sep 10, 2018
f51fb33
Merge remote-tracking branch 'origin/master' into feat/contact-archiving
asbiin Sep 21, 2018
7f85355
Merge remote-tracking branch 'origin/master' into feat/contact-archiving
asbiin Sep 23, 2018
0a24bb0
update
asbiin Sep 23, 2018
2c0ab3b
Merge remote-tracking branch 'origin/master' into feat/contact-archiving
asbiin Sep 30, 2018
fdbf4bc
Add links to archived contacts
asbiin Oct 1, 2018
93866bf
chore(assets): Update assets
MonicaBot Oct 1, 2018
6058b3e
Merge remote-tracking branch 'origin/master' into feat/contact-archiving
asbiin Oct 11, 2018
df94b44
Merge remote-tracking branch 'origin/master' into feat/contact-archiving
asbiin Oct 13, 2018
32b258b
Merge remote-tracking branch 'origin/master' into feat/contact-archiving
asbiin Oct 19, 2018
6991d67
Add changelog notification
asbiin Oct 19, 2018
6d52b0b
Apply fixes from StyleCI
asbiin Oct 19, 2018
af7337b
fix
asbiin Oct 19, 2018
6d8d58b
Merge branch 'master' into feat/contact-archiving
asbiin Oct 25, 2018
ac1c984
Improve screens
djaiss Oct 27, 2018
f51e22b
remove useless button
djaiss Oct 27, 2018
4beed75
Fix sonar
djaiss Oct 27, 2018
898a4c6
Trying to fix this freaking sonar
djaiss Oct 27, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG
@@ -1,5 +1,6 @@
UNRELEASED CHANGES:

* Add ability to archive a contact
* Fix settings' sidebar links and change security icon
* Fix CSV import

Expand Down
6 changes: 5 additions & 1 deletion Makefile
Expand Up @@ -101,7 +101,11 @@ docker_push_bintray: .deploy.json

.PHONY: docker docker_build docker_tag docker_push docker_push_bintray

build: build-dev
build:
composer install --no-interaction --no-suggest --ignore-platform-reqs
php artisan lang:generate
yarn install
yarn run production

build-prod:
composer install --no-interaction --no-suggest --ignore-platform-reqs --no-dev
Expand Down
8 changes: 4 additions & 4 deletions app/Http/Controllers/Api/ApiContactController.php
Expand Up @@ -49,16 +49,16 @@ public function index(Request $request)
}

try {
$contacts = auth()->user()->account->contacts()->real()
$contacts = auth()->user()->account->contacts()
->real()
->active()
->orderBy($this->sort, $this->sortDirection)
->paginate($this->getLimitPerPage());
} catch (QueryException $e) {
return $this->respondInvalidQuery();
}

$collection = $this->applyWithParameter($contacts, $this->getWithParameter());

return $collection;
return $this->applyWithParameter($contacts, $this->getWithParameter());
}

/**
Expand Down
1 change: 1 addition & 0 deletions app/Http/Controllers/Contacts/RelationshipsController.php
Expand Up @@ -22,6 +22,7 @@ public function new(Request $request, Contact $contact)
// getting top 100 of existing contacts
$existingContacts = auth()->user()->account->contacts()
->real()
->active()
->select(['id', 'first_name', 'last_name'])
->sortedBy('name')
->take(100)
Expand Down
62 changes: 54 additions & 8 deletions app/Http/Controllers/ContactsController.php
Expand Up @@ -25,6 +25,28 @@ class ContactsController extends Controller
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
return $this->contacts($request, true);
}

/**
* Display a listing of the resource.
*
* @param Request $request
* @return \Illuminate\Http\Response
*/
public function archived(Request $request)
{
return $this->contacts($request, false);
}

/**
* Display contacts.
*
* @param Request $request
* @return \Illuminate\Http\Response
*/
private function contacts(Request $request, bool $active)
{
$user = $request->user();
$sort = $request->get('sort') ?? $user->contacts_sort_order;
Expand All @@ -37,10 +59,19 @@ public function index(Request $request)
$url = '';
$count = 1;

$contacts = $user->account->contacts()->real();
if ($active) {
$nbarchived = $contacts->count();
$contacts = $contacts->active();
$nbarchived = $nbarchived - $contacts->count();
} else {
$contacts = $contacts->notActive();
$nbarchived = $contacts->count();
}

if ($request->get('no_tag')) {
//get tag less contacts
$contacts = $user->account->contacts()->real()->sortedBy($sort);
$contacts = $contacts->tags('NONE')->get();
$contacts = $contacts->tags('NONE');
} elseif ($request->get('tag1')) {
// get contacts with selected tags

Expand All @@ -63,13 +94,9 @@ public function index(Request $request)
return redirect()->route('people.index');
}

$contacts = $user->account->contacts()->real()->sortedBy($sort);

$contacts = $contacts->tags($tags)->get();
} else {
// get all contacts
$contacts = $user->account->contacts()->real()->sortedBy($sort)->get();
$contacts = $contacts->tags($tags);
}
$contacts = $contacts->sortedBy($sort)->get();

// starred contacts
$starredContacts = $contacts->filter(function ($item) {
Expand All @@ -84,6 +111,8 @@ public function index(Request $request)
->withContacts($contacts->unique('id'))
->withUnstarredContacts($unstarredContacts)
->withStarredContacts($starredContacts)
->withActive($active)
->withHasArchived($nbarchived > 0)
->withTags($tags)
->withUserTags(auth()->user()->account->tags)
->withUrl($url)
Expand Down Expand Up @@ -562,4 +591,21 @@ public function favorite(Request $request, Contact $contact)
'is_starred' => $bool,
];
}

/**
* Toggle archive of a contact.
*
* @param Request $request
* @param Contact $contact
* @return array
*/
public function archive(Request $request, Contact $contact)
{
$contact->is_active = ! $contact->is_active;
$contact->save();

return [
'is_active' => $contact->is_active,
];
}
}
11 changes: 8 additions & 3 deletions app/Http/Controllers/DashboardController.php
Expand Up @@ -27,13 +27,18 @@ public function index()
)->with('debts.contact')
->first();

if ($account->contacts()->count() === 0) {
if ($account->contacts()->real()->active()->count() === 0) {
return view('dashboard.blank');
}

// Fetch last updated contacts
$lastUpdatedContactsCollection = collect([]);
$lastUpdatedContacts = $account->contacts()->where('is_partial', false)->latest('updated_at')->limit(10)->get();
$lastUpdatedContacts = $account->contacts()
->real()
->active()
->latest('updated_at')
->limit(10)
->get();
foreach ($lastUpdatedContacts as $contact) {
$data = [
'id' => $contact->hashID(),
Expand All @@ -60,7 +65,7 @@ public function index()

$data = [
'lastUpdatedContacts' => $lastUpdatedContactsCollection,
'number_of_contacts' => $account->contacts()->real()->count(),
'number_of_contacts' => $account->contacts()->real()->active()->count(),
'number_of_reminders' => $account->reminders_count,
'number_of_notes' => $account->notes_count,
'number_of_activities' => $account->activities_count,
Expand Down
1 change: 1 addition & 0 deletions app/Http/Resources/Contact/Contact.php
Expand Up @@ -27,6 +27,7 @@ public function toArray($request)
'gender' => $this->gender->name,
'is_starred' => (bool) $this->is_starred,
'is_partial' => (bool) $this->is_partial,
'is_active' => (bool) $this->is_active,
'is_dead' => (bool) $this->is_dead,
'last_called' => $this->when(! $this->is_partial, $this->getLastCalled()),
'last_activity_together' => $this->when(! $this->is_partial, $this->getLastActivityDate()),
Expand Down
1 change: 1 addition & 0 deletions app/Http/Resources/Contact/ContactWithContactFields.php
Expand Up @@ -26,6 +26,7 @@ public function toArray($request)
'gender' => $this->gender->name,
'is_starred' => (bool) $this->is_starred,
'is_partial' => (bool) $this->is_partial,
'is_active' => (bool) $this->is_active,
'is_dead' => (bool) $this->is_dead,
'last_called' => $this->when(! $this->is_partial, $this->getLastCalled()),
'last_activity_together' => $this->when(! $this->is_partial, $this->getLastActivityDate()),
Expand Down
23 changes: 23 additions & 0 deletions app/Models/Contact/Contact.php
Expand Up @@ -115,6 +115,7 @@ class Contact extends Model
'is_dead' => 'boolean',
'has_avatar' => 'boolean',
'is_starred' => 'boolean',
'is_active' => 'boolean',
];

/**
Expand Down Expand Up @@ -413,6 +414,28 @@ public function scopeReal($query)
return $query->where('is_partial', 0);
}

/**
* Scope a query to only include contacts who are active.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeActive($query)
{
return $query->where('is_active', 1);
}

/**
* Scope a query to only include contacts who are not active.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeNotActive($query)
{
return $query->where('is_active', 0);
}

/**
* Get the first name of the contact.
*
Expand Down
32 changes: 32 additions & 0 deletions database/migrations/2018_09_02_150531_contact_archiving.php
@@ -0,0 +1,32 @@
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class ContactArchiving extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('contacts', function (Blueprint $table) {
$table->boolean('is_active')->default(1)->after('is_partial');
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('contacts', function ($table) {
$table->dropColumn('is_active');
});
}
}
@@ -0,0 +1,31 @@
<?php

use App\Models\Instance\Instance;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Migrations\Migration;

class ChangelogAboutArchiving extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$description = '
**New feature: archiving contact**

You can now archive a contact to no longer see it in the Dashboard, or in the searchs. Archived contacts can still be found on the Contacts board.

![image](/img/changelogs/2018-10-19-archiving.png)';

$id = DB::table('changelogs')->insertGetId([
'description' => $description,
'created_at' => '2018-10-19',
]);

$instance = Instance::first();
$instance->addUnreadChangelogEntry($id);
}
}
2 changes: 1 addition & 1 deletion public/css/app-ltr.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion public/css/app-rtl.css

Large diffs are not rendered by default.

Binary file added public/img/changelogs/2018-10-19-archiving.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/js/app.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion public/js/langs/en.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions public/mix-manifest.json
@@ -1,7 +1,7 @@
{
"/js/app.js": "/js/app.js?id=06cf7d3943c971315cac",
"/css/app-ltr.css": "/css/app-ltr.css?id=aeed1bc1277811d4283c",
"/css/app-rtl.css": "/css/app-rtl.css?id=ebbe907f4e5cf0c8bd1a",
"/js/app.js": "/js/app.js?id=be1081f3aade4d748c86",
"/css/app-ltr.css": "/css/app-ltr.css?id=c31157ff6b8b03764087",
"/css/app-rtl.css": "/css/app-rtl.css?id=34ddbd8de0120976f96b",
"/css/stripe.css": "/css/stripe.css?id=64c68c04c4e475fcc7c6",
"/js/vendor.js": "/js/vendor.js?id=490bf428af4c7224b600",
"/js/stripe.js": "/js/stripe.js?id=e2284957ba723a52a4b7",
Expand Down
4 changes: 4 additions & 0 deletions resources/assets/js/app.js
Expand Up @@ -110,6 +110,10 @@ Vue.component(
'contact-favorite',
require('./components/people/SetFavorite.vue')
);
Vue.component(
'contact-archive',
require('./components/people/Archive.vue')
);

Vue.component(
'contact-address',
Expand Down
62 changes: 62 additions & 0 deletions resources/assets/js/components/people/Archive.vue
@@ -0,0 +1,62 @@
<style scoped>
</style>

<template>
<div>
<notifications group="archive" position="top middle" duration=5000 width="400" />

<a class="btn btn-special" @click="toggle" :title="$t('people.contact_archive_help')">{{ isActive ? $t('people.contact_archive') : $t('people.contact_unarchive') }}</a>
</div>
</template>

<script>
export default {
/*
* The component's data.
*/
data() {
return {
isActive: false,
};
},

/**
* Prepare the component (Vue 2.x).
*/
mounted() {
this.prepareComponent();
},

props: {
hash: {
type: String,
},
active: {
type: Boolean,
},
},

methods: {
/**
* Prepare the component.
*/
prepareComponent() {
this.isActive = this.active;
},

toggle() {
axios.put('/people/' + this.hash + '/archive')
.then(response => {
this.isActive = response.data.is_active

this.$notify({
group: 'archive',
title: this.$t('app.default_save_success'),
text: '',
type: 'success'
});
});
},
}
}
</script>
2 changes: 1 addition & 1 deletion resources/assets/js/components/people/SetFavorite.vue
Expand Up @@ -63,7 +63,7 @@
this.isFavorite = response.data.is_starred

this.$notify({
group: 'main',
group: 'favorite',
title: this.$t('app.default_save_success'),
text: '',
type: 'success'
Expand Down