diff --git a/src/api/__mocks__/reports.js b/src/api/__mocks__/reports.js
index e277d8df9be863e97e99087c20228c841a379f7e..ba4e412e5dd3464245801532e458936a21b36e13 100644
--- a/src/api/__mocks__/reports.js
+++ b/src/api/__mocks__/reports.js
@@ -11,18 +11,41 @@ const reports = [
   { created_at: '2019-05-18T13:01:33.000Z', account: { acct: 'nick', display_name: 'Nick Keys', tags: [] }, actor: { acct: 'admin' }, state: 'closed', id: '4', content: '', statuses: [] }
 ]
 
-export async function fetchReports(limit, max_id, authHost, token) {
-  const paginatedReports = max_id.length > 0 ? reports.slice(5) : reports.slice(0, 5)
-  return Promise.resolve({ data: { reports: paginatedReports }})
+const groupedReports = [
+  { account: { avatar: 'http://localhost:4000/images/avi.png', confirmation_pending: false, deactivated: false, display_name: 'leo', id: '9oG0YghgBi94EATI9I', local: true, nickname: 'leo', roles: { admin: false, moderator: false }, tags: [] },
+    actors: [{ acct: 'admin', avatar: 'http://localhost:4000/images/avi.png', deactivated: false, display_name: 'admin', id: '9oFz4pTauG0cnJ581w', local: true, nickname: 'admin', roles: { admin: false, moderator: false }, tags: [], url: 'http://localhost:4000/users/admin', username: 'admin' }],
+    date: '2019-11-23T12:56:11.969772Z',
+    reports: [
+      { created_at: '2019-05-21T21:35:33.000Z', account: { acct: 'benj', display_name: 'Benjamin Fame', tags: [] }, actor: { acct: 'admin' }, state: 'open', id: '2', content: 'This is a report', statuses: [] },
+      { created_at: '2019-05-20T22:45:33.000Z', account: { acct: 'alice', display_name: 'Alice Pool', tags: [] }, actor: { acct: 'admin2' }, state: 'resolved', id: '7', content: 'Please block this user', statuses: [
+        { account: { display_name: 'Alice Pool', avatar: '' }, visibility: 'public', sensitive: false, id: '11', content: 'Hey!', url: '', created_at: '2019-05-10T21:35:33.000Z' },
+        { account: { display_name: 'Alice Pool', avatar: '' }, visibility: 'unlisted', sensitive: true, id: '10', content: 'Bye!', url: '', created_at: '2019-05-10T21:00:33.000Z' }
+      ] }
+    ],
+    status: {
+      account: { acct: 'leo' },
+      content: 'At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis',
+      created_at: '2019-11-23T12:55:20.000Z',
+      id: '9pFoQO69piu7cUDnJg',
+      url: 'http://localhost:4000/notice/9pFoQO69piu7cUDnJg',
+      visibility: 'unlisted',
+      sensitive: true
+    },
+    status_deleted: false
+  }
+]
+
+export async function fetchReports(filter, page, pageSize, authHost, token) {
+  return filter.length > 0
+    ? Promise.resolve({ data: { reports: reports.filter(report => report.state === filter) }})
+    : Promise.resolve({ data: { reports }})
 }
 
-export async function filterReports(filter, limit, max_id, authHost, token) {
-  const filteredReports = reports.filter(report => report.state === filter)
-  const paginatedReports = max_id.length > 0 ? filteredReports.slice(5) : filteredReports.slice(0, 5)
-  return Promise.resolve({ data: { reports: paginatedReports }})
+export async function fetchGroupedReports(authHost, token) {
+  return Promise.resolve({ data: { reports: groupedReports }})
 }
 
-export async function changeState(state, id, authHost, token) {
+export async function changeState(reportsData, authHost, token) {
   return Promise.resolve({ data: '' })
 }
 
diff --git a/src/api/__mocks__/status.js b/src/api/__mocks__/status.js
new file mode 100644
index 0000000000000000000000000000000000000000..0e7bc9fb6c90715daa4fe4a4dc30e85cd02425b6
--- /dev/null
+++ b/src/api/__mocks__/status.js
@@ -0,0 +1,7 @@
+export async function changeStatusScope(id, sensitive, visibility, authHost, token) {
+  return Promise.resolve()
+}
+
+export async function deleteStatus(id, authHost, token) {
+  return Promise.resolve()
+}
diff --git a/src/api/reports.js b/src/api/reports.js
index 79833e40f71952bcf9633fe8157844d28b358c27..373e5bd5bd6f89b959e431e4ff47d9243c8889b6 100644
--- a/src/api/reports.js
+++ b/src/api/reports.js
@@ -2,48 +2,32 @@ import request from '@/utils/request'
 import { getToken } from '@/utils/auth'
 import { baseName } from './utils'
 
-export async function changeState(state, id, authHost, token) {
+export async function changeState(reports, authHost, token) {
   return await request({
     baseURL: baseName(authHost),
     url: `/api/pleroma/admin/reports`,
     method: 'patch',
     headers: authHeaders(token),
-    data: { reports: [{ id, state }] }
+    data: { reports }
   })
 }
 
-export async function changeStatusScope(id, sensitive, visibility, authHost, token) {
+export async function fetchReports(filter, page, pageSize, authHost, token) {
+  const url = filter.length > 0
+    ? `/api/pleroma/admin/reports?state=${filter}&page=${page}&page_size=${pageSize}`
+    : `/api/pleroma/admin/reports?page=${page}&page_size=${pageSize}`
   return await request({
     baseURL: baseName(authHost),
-    url: `/api/pleroma/admin/statuses/${id}`,
-    method: 'put',
-    headers: authHeaders(token),
-    data: { sensitive, visibility }
-  })
-}
-
-export async function deleteStatus(id, authHost, token) {
-  return await request({
-    baseURL: baseName(authHost),
-    url: `/api/pleroma/admin/statuses/${id}`,
-    method: 'delete',
-    headers: authHeaders(token)
-  })
-}
-
-export async function fetchReports(limit, max_id, authHost, token) {
-  return await request({
-    baseURL: baseName(authHost),
-    url: `/api/pleroma/admin/reports?limit=${limit}&max_id=${max_id}`,
+    url,
     method: 'get',
     headers: authHeaders(token)
   })
 }
 
-export async function filterReports(filter, limit, max_id, authHost, token) {
+export async function fetchGroupedReports(authHost, token) {
   return await request({
     baseURL: baseName(authHost),
-    url: `/api/pleroma/admin/reports?state=${filter}&limit=${limit}&max_id=${max_id}`,
+    url: `/api/pleroma/admin/grouped_reports`,
     method: 'get',
     headers: authHeaders(token)
   })
diff --git a/src/api/status.js b/src/api/status.js
new file mode 100644
index 0000000000000000000000000000000000000000..7d931ae04c73f3c150883035d56fb07c0e8c974a
--- /dev/null
+++ b/src/api/status.js
@@ -0,0 +1,24 @@
+import request from '@/utils/request'
+import { getToken } from '@/utils/auth'
+import { baseName } from './utils'
+
+export async function changeStatusScope(id, sensitive, visibility, authHost, token) {
+  return await request({
+    baseURL: baseName(authHost),
+    url: `/api/pleroma/admin/statuses/${id}`,
+    method: 'put',
+    headers: authHeaders(token),
+    data: { sensitive, visibility }
+  })
+}
+
+export async function deleteStatus(id, authHost, token) {
+  return await request({
+    baseURL: baseName(authHost),
+    url: `/api/pleroma/admin/statuses/${id}`,
+    method: 'delete',
+    headers: authHeaders(token)
+  })
+}
+
+const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {}
diff --git a/src/lang/en.js b/src/lang/en.js
index fee486d06f47a02b4ef8b12f4bf396efc1a9e1a3..d48934556dd6de016a586ab3b8a737959f20b231 100644
--- a/src/lang/en.js
+++ b/src/lang/en.js
@@ -253,6 +253,7 @@ export default {
   },
   reports: {
     reports: 'Reports',
+    groupedReports: 'Grouped reports',
     reply: 'Reply',
     from: 'From',
     showNotes: 'Show notes',
@@ -264,19 +265,32 @@ export default {
     deleteCompleted: 'Delete comleted',
     deleteCanceled: 'Delete canceled',
     noNotes: 'No notes to display',
-    changeState: 'Change report state',
+    changeState: "Change report's state",
+    changeAllReports: 'Change all reports',
     changeScope: 'Change scope',
     moderateUser: 'Moderate user',
     resolve: 'Resolve',
     reopen: 'Reopen',
     close: 'Close',
+    resolveAll: 'Resolve all',
+    reopenAll: 'Reopen all',
+    closeAll: 'Close all',
     addSensitive: 'Add Sensitive flag',
     removeSensitive: 'Remove Sensitive flag',
     public: 'Make status public',
     private: 'Make status private',
     unlisted: 'Make status unlisted',
     sensitive: 'Sensitive',
-    deleteStatus: 'Delete status'
+    deleteStatus: 'Delete status',
+    reportOn: 'Report on',
+    reportsOn: 'Reports on',
+    id: 'ID',
+    account: 'Account',
+    actor: 'Actor',
+    actors: 'Actors',
+    content: 'Content',
+    reportedStatus: 'Reported status',
+    statusDeleted: 'This status has been deleted'
   },
   reportsFilter: {
     inputPlaceholder: 'Select filter',
diff --git a/src/store/index.js b/src/store/index.js
index c71fca877b61e34f3bca306d5c28c4fe3b947875..87301b69ce68223eaa7c1c579cce037b5a5cc224 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -8,6 +8,7 @@ import permission from './modules/permission'
 import relays from './modules/relays'
 import reports from './modules/reports'
 import settings from './modules/settings'
+import status from './modules/status'
 import tagsView from './modules/tagsView'
 import user from './modules/user'
 import userProfile from './modules/userProfile'
@@ -27,6 +28,7 @@ const store = new Vuex.Store({
     relays,
     reports,
     settings,
+    status,
     tagsView,
     user,
     userProfile,
diff --git a/src/store/modules/reports.js b/src/store/modules/reports.js
index e44664f437ac467ecaef7985e84fc66d7828c108..d62f1b55e2e3faffd7869738a0f1c85c993c1166 100644
--- a/src/store/modules/reports.js
+++ b/src/store/modules/reports.js
@@ -1,10 +1,13 @@
-import { changeState, changeStatusScope, deleteStatus, fetchReports, filterReports } from '@/api/reports'
+import { changeState, fetchReports, fetchGroupedReports } from '@/api/reports'
 
 const reports = {
   state: {
     fetchedReports: [],
-    idOfLastReport: '',
-    page_limit: 5,
+    fetchedGroupedReports: [],
+    totalReportsCount: 0,
+    currentPage: 1,
+    pageSize: 50,
+    groupReports: false,
     stateFilter: '',
     loading: true
   },
@@ -15,67 +18,67 @@ const reports = {
     SET_LOADING: (state, status) => {
       state.loading = status
     },
+    SET_PAGE: (state, page) => {
+      state.currentPage = page
+    },
     SET_REPORTS: (state, reports) => {
       state.fetchedReports = reports
     },
+    SET_GROUPED_REPORTS: (state, reports) => {
+      state.fetchedGroupedReports = reports
+    },
+    SET_REPORTS_COUNT: (state, total) => {
+      state.totalReportsCount = total
+    },
     SET_REPORTS_FILTER: (state, filter) => {
       state.stateFilter = filter
+    },
+    SET_REPORTS_GROUPING: (state) => {
+      state.groupReports = !state.groupReports
     }
   },
   actions: {
-    async ChangeReportState({ commit, getters, state }, { reportState, reportId }) {
-      changeState(reportState, reportId, getters.authHost, getters.token)
+    async ChangeReportState({ commit, getters, state }, reportsData) {
+      changeState(reportsData, getters.authHost, getters.token)
 
       const updatedReports = state.fetchedReports.map(report => {
-        return report.id === reportId ? { ...report, state: reportState } : report
+        const updatedReportsIds = reportsData.map(({ id }) => id)
+        return updatedReportsIds.includes(report.id) ? { ...report, state: reportsData[0].state } : report
       })
 
-      commit('SET_REPORTS', updatedReports)
-    },
-    async ChangeStatusScope({ commit, getters, state }, { statusId, isSensitive, visibility, reportId }) {
-      const { data } = await changeStatusScope(statusId, isSensitive, visibility, getters.authHost, getters.token)
-      const updatedReports = state.fetchedReports.map(report => {
-        if (report.id === reportId) {
-          const statuses = report.statuses.map(status => status.id === statusId ? data : status)
-          return { ...report, statuses }
-        } else {
-          return report
-        }
+      const updatedGroupedReports = state.fetchedGroupedReports.map(group => {
+        const updatedReportsIds = reportsData.map(({ id }) => id)
+        const updatedReports = group.reports.map(report => updatedReportsIds.includes(report.id) ? { ...report, state: reportsData[0].state } : report)
+        return { ...group, reports: updatedReports }
       })
+
       commit('SET_REPORTS', updatedReports)
+      commit('SET_GROUPED_REPORTS', updatedGroupedReports)
     },
     ClearFetchedReports({ commit }) {
       commit('SET_REPORTS', [])
-      commit('SET_LAST_REPORT_ID', '')
     },
-    async DeleteStatus({ commit, getters, state }, { statusId, reportId }) {
-      deleteStatus(statusId, getters.authHost, getters.token)
-      const updatedReports = state.fetchedReports.map(report => {
-        if (report.id === reportId) {
-          const statuses = report.statuses.filter(status => status.id !== statusId)
-          return { ...report, statuses }
-        } else {
-          return report
-        }
-      })
-      commit('SET_REPORTS', updatedReports)
-    },
-    async FetchReports({ commit, getters, state }) {
+    async FetchReports({ commit, getters, state }, page) {
       commit('SET_LOADING', true)
+      const { data } = await fetchReports(state.stateFilter, page, state.pageSize, getters.authHost, getters.token)
 
-      const response = state.stateFilter.length === 0
-        ? await fetchReports(state.page_limit, state.idOfLastReport, getters.authHost, getters.token)
-        : await filterReports(state.stateFilter, state.page_limit, state.idOfLastReport, getters.authHost, getters.token)
-
-      const reports = state.fetchedReports.concat(response.data.reports)
-      const id = reports.length > 0 ? reports[reports.length - 1].id : state.idOfLastReport
+      commit('SET_REPORTS', data.reports)
+      commit('SET_REPORTS_COUNT', data.total)
+      commit('SET_PAGE', page)
+      commit('SET_LOADING', false)
+    },
+    async FetchGroupedReports({ commit, getters }) {
+      commit('SET_LOADING', true)
+      const { data } = await fetchGroupedReports(getters.authHost, getters.token)
 
-      commit('SET_REPORTS', reports)
-      commit('SET_LAST_REPORT_ID', id)
+      commit('SET_GROUPED_REPORTS', data.reports)
       commit('SET_LOADING', false)
     },
     SetFilter({ commit }, filter) {
       commit('SET_REPORTS_FILTER', filter)
+    },
+    ToggleReportsGrouping({ commit }) {
+      commit('SET_REPORTS_GROUPING')
     }
   }
 }
diff --git a/src/store/modules/status.js b/src/store/modules/status.js
new file mode 100644
index 0000000000000000000000000000000000000000..7d19d895ecd43fb44ad54f5df5cdbddcb0abe58c
--- /dev/null
+++ b/src/store/modules/status.js
@@ -0,0 +1,28 @@
+import { changeStatusScope, deleteStatus } from '@/api/status'
+
+const status = {
+  actions: {
+    async ChangeStatusScope({ dispatch, getters }, { statusId, isSensitive, visibility, reportCurrentPage, userId, godmode }) {
+      await changeStatusScope(statusId, isSensitive, visibility, getters.authHost, getters.token)
+      if (reportCurrentPage !== 0) { // called from Reports
+        dispatch('FetchReports', reportCurrentPage)
+      } else if (userId.length > 0) { // called from User profile
+        dispatch('FetchUserStatuses', { userId, godmode })
+      } else { // called from GroupedReports
+        dispatch('FetchGroupedReports')
+      }
+    },
+    async DeleteStatus({ dispatch, getters }, { statusId, reportCurrentPage, userId, godmode }) {
+      await deleteStatus(statusId, getters.authHost, getters.token)
+      if (reportCurrentPage !== 0) {
+        dispatch('FetchReports', reportCurrentPage)
+      } else if (userId.length > 0) {
+        dispatch('FetchUserStatuses', { userId, godmode })
+      } else {
+        dispatch('FetchGroupedReports')
+      }
+    }
+  }
+}
+
+export default status
diff --git a/src/store/modules/userProfile.js b/src/store/modules/userProfile.js
index 2dd656e688569514b4192a10d6c7b044059748fd..5a7e4394cd84e6019256c5b3b63ae38ad556c510 100644
--- a/src/store/modules/userProfile.js
+++ b/src/store/modules/userProfile.js
@@ -2,33 +2,42 @@ import { fetchUser, fetchUserStatuses } from '@/api/users'
 
 const userProfile = {
   state: {
+    statuses: [],
+    statusesLoading: true,
     user: {},
-    loading: true,
-    statuses: []
+    userProfileLoading: true
   },
   mutations: {
+    SET_STATUSES: (state, statuses) => {
+      state.statuses = statuses
+    },
+    SET_STATUSES_LOADING: (state, status) => {
+      state.statusesLoading = status
+    },
     SET_USER: (state, user) => {
       state.user = user
     },
-    SET_LOADING: (state, status) => {
-      state.loading = status
-    },
-    SET_STATUSES: (state, statuses) => {
-      state.statuses = statuses
+    SET_USER_PROFILE_LOADING: (state, status) => {
+      state.userProfileLoading = status
     }
   },
   actions: {
-    async FetchData({ commit, getters }, { id, godmode }) {
-      commit('SET_LOADING', true)
-
-      const [userResponse, statusesResponse] = await Promise.all([
-        fetchUser(id, getters.authHost, getters.token),
-        fetchUserStatuses(id, getters.authHost, godmode, getters.token)
-      ])
+    async FetchUserProfile({ commit, dispatch, getters }, { userId, godmode }) {
+      commit('SET_USER_PROFILE_LOADING', true)
 
+      const userResponse = await fetchUser(userId, getters.authHost, getters.token)
       commit('SET_USER', userResponse.data)
-      commit('SET_STATUSES', statusesResponse.data)
-      commit('SET_LOADING', false)
+      commit('SET_USER_PROFILE_LOADING', false)
+
+      dispatch('FetchUserStatuses', { userId, godmode })
+    },
+    async FetchUserStatuses({ commit, getters }, { userId, godmode }) {
+      commit('SET_STATUSES_LOADING', true)
+
+      const statuses = await fetchUserStatuses(userId, getters.authHost, godmode, getters.token)
+
+      commit('SET_STATUSES', statuses.data)
+      commit('SET_STATUSES_LOADING', false)
     }
   }
 }
diff --git a/src/views/reports/components/GroupedReport.vue b/src/views/reports/components/GroupedReport.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e11ba313882bdc76380c77f95c423a901b3cfc8f
--- /dev/null
+++ b/src/views/reports/components/GroupedReport.vue
@@ -0,0 +1,143 @@
+<template>
+  <el-timeline class="timeline">
+    <el-timeline-item
+      v-for="groupedReport in groupedReports"
+      :key="groupedReport.id"
+      :timestamp="parseTimestamp(groupedReport.date)"
+      placement="top"
+      class="timeline-item-container">
+      <el-card class="grouped-report">
+        <div class="header-container">
+          <div>
+            <h3 class="report-title">{{ $t('reports.reportsOn') }} {{ groupedReport.account.display_name }}</h3>
+          </div>
+          <div>
+            <el-dropdown trigger="click">
+              <el-button plain size="small" icon="el-icon-edit">{{ $t('reports.changeAllReports') }}<i class="el-icon-arrow-down el-icon--right"/></el-button>
+              <el-dropdown-menu slot="dropdown">
+                <el-dropdown-item @click.native="changeAllReports('resolved', groupedReport.reports)">{{ $t('reports.resolveAll') }}</el-dropdown-item>
+                <el-dropdown-item @click.native="changeAllReports('open', groupedReport.reports)">{{ $t('reports.reopenAll') }}</el-dropdown-item>
+                <el-dropdown-item @click.native="changeAllReports('closed', groupedReport.reports)">{{ $t('reports.closeAll') }}</el-dropdown-item>
+              </el-dropdown-menu>
+            </el-dropdown>
+            <moderate-user-dropdown :account="groupedReport.account"/>
+          </div>
+        </div>
+        <div>
+          <div class="line"/>
+          <span class="report-row-key">{{ $t('reports.account') }}:</span>
+          <img
+            :src="groupedReport.account.avatar"
+            alt="avatar"
+            class="avatar-img">
+          <a :href="groupedReport.account.url" target="_blank">
+            <span>{{ groupedReport.account.nickname }}</span>
+          </a>
+        </div>
+        <div>
+          <div class="line"/>
+          <span class="report-row-key">{{ $t('reports.actors') }}:</span>
+          <span v-for="(actor, index) in groupedReport.actors" :key="actor.id">
+            <a :href="actor.url" target="_blank">
+              {{ actor.acct }}<span v-if="index < groupedReport.actors.length - 1">, </span>
+            </a>
+          </span>
+        </div>
+        <div v-if="groupedReport.status">
+          <div class="line"/>
+          <span class="report-row-key">{{ $t('reports.reportedStatus') }}:</span>
+          <status :status="groupedReport.status" class="reported-status"/>
+        </div>
+        <div v-if="groupedReport.reports">
+          <el-collapse>
+            <el-collapse-item :title="$t('reports.reports')">
+              <report-card :reports="groupedReport.reports"/>
+            </el-collapse-item>
+          </el-collapse>
+        </div>
+      </el-card>
+    </el-timeline-item>
+  </el-timeline>
+</template>
+
+<script>
+import moment from 'moment'
+import ModerateUserDropdown from './ModerateUserDropdown'
+import ReportCard from './ReportCard'
+import Status from '../../status/Status'
+
+export default {
+  name: 'Report',
+  components: { ModerateUserDropdown, ReportCard, Status },
+  props: {
+    groupedReports: {
+      type: Array,
+      required: true
+    }
+  },
+  methods: {
+    changeAllReports(reportState, groupOfReports) {
+      const reportsData = groupOfReports.map(report => {
+        return { id: report.id, state: reportState }
+      })
+      this.$store.dispatch('ChangeReportState', reportsData)
+    },
+    parseTimestamp(timestamp) {
+      return moment(timestamp).format('L HH:mm')
+    }
+  }
+}
+</script>
+
+<style rel='stylesheet/scss' lang='scss'>
+  a {
+    text-decoration: underline;
+  }
+  .avatar-img {
+    vertical-align: bottom;
+    width: 15px;
+    height: 15px;
+    margin-left: 5px;
+  }
+  .el-card__body {
+    padding: 17px;
+  }
+  .el-card__header {
+    background-color: #FAFAFA;
+    padding: 10px 20px;
+  }
+  .el-icon-arrow-right {
+    margin-right: 6px;
+  }
+  .header-container {
+    display: flex;
+    justify-content: space-between;
+    align-items: baseline;
+    height: 40px;
+  }
+  .line {
+    width: 100%;
+    height: 0;
+    border: 0.5px solid #EBEEF5;
+    margin: 15px 0 15px;
+  }
+  .report-title {
+    margin: 0;
+  }
+  .report-row-key {
+    font-size: 14px;
+    font-weight: 500;
+  }
+  .reported-status {
+    margin-top: 15px;
+  }
+  @media
+  only screen and (max-width: 760px),
+  (min-device-width: 768px) and (max-device-width: 1024px) {
+    .header-container {
+      display: flex;
+      flex-direction: column;
+      height: 80px;
+    }
+  }
+</style>
diff --git a/src/views/reports/components/ModerateUserDropdown.vue b/src/views/reports/components/ModerateUserDropdown.vue
new file mode 100644
index 0000000000000000000000000000000000000000..2d3689991e97590f1e4eff62553337d9033e4a98
--- /dev/null
+++ b/src/views/reports/components/ModerateUserDropdown.vue
@@ -0,0 +1,86 @@
+<template>
+  <el-dropdown trigger="click">
+    <el-button plain size="small" icon="el-icon-files">{{ $t('reports.moderateUser') }}
+      <i class="el-icon-arrow-down el-icon--right"/>
+    </el-button>
+    <el-dropdown-menu slot="dropdown">
+      <el-dropdown-item
+        v-if="showDeactivatedButton(account)"
+        @click.native="handleDeactivation(account)">
+        {{ account.deactivated ? $t('users.activateAccount') : $t('users.deactivateAccount') }}
+      </el-dropdown-item>
+      <el-dropdown-item
+        v-if="showDeactivatedButton(account.id)"
+        @click.native="handleDeletion(account.id)">
+        {{ $t('users.deleteAccount') }}
+      </el-dropdown-item>
+      <el-dropdown-item
+        :divided="true"
+        :class="{ 'active-tag': account.tags.includes('force_nsfw') }"
+        @click.native="toggleTag(account, 'force_nsfw')">
+        {{ $t('users.forceNsfw') }}
+        <i v-if="account.tags.includes('force_nsfw')" class="el-icon-check"/>
+      </el-dropdown-item>
+      <el-dropdown-item
+        :class="{ 'active-tag': account.tags.includes('strip_media') }"
+        @click.native="toggleTag(account, 'strip_media')">
+        {{ $t('users.stripMedia') }}
+        <i v-if="account.tags.includes('strip_media')" class="el-icon-check"/>
+      </el-dropdown-item>
+      <el-dropdown-item
+        :class="{ 'active-tag': account.tags.includes('force_unlisted') }"
+        @click.native="toggleTag(account, 'force_unlisted')">
+        {{ $t('users.forceUnlisted') }}
+        <i v-if="account.tags.includes('force_unlisted')" class="el-icon-check"/>
+      </el-dropdown-item>
+      <el-dropdown-item
+        :class="{ 'active-tag': account.tags.includes('sandbox') }"
+        @click.native="toggleTag(account, 'sandbox')">
+        {{ $t('users.sandbox') }}
+        <i v-if="account.tags.includes('sandbox')" class="el-icon-check"/>
+      </el-dropdown-item>
+      <el-dropdown-item
+        v-if="account.local"
+        :class="{ 'active-tag': account.tags.includes('disable_remote_subscription') }"
+        @click.native="toggleTag(account, 'disable_remote_subscription')">
+        {{ $t('users.disableRemoteSubscription') }}
+        <i v-if="account.tags.includes('disable_remote_subscription')" class="el-icon-check"/>
+      </el-dropdown-item>
+      <el-dropdown-item
+        v-if="account.local"
+        :class="{ 'active-tag': account.tags.includes('disable_any_subscription') }"
+        @click.native="toggleTag(account, 'disable_any_subscription')">
+        {{ $t('users.disableAnySubscription') }}
+        <i v-if="account.tags.includes('disable_any_subscription')" class="el-icon-check"/>
+      </el-dropdown-item>
+    </el-dropdown-menu>
+  </el-dropdown>
+</template>
+
+<script>
+export default {
+  name: 'ModerateUserDropdown',
+  props: {
+    account: {
+      type: Object,
+      required: true
+    }
+  },
+  methods: {
+    handleDeactivation({ nickname }) {
+      this.$store.dispatch('ToggleUserActivation', nickname)
+    },
+    handleDeletion(user) {
+      this.$store.dispatch('DeleteUser', user)
+    },
+    showDeactivatedButton(id) {
+      return this.$store.state.user.id !== id
+    },
+    toggleTag(user, tag) {
+      user.tags.includes(tag)
+        ? this.$store.dispatch('RemoveTag', { users: [user], tag })
+        : this.$store.dispatch('AddTag', { users: [user], tag })
+    }
+  }
+}
+</script>
diff --git a/src/views/reports/components/Report.vue b/src/views/reports/components/Report.vue
new file mode 100644
index 0000000000000000000000000000000000000000..7fc5d0519ac2a03f249dc85438c3f7de2c74029e
--- /dev/null
+++ b/src/views/reports/components/Report.vue
@@ -0,0 +1,250 @@
+<template>
+  <div>
+    <el-timeline class="timeline">
+      <el-timeline-item
+        v-for="report in reports"
+        :timestamp="parseTimestamp(report.created_at)"
+        :key="report.id"
+        placement="top"
+        class="timeline-item-container">
+        <el-card>
+          <div class="header-container">
+            <div>
+              <h3 class="report-title">{{ $t('reports.reportOn') }} {{ report.account.display_name }}</h3>
+              <h5 class="id">{{ $t('reports.id') }}: {{ report.id }}</h5>
+            </div>
+            <div>
+              <el-tag :type="getStateType(report.state)" size="large">{{ capitalizeFirstLetter(report.state) }}</el-tag>
+              <el-dropdown trigger="click">
+                <el-button plain size="small" icon="el-icon-edit">{{ $t('reports.changeState') }}<i class="el-icon-arrow-down el-icon--right"/></el-button>
+                <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item v-if="report.state !== 'resolved'" @click.native="changeReportState('resolved', report.id)">{{ $t('reports.resolve') }}</el-dropdown-item>
+                  <el-dropdown-item v-if="report.state !== 'open'" @click.native="changeReportState('open', report.id)">{{ $t('reports.reopen') }}</el-dropdown-item>
+                  <el-dropdown-item v-if="report.state !== 'closed'" @click.native="changeReportState('closed', report.id)">{{ $t('reports.close') }}</el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+              <moderate-user-dropdown :account="report.account"/>
+            </div>
+          </div>
+          <div>
+            <div class="line"/>
+            <span class="report-row-key">{{ $t('reports.account') }}:</span>
+            <img
+              :src="report.account.avatar"
+              alt="avatar"
+              class="avatar-img">
+            <a :href="report.account.url" target="_blank" class="account">
+              <span>{{ report.account.acct }}</span>
+            </a>
+          </div>
+          <div v-if="report.content.length > 0">
+            <div class="line"/>
+            <span class="report-row-key">{{ $t('reports.content') }}:
+              <span>{{ report.content }}</span>
+            </span>
+          </div>
+          <div>
+            <div class="line"/>
+            <span class="report-row-key">{{ $t('reports.actor') }}:</span>
+            <img
+              :src="report.actor.avatar"
+              alt="avatar"
+              class="avatar-img">
+            <a :href="report.actor.url" target="_blank" class="account">
+              <span>{{ report.actor.acct }}</span>
+            </a>
+          </div>
+          <div v-if="report.statuses.length > 0" class="statuses">
+            <el-collapse>
+              <el-collapse-item :title="getStatusesTitle(report.statuses)">
+                <div v-for="status in report.statuses" :key="status.id">
+                  <status :status="status" :page="currentPage"/>
+                </div>
+              </el-collapse-item>
+            </el-collapse>
+          </div>
+        </el-card>
+      </el-timeline-item>
+    </el-timeline>
+    <div v-if="!loading" class="reports-pagination">
+      <el-pagination
+        :total="totalReportsCount"
+        :current-page="currentPage"
+        :page-size="pageSize"
+        background
+        layout="prev, pager, next"
+        @current-change="handlePageChange"
+      />
+    </div>
+  </div>
+</template>
+
+<script>
+import moment from 'moment'
+import Status from '../../status/Status'
+import ModerateUserDropdown from './ModerateUserDropdown'
+
+export default {
+  name: 'Report',
+  components: { Status, ModerateUserDropdown },
+  props: {
+    reports: {
+      type: Array,
+      required: true
+    }
+  },
+  computed: {
+    loading() {
+      return this.$store.state.reports.loading
+    },
+    pageSize() {
+      return this.$store.state.reports.pageSize
+    },
+    totalReportsCount() {
+      return this.$store.state.reports.totalReportsCount
+    },
+    currentPage() {
+      return this.$store.state.reports.currentPage
+    }
+  },
+  methods: {
+    changeReportState(state, id) {
+      this.$store.dispatch('ChangeReportState', [{ state, id }])
+    },
+    capitalizeFirstLetter(str) {
+      return str.charAt(0).toUpperCase() + str.slice(1)
+    },
+    getStateType(state) {
+      switch (state) {
+        case 'closed':
+          return 'info'
+        case 'resolved':
+          return 'success'
+        default:
+          return 'primary'
+      }
+    },
+    getStatusesTitle(statuses) {
+      return `Reported statuses: ${statuses.length} item(s)`
+    },
+    handlePageChange(page) {
+      this.$store.dispatch('FetchReports', page)
+    },
+    parseTimestamp(timestamp) {
+      return moment(timestamp).format('L HH:mm')
+    }
+  }
+}
+</script>
+
+<style rel='stylesheet/scss' lang='scss'>
+  .account {
+    text-decoration: underline;
+  }
+  .avatar-img {
+    vertical-align: bottom;
+    width: 15px;
+    height: 15px;
+    margin-left: 5px;
+  }
+  .el-card__body {
+    padding: 17px;
+  }
+  .el-card__header {
+    background-color: #FAFAFA;
+    padding: 10px 20px;
+  }
+  .el-collapse {
+    border-bottom: none;
+  }
+  .el-collapse-item__header {
+    height: 46px;
+    font-size: 14px;
+  }
+  .el-collapse-item__content {
+    padding-bottom: 7px;
+  }
+  .el-icon-arrow-right {
+    margin-right: 6px;
+  }
+  .el-icon-close {
+    padding: 10px 5px 10px 10px;
+    cursor: pointer;
+  }
+  h4 {
+    margin: 0;
+    height: 17px;
+  }
+  .header-container {
+    display: flex;
+    justify-content: space-between;
+    align-items: baseline;
+    height: 40px;
+  }
+  .id {
+    color: gray;
+    margin-top: 6px;
+  }
+  .line {
+    width: 100%;
+    height: 0;
+    border: 0.5px solid #EBEEF5;
+    margin: 15px 0 15px;
+  }
+  .new-note {
+    p {
+      font-size: 14px;
+      font-weight: 500;
+      height: 17px;
+      margin: 13px 0 7px;
+    }
+  }
+  .note {
+    box-shadow: 0 2px 5px 0 rgba(0,0,0,.1);
+    margin-bottom: 10px;
+  }
+  .no-notes {
+    font-style: italic;
+    color: gray;
+  }
+  .report-row-key {
+    font-size: 14px;
+    font-weight: 500;
+  }
+  .report-row-key {
+    font-size: 14px;
+  }
+  .report-title {
+    margin: 0;
+  }
+  .reports-pagination {
+    margin: 25px 0;
+    text-align: center;
+  }
+  .statuses {
+    margin-top: 15px;
+  }
+  .submit-button {
+    display: block;
+    margin: 7px 0 17px auto;
+  }
+  .timestamp {
+    margin: 0;
+    font-style: italic;
+    color: gray;
+  }
+  @media
+  only screen and (max-width: 760px),
+  (min-device-width: 768px) and (max-device-width: 1024px) {
+    .timeline-item-container {
+      .header-container {
+        display: flex;
+        flex-direction: column;
+        height: 80px;
+      }
+      .id {
+        margin: 6px 0 0 0;
+      }
+    }
+  }
+</style>
diff --git a/src/views/reports/components/ReportCard.vue b/src/views/reports/components/ReportCard.vue
new file mode 100644
index 0000000000000000000000000000000000000000..67b0b01ceecfd4cdb5bdba60af87d80e666ab33e
--- /dev/null
+++ b/src/views/reports/components/ReportCard.vue
@@ -0,0 +1,130 @@
+<template>
+  <div>
+    <el-card v-for="report in reports" :key="report.id" class="report-card">
+      <div slot="header">
+        <div class="report-header">
+          <div class="report-actor-container">
+            <div class="report-actor">
+              <img :src="report.actor.avatar" class="report-avatar-img">
+              <h3 class="report-actor-name">{{ report.actor.display_name }}</h3>
+            </div>
+            <a :href="report.actor.url" target="_blank">
+              @{{ report.actor.acct }}
+            </a>
+          </div>
+          <div>
+            <el-tag :type="getStateType(report.state)" size="large">{{ capitalizeFirstLetter(report.state) }}</el-tag>
+            <el-dropdown trigger="click">
+              <el-button plain size="small" icon="el-icon-edit">{{ $t('reports.changeState') }}<i class="el-icon-arrow-down el-icon--right"/></el-button>
+              <el-dropdown-menu slot="dropdown">
+                <el-dropdown-item v-if="report.state !== 'resolved'" @click.native="changeReportState('resolved', report.id)">{{ $t('reports.resolve') }}</el-dropdown-item>
+                <el-dropdown-item v-if="report.state !== 'open'" @click.native="changeReportState('open', report.id)">{{ $t('reports.reopen') }}</el-dropdown-item>
+                <el-dropdown-item v-if="report.state !== 'closed'" @click.native="changeReportState('closed', report.id)">{{ $t('reports.close') }}</el-dropdown-item>
+              </el-dropdown-menu>
+            </el-dropdown>
+          </div>
+        </div>
+      </div>
+      <div class="report-body">
+        <span class="report-content" v-html="report.content"/>
+        {{ parseTimestamp(report.created_at) }}
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import moment from 'moment'
+
+export default {
+  name: 'Statuses',
+  props: {
+    reports: {
+      type: Array,
+      required: true
+    }
+  },
+  methods: {
+    capitalizeFirstLetter(str) {
+      return str.charAt(0).toUpperCase() + str.slice(1)
+    },
+    changeReportState(state, id) {
+      this.$store.dispatch('ChangeReportState', [{ state, id }])
+    },
+    getStateType(state) {
+      switch (state) {
+        case 'closed':
+          return 'info'
+        case 'resolved':
+          return 'success'
+        default:
+          return 'primary'
+      }
+    },
+    parseTimestamp(timestamp) {
+      return moment(timestamp).format('YYYY-MM-DD HH:mm')
+    }
+  }
+}
+</script>
+
+<style rel='stylesheet/scss' lang='scss'>
+  a {
+    text-decoration: underline;
+  }
+  .el-icon-arrow-right {
+    margin-right: 6px;
+  }
+  .report-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: baseline;
+    height: 40px;
+  }
+  .report-actor {
+    display: flex;
+    align-items: center;
+  }
+  .report-actor-name {
+    margin: 0;
+    height: 22px;
+  }
+  .report-avatar-img {
+    width: 15px;
+    height: 15px;
+    margin-right: 5px;
+  }
+  .report-body {
+    display: flex;
+    flex-direction: column;
+  }
+  .report-card {
+    margin-bottom: 15px;
+  }
+  .report-content {
+    font-size: 15px;
+  }
+  .report-header {
+    display: flex;
+    justify-content: space-between;
+  }
+  @media
+  only screen and (max-width: 760px),
+  (min-device-width: 768px) and (max-device-width: 1024px) {
+    .el-card__header {
+      padding: 10px 17px;
+    }
+    .report-header {
+      display: flex;
+      flex-direction: column;
+      height: 80px;
+    }
+    .report-actor-container {
+      margin-bottom: 5px;
+    }
+    .report-header {
+      display: flex;
+      flex-direction: column;
+    }
+  }
+</style>
diff --git a/src/views/reports/components/ReportsFilter.vue b/src/views/reports/components/ReportsFilter.vue
index 40c232165fba4fb8b8be9b1678bfe00cf02ab147..da1fd7820813c045bbec9c149ec32873e7c0571e 100644
--- a/src/views/reports/components/ReportsFilter.vue
+++ b/src/views/reports/components/ReportsFilter.vue
@@ -44,7 +44,7 @@ export default {
     toggleFilters() {
       this.$store.dispatch('SetFilter', this.$data.filter)
       this.$store.dispatch('ClearFetchedReports')
-      this.$store.dispatch('FetchReports')
+      this.$store.dispatch('FetchReports', 1)
     }
   }
 }
diff --git a/src/views/reports/components/Statuses.vue b/src/views/reports/components/Statuses.vue
deleted file mode 100644
index a385a700af4e98f004221911ee76bdfedd259e73..0000000000000000000000000000000000000000
--- a/src/views/reports/components/Statuses.vue
+++ /dev/null
@@ -1,176 +0,0 @@
-<template>
-  <el-collapse-item :title="getStatusesTitle(report.statuses)">
-    <el-card v-for="status in report.statuses" :key="status.id" class="status-card">
-      <div slot="header">
-        <div class="status-header">
-          <div class="status-account-container">
-            <div class="status-account">
-              <img :src="status.account.avatar" class="status-avatar-img">
-              <h3 class="status-account-name">{{ status.account.display_name }}</h3>
-            </div>
-            <a :href="status.account.url" target="_blank" class="account">
-              @{{ status.account.acct }}
-            </a>
-          </div>
-          <div class="status-actions">
-            <el-tag v-if="status.sensitive" type="warning" size="large">{{ $t('reports.sensitive') }}</el-tag>
-            <el-tag size="large">{{ capitalizeFirstLetter(status.visibility) }}</el-tag>
-            <el-dropdown trigger="click">
-              <el-button plain size="small" icon="el-icon-edit" class="status-actions-button">
-                {{ $t('reports.changeScope') }}<i class="el-icon-arrow-down el-icon--right"/>
-              </el-button>
-              <el-dropdown-menu slot="dropdown">
-                <el-dropdown-item
-                  v-if="!status.sensitive"
-                  @click.native="changeStatus(status.id, true, status.visibility, report.id)">
-                  {{ $t('reports.addSensitive') }}
-                </el-dropdown-item>
-                <el-dropdown-item
-                  v-if="status.sensitive"
-                  @click.native="changeStatus(status.id, false, status.visibility, report.id)">
-                  {{ $t('reports.removeSensitive') }}
-                </el-dropdown-item>
-                <el-dropdown-item
-                  v-if="status.visibility !== 'public'"
-                  @click.native="changeStatus(status.id, status.sensitive, 'public', report.id)">
-                  {{ $t('reports.public') }}
-                </el-dropdown-item>
-                <el-dropdown-item
-                  v-if="status.visibility !== 'private'"
-                  @click.native="changeStatus(status.id, status.sensitive, 'private', report.id)">
-                  {{ $t('reports.private') }}
-                </el-dropdown-item>
-                <el-dropdown-item
-                  v-if="status.visibility !== 'unlisted'"
-                  @click.native="changeStatus(status.id, status.sensitive, 'unlisted', report.id)">
-                  {{ $t('reports.unlisted') }}
-                </el-dropdown-item>
-                <el-dropdown-item
-                  @click.native="deleteStatus(status.id, report.id)">
-                  {{ $t('reports.deleteStatus') }}
-                </el-dropdown-item>
-              </el-dropdown-menu>
-            </el-dropdown>
-          </div>
-        </div>
-      </div>
-      <div class="status-body">
-        <span class="status-content" v-html="status.content"/>
-        <a :href="status.url" target="_blank" class="account">
-          {{ parseTimestamp(status.created_at) }}
-        </a>
-      </div>
-    </el-card>
-  </el-collapse-item>
-</template>
-
-<script>
-import moment from 'moment'
-
-export default {
-  name: 'Statuses',
-  props: {
-    report: {
-      type: Object,
-      required: true
-    }
-  },
-  methods: {
-    capitalizeFirstLetter(str) {
-      return str.charAt(0).toUpperCase() + str.slice(1)
-    },
-    changeStatus(statusId, isSensitive, visibility, reportId) {
-      this.$store.dispatch('ChangeStatusScope', { statusId, isSensitive, visibility, reportId })
-    },
-    deleteStatus(statusId, reportId) {
-      this.$confirm('Are you sure you want to delete this status?', 'Warning', {
-        confirmButtonText: 'OK',
-        cancelButtonText: 'Cancel',
-        type: 'warning'
-      }).then(() => {
-        this.$store.dispatch('DeleteStatus', { statusId, reportId })
-        this.$message({
-          type: 'success',
-          message: 'Delete completed'
-        })
-      }).catch(() => {
-        this.$message({
-          type: 'info',
-          message: 'Delete canceled'
-        })
-      })
-    },
-    getStatusesTitle(statuses) {
-      return `Reported statuses: ${statuses.length} item(s)`
-    },
-    parseTimestamp(timestamp) {
-      return moment(timestamp).format('YYYY-MM-DD HH:mm')
-    }
-  }
-}
-</script>
-
-<style rel='stylesheet/scss' lang='scss'>
-  .account {
-    text-decoration: underline;
-  }
-  .status-account {
-    display: flex;
-    align-items: center;
-  }
-  .status-avatar-img {
-    width: 15px;
-    height: 15px;
-    margin-right: 5px;
-  }
-  .status-account-name {
-    margin: 0;
-    height: 22px;
-  }
-  .status-body {
-    display: flex;
-    flex-direction: column;
-  }
-  .status-content {
-    font-size: 15px;
-  }
-  .status-card {
-    margin-bottom: 15px;
-  }
-  .status-header {
-    display: flex;
-    justify-content: space-between;
-  }
-  @media
-  only screen and (max-width: 760px),
-  (min-device-width: 768px) and (max-device-width: 1024px) {
-    .el-message {
-      min-width: 80%;
-    }
-    .el-message-box {
-      width: 80%;
-    }
-    .status-card {
-      .el-card__header {
-        padding: 10px 17px
-      }
-      .el-tag {
-        margin: 3px 4px 3px 0;
-      }
-      .status-account-container {
-        margin-bottom: 5px;
-      }
-      .status-actions-button {
-        margin: 3px 0 3px;
-      }
-      .status-actions {
-        display: flex;
-        flex-wrap: wrap;
-      }
-      .status-header {
-        display: flex;
-        flex-direction: column;
-      }
-    }
-  }
-</style>
diff --git a/src/views/reports/components/TimelineItem.vue b/src/views/reports/components/TimelineItem.vue
deleted file mode 100644
index e7e41e7ba91f1f93302ab898c477337b057db831..0000000000000000000000000000000000000000
--- a/src/views/reports/components/TimelineItem.vue
+++ /dev/null
@@ -1,271 +0,0 @@
-<template>
-  <el-timeline-item :timestamp="parseTimestamp(report.created_at)" placement="top" class="timeline-item-container">
-    <el-card>
-      <div class="header-container">
-        <div>
-          <h3 class="report-title">Report on {{ report.account.display_name }}</h3>
-          <h5 class="id">ID: {{ report.id }}</h5>
-        </div>
-        <div>
-          <el-tag :type="getStateType(report.state)" size="large">{{ capitalizeFirstLetter(report.state) }}</el-tag>
-          <el-dropdown trigger="click">
-            <el-button plain size="small" icon="el-icon-edit">{{ $t('reports.changeState') }}<i class="el-icon-arrow-down el-icon--right"/></el-button>
-            <el-dropdown-menu slot="dropdown">
-              <el-dropdown-item v-if="report.state !== 'resolved'" @click.native="changeReportState('resolved', report.id)">{{ $t('reports.resolve') }}</el-dropdown-item>
-              <el-dropdown-item v-if="report.state !== 'open'" @click.native="changeReportState('open', report.id)">{{ $t('reports.reopen') }}</el-dropdown-item>
-              <el-dropdown-item v-if="report.state !== 'closed'" @click.native="changeReportState('closed', report.id)">{{ $t('reports.close') }}</el-dropdown-item>
-            </el-dropdown-menu>
-          </el-dropdown>
-          <el-dropdown trigger="click">
-            <el-button plain size="small" icon="el-icon-files">{{ $t('reports.moderateUser') }}<i class="el-icon-arrow-down el-icon--right"/></el-button>
-            <el-dropdown-menu slot="dropdown">
-              <el-dropdown-item
-                v-if="showDeactivatedButton(report.account)"
-                @click.native="toggleActivation(report.account)">
-                {{ report.account.deactivated ? $t('users.activateAccount') : $t('users.deactivateAccount') }}
-              </el-dropdown-item>
-              <el-dropdown-item
-                v-if="showDeactivatedButton(report.account.id)"
-                @click.native="handleDeletion(report.account.id)">
-                {{ $t('users.deleteAccount') }}
-              </el-dropdown-item>
-              <el-dropdown-item
-                :divided="true"
-                :class="{ 'active-tag': report.account.tags.includes('force_nsfw') }"
-                @click.native="toggleTag(report.account, 'force_nsfw')">
-                {{ $t('users.forceNsfw') }}
-                <i v-if="report.account.tags.includes('force_nsfw')" class="el-icon-check"/>
-              </el-dropdown-item>
-              <el-dropdown-item
-                :class="{ 'active-tag': report.account.tags.includes('strip_media') }"
-                @click.native="toggleTag(report.account, 'strip_media')">
-                {{ $t('users.stripMedia') }}
-                <i v-if="report.account.tags.includes('strip_media')" class="el-icon-check"/>
-              </el-dropdown-item>
-              <el-dropdown-item
-                :class="{ 'active-tag': report.account.tags.includes('force_unlisted') }"
-                @click.native="toggleTag(report.account, 'force_unlisted')">
-                {{ $t('users.forceUnlisted') }}
-                <i v-if="report.account.tags.includes('force_unlisted')" class="el-icon-check"/>
-              </el-dropdown-item>
-              <el-dropdown-item
-                :class="{ 'active-tag': report.account.tags.includes('sandbox') }"
-                @click.native="toggleTag(report.account, 'sandbox')">
-                {{ $t('users.sandbox') }}
-                <i v-if="report.account.tags.includes('sandbox')" class="el-icon-check"/>
-              </el-dropdown-item>
-              <el-dropdown-item
-                v-if="report.account.local"
-                :class="{ 'active-tag': report.account.tags.includes('disable_remote_subscription') }"
-                @click.native="toggleTag(report.account, 'disable_remote_subscription')">
-                {{ $t('users.disableRemoteSubscription') }}
-                <i v-if="report.account.tags.includes('disable_remote_subscription')" class="el-icon-check"/>
-              </el-dropdown-item>
-              <el-dropdown-item
-                v-if="report.account.local"
-                :class="{ 'active-tag': report.account.tags.includes('disable_any_subscription') }"
-                @click.native="toggleTag(report.account, 'disable_any_subscription')">
-                {{ $t('users.disableAnySubscription') }}
-                <i v-if="report.account.tags.includes('disable_any_subscription')" class="el-icon-check"/>
-              </el-dropdown-item>
-            </el-dropdown-menu>
-          </el-dropdown>
-        </div>
-      </div>
-      <div>
-        <div class="line"/>
-        <span class="report-row-key">Account:</span>
-        <img
-          :src="report.account.avatar"
-          alt="avatar"
-          class="avatar-img">
-        <a :href="report.account.url" target="_blank" class="account">
-          <span class="report-row-value">{{ report.account.acct }}</span>
-        </a>
-      </div>
-      <div v-if="report.content.length > 0">
-        <div class="line"/>
-        <span class="report-row-key">Content:
-          <span class="report-row-value">{{ report.content }}</span>
-        </span>
-      </div>
-      <div>
-        <div class="line"/>
-        <span class="report-row-key">Actor:</span>
-        <img
-          :src="report.actor.avatar"
-          alt="avatar"
-          class="avatar-img">
-        <a :href="report.actor.url" target="_blank" class="account">
-          <span class="report-row-value">{{ report.actor.acct }}</span>
-        </a>
-      </div>
-      <div v-if="report.statuses.length > 0" class="statuses">
-        <el-collapse>
-          <statuses :report="report"/>
-        </el-collapse>
-      </div>
-    </el-card>
-  </el-timeline-item>
-</template>
-
-<script>
-import moment from 'moment'
-import Statuses from './Statuses'
-
-export default {
-  name: 'TimelineItem',
-  components: { Statuses },
-  props: {
-    report: {
-      type: Object,
-      required: true
-    }
-  },
-  methods: {
-    changeReportState(reportState, reportId) {
-      this.$store.dispatch('ChangeReportState', { reportState, reportId })
-    },
-    capitalizeFirstLetter(str) {
-      return str.charAt(0).toUpperCase() + str.slice(1)
-    },
-    getStateType(state) {
-      switch (state) {
-        case 'closed':
-          return 'info'
-        case 'resolved':
-          return 'success'
-        default:
-          return 'primary'
-      }
-    },
-    handleDeletion(user) {
-      this.$store.dispatch('DeleteUsers', [user])
-    },
-    parseTimestamp(timestamp) {
-      return moment(timestamp).format('L HH:mm')
-    },
-    showDeactivatedButton(id) {
-      return this.$store.state.user.id !== id
-    },
-    toggleActivation(user) {
-      user.deactivated
-        ? this.$store.dispatch('ActivateUsers', [user])
-        : this.$store.dispatch('DeactivateUsers', [user])
-    },
-    toggleTag(user, tag) {
-      user.tags.includes(tag)
-        ? this.$store.dispatch('RemoveTag', { users: [user], tag })
-        : this.$store.dispatch('AddTag', { users: [user], tag })
-    }
-  }
-}
-</script>
-
-<style rel='stylesheet/scss' lang='scss'>
-  .account {
-    text-decoration: underline;
-  }
-  .avatar-img {
-    vertical-align: bottom;
-    width: 15px;
-    height: 15px;
-    margin-left: 5px;
-  }
-  .el-card__body {
-    padding: 17px;
-  }
-  .el-card__header {
-    background-color: #FAFAFA;
-    padding: 10px 20px;
-  }
-  .el-collapse {
-    border-bottom: none;
-  }
-  .el-collapse-item__header {
-    height: 46px;
-    font-size: 14px;
-  }
-  .el-collapse-item__content {
-    padding-bottom: 7px;
-  }
-  .el-icon-arrow-right {
-    margin-right: 6px;
-  }
-  .el-icon-close {
-    padding: 10px 5px 10px 10px;
-    cursor: pointer;
-  }
-  h4 {
-    margin: 0;
-    height: 17px;
-  }
-  .header-container {
-    display: flex;
-    justify-content: space-between;
-    align-items: baseline;
-    height: 40px;
-  }
-  .id {
-    color: gray;
-    margin-top: 6px;
-  }
-  .line {
-    width: 100%;
-    height: 0;
-    border: 0.5px solid #EBEEF5;
-    margin: 15px 0 15px;
-  }
-  .new-note {
-    p {
-      font-size: 14px;
-      font-weight: 500;
-      height: 17px;
-      margin: 13px 0 7px;
-    }
-  }
-  .note {
-    box-shadow: 0 2px 5px 0 rgba(0,0,0,.1);
-    margin-bottom: 10px;
-  }
-  .no-notes {
-    font-style: italic;
-    color: gray;
-  }
-  .report-row-key {
-    font-size: 14px;
-    font-weight: 500;
-  }
-  .report-row-key {
-    font-size: 14px;
-  }
-  .report-title {
-    margin: 0;
-  }
-  .statuses {
-    margin-top: 15px;
-  }
-  .submit-button {
-    display: block;
-    margin: 7px 0 17px auto;
-  }
-  .timestamp {
-    margin: 0;
-    font-style: italic;
-    color: gray;
-  }
-  @media
-  only screen and (max-width: 760px),
-  (min-device-width: 768px) and (max-device-width: 1024px) {
-    .timeline-item-container {
-      .header-container {
-        display: flex;
-        flex-direction: column;
-        height: 80px;
-      }
-      .id {
-        margin: 6px 0 0 0;
-      }
-    }
-  }
-</style>
diff --git a/src/views/reports/index.vue b/src/views/reports/index.vue
index 63a830ae9352aacdc87c44fb8419f3e4d63e3b15..3c87d3e52138e70238d84da904a12290319472c9 100644
--- a/src/views/reports/index.vue
+++ b/src/views/reports/index.vue
@@ -1,13 +1,22 @@
 <template>
   <div class="reports-container">
-    <h1>{{ $t('reports.reports') }}</h1>
+    <h1 v-if="groupReports">
+      {{ $t('reports.groupedReports') }}
+      <span class="report-count">({{ normalizedReportsCount }})</span>
+    </h1>
+    <h1 v-else>
+      {{ $t('reports.reports') }}
+      <span class="report-count">({{ normalizedReportsCount }})</span>
+    </h1>
     <div class="filter-container">
-      <reports-filter/>
+      <reports-filter v-if="!groupReports"/>
+      <el-checkbox v-model="groupReports" class="group-reports-checkbox">
+        Group reports by statuses
+      </el-checkbox>
     </div>
     <div class="block">
-      <el-timeline class="timeline">
-        <timeline-item v-loading="loading" v-for="report in reports" :report="report" :key="report.id"/>
-      </el-timeline>
+      <grouped-report v-loading="loading" v-if="groupReports" :grouped-reports="groupedReports"/>
+      <report v-loading="loading" v-else :reports="reports"/>
       <div v-if="reports.length === 0" class="no-reports-message">
         <p>There are no reports to display</p>
       </div>
@@ -16,34 +25,44 @@
 </template>
 
 <script>
-import TimelineItem from './components/TimelineItem'
+import GroupedReport from './components/GroupedReport'
+import numeral from 'numeral'
+import Report from './components/Report'
 import ReportsFilter from './components/ReportsFilter'
 
 export default {
-  components: { TimelineItem, ReportsFilter },
+  components: { GroupedReport, Report, ReportsFilter },
   computed: {
+    groupedReports() {
+      return this.$store.state.reports.fetchedGroupedReports
+    },
+    groupReports: {
+      get() {
+        return this.$store.state.reports.groupReports
+      },
+      set() {
+        this.toggleReportsGrouping()
+      }
+    },
     loading() {
-      return this.$store.state.users.loading
+      return this.$store.state.reports.loading
+    },
+    normalizedReportsCount() {
+      return this.groupReports
+        ? numeral(this.$store.state.reports.fetchedGroupedReports.length).format('0a')
+        : numeral(this.$store.state.reports.totalReportsCount).format('0a')
     },
     reports() {
       return this.$store.state.reports.fetchedReports
     }
   },
   mounted() {
-    this.$store.dispatch('FetchReports')
-  },
-  created() {
-    window.addEventListener('scroll', this.handleScroll)
-  },
-  destroyed() {
-    window.removeEventListener('scroll', this.handleScroll)
+    this.$store.dispatch('FetchReports', 1)
+    this.$store.dispatch('FetchGroupedReports')
   },
   methods: {
-    handleScroll(reports) {
-      const bottomOfWindow = document.documentElement.scrollHeight - document.documentElement.scrollTop === document.documentElement.clientHeight
-      if (bottomOfWindow) {
-        this.$store.dispatch('FetchReports')
-      }
+    toggleReportsGrouping() {
+      this.$store.dispatch('ToggleReportsGrouping')
     }
   }
 }
@@ -56,16 +75,24 @@ export default {
     padding: 0px;
   }
   .filter-container {
+    display: flex;
+    flex-direction: column;
     margin: 22px 15px 22px 15px;
     padding-bottom: 0
   }
+  .group-reports-checkbox {
+    margin-top: 10px;
+  }
   h1 {
     margin: 22px 0 0 15px;
   }
   .no-reports-message {
     color: gray;
     margin-left: 19px
-
+  }
+  .report-count {
+    color: gray;
+    font-size: 28px;
   }
 }
 @media
@@ -78,9 +105,9 @@ only screen and (max-width: 760px),
     .filter-container {
       margin: 0 10px
     }
-    .timeline {
-      margin: 20px 20px 20px 18px
-    }
+  }
+  #app > div > div.main-container > section > div > div.block > ul {
+    margin: 45px 45px 5px 19px;
   }
 }
 </style>
diff --git a/src/views/status/Status.vue b/src/views/status/Status.vue
new file mode 100644
index 0000000000000000000000000000000000000000..b33744b1db2f60e7ae764c45214c796b3bda7b90
--- /dev/null
+++ b/src/views/status/Status.vue
@@ -0,0 +1,269 @@
+<template>
+  <div>
+    <el-card v-if="!status.deleted" class="status-card">
+      <div slot="header">
+        <div class="status-header">
+          <div class="status-account-container">
+            <div class="status-account">
+              <img :src="status.account.avatar" class="status-avatar-img">
+              <h3 class="status-account-name">{{ status.account.display_name }}</h3>
+            </div>
+            <a :href="status.account.url" target="_blank" class="account">
+              @{{ status.account.acct }}
+            </a>
+          </div>
+          <div class="status-actions">
+            <el-tag v-if="status.sensitive" type="warning" size="large">{{ $t('reports.sensitive') }}</el-tag>
+            <el-tag size="large">{{ capitalizeFirstLetter(status.visibility) }}</el-tag>
+            <el-dropdown trigger="click">
+              <el-button plain size="small" icon="el-icon-edit" class="status-actions-button">
+                {{ $t('reports.changeScope') }}<i class="el-icon-arrow-down el-icon--right"/>
+              </el-button>
+              <el-dropdown-menu slot="dropdown">
+                <el-dropdown-item
+                  v-if="!status.sensitive"
+                  @click.native="changeStatus(status.id, true, status.visibility)">
+                  {{ $t('reports.addSensitive') }}
+                </el-dropdown-item>
+                <el-dropdown-item
+                  v-if="status.sensitive"
+                  @click.native="changeStatus(status.id, false, status.visibility)">
+                  {{ $t('reports.removeSensitive') }}
+                </el-dropdown-item>
+                <el-dropdown-item
+                  v-if="status.visibility !== 'public'"
+                  @click.native="changeStatus(status.id, status.sensitive, 'public')">
+                  {{ $t('reports.public') }}
+                </el-dropdown-item>
+                <el-dropdown-item
+                  v-if="status.visibility !== 'private'"
+                  @click.native="changeStatus(status.id, status.sensitive, 'private')">
+                  {{ $t('reports.private') }}
+                </el-dropdown-item>
+                <el-dropdown-item
+                  v-if="status.visibility !== 'unlisted'"
+                  @click.native="changeStatus(status.id, status.sensitive, 'unlisted')">
+                  {{ $t('reports.unlisted') }}
+                </el-dropdown-item>
+                <el-dropdown-item
+                  @click.native="deleteStatus(status.id)">
+                  {{ $t('reports.deleteStatus') }}
+                </el-dropdown-item>
+              </el-dropdown-menu>
+            </el-dropdown>
+          </div>
+        </div>
+      </div>
+      <div class="status-body">
+        <div v-if="status.spoiler_text">
+          <strong>{{ status.spoiler_text }}</strong>
+          <el-button v-if="!showHiddenStatus" size="mini" class="show-more-button" @click="showHiddenStatus = true">Show more</el-button>
+          <el-button v-if="showHiddenStatus" size="mini" class="show-more-button" @click="showHiddenStatus = false">Show less</el-button>
+          <div v-if="showHiddenStatus">
+            <span class="status-content" v-html="status.content"/>
+            <div v-if="status.poll" class="poll">
+              <ul>
+                <li v-for="(option, index) in status.poll.options" :key="index">
+                  {{ option.title }}
+                  <el-progress :percentage="optionPercent(status.poll, option)" />
+                </li>
+              </ul>
+            </div>
+            <div v-for="(attachment, index) in status.media_attachments" :key="index" class="image">
+              <img :src="attachment.preview_url">
+            </div>
+          </div>
+        </div>
+        <div v-if="!status.spoiler_text">
+          <span class="status-content" v-html="status.content"/>
+          <div v-if="status.poll" class="poll">
+            <ul>
+              <li v-for="(option, index) in status.poll.options" :key="index">
+                {{ option.title }}
+                <el-progress :percentage="optionPercent(status.poll, option)" />
+              </li>
+            </ul>
+          </div>
+          <div v-for="(attachment, index) in status.media_attachments" :key="index" class="image">
+            <img :src="attachment.preview_url">
+          </div>
+        </div>
+        <a :href="status.url" target="_blank" class="account">
+          {{ parseTimestamp(status.created_at) }}
+        </a>
+      </div>
+    </el-card>
+    <el-card v-else class="status-card">
+      <div slot="header">
+        <div class="status-header">
+          <div class="status-account-container">
+            <div class="status-account">
+              <h4 class="status-deleted">{{ $t('reports.statusDeleted') }}</h4>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="status-body">
+        <span v-if="status.content" class="status-content" v-html="status.content"/>
+        <span v-else class="status-without-content">no content</span>
+      </div>
+      <a v-if="status.created_at" :href="status.url" target="_blank" class="account">
+        {{ parseTimestamp(status.created_at) }}
+      </a>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import moment from 'moment'
+
+export default {
+  name: 'Status',
+  props: {
+    status: {
+      type: Object,
+      required: true
+    },
+    page: {
+      type: Number,
+      required: false,
+      default: 0
+    },
+    userId: {
+      type: String,
+      required: false,
+      default: ''
+    },
+    godmode: {
+      type: Boolean,
+      required: false,
+      default: false
+    }
+  },
+  data() {
+    return {
+      showHiddenStatus: false
+    }
+  },
+  methods: {
+    capitalizeFirstLetter(str) {
+      return str.charAt(0).toUpperCase() + str.slice(1)
+    },
+    changeStatus(statusId, isSensitive, visibility) {
+      this.$store.dispatch('ChangeStatusScope', { statusId, isSensitive, visibility, reportCurrentPage: this.page, userId: this.userId, godmode: this.godmode })
+    },
+    deleteStatus(statusId) {
+      this.$confirm('Are you sure you want to delete this status?', 'Warning', {
+        confirmButtonText: 'OK',
+        cancelButtonText: 'Cancel',
+        type: 'warning'
+      }).then(() => {
+        this.$store.dispatch('DeleteStatus', { statusId, reportCurrentPage: this.page, userId: this.userId, godmode: this.godmode })
+        this.$message({
+          type: 'success',
+          message: 'Delete completed'
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: 'Delete canceled'
+        })
+      })
+    },
+    optionPercent(poll, pollOption) {
+      const allVotes = poll.options.reduce((acc, option) => (acc + option.votes_count), 0)
+      if (allVotes === 0) {
+        return 0
+      }
+      return +(pollOption.votes_count / allVotes * 100).toFixed(1)
+    },
+    parseTimestamp(timestamp) {
+      return moment(timestamp).format('YYYY-MM-DD HH:mm')
+    }
+  }
+}
+</script>
+
+<style rel='stylesheet/scss' lang='scss'>
+.account {
+  text-decoration: underline;
+  line-height: 26px;
+  font-size: 13px;
+}
+.image {
+  width: 20%;
+  img {
+    width: 100%;
+  }
+}
+.show-more-button {
+  margin-left: 5px;
+}
+.status-account {
+  display: flex;
+  align-items: center;
+}
+.status-avatar-img {
+  width: 15px;
+  height: 15px;
+  margin-right: 5px;
+}
+.status-account-name {
+  margin: 0;
+  height: 22px;
+}
+.status-body {
+  display: flex;
+  flex-direction: column;
+}
+.status-content {
+  font-size: 15px;
+  line-height: 26px;
+}
+.status-card {
+  margin-bottom: 15px;
+}
+.status-deleted {
+  font-style: italic;
+  margin-top: 3px;
+}
+.status-header {
+  display: flex;
+  justify-content: space-between;
+}
+.status-without-content {
+  font-style: italic;
+}
+@media
+only screen and (max-width: 760px),
+(min-device-width: 768px) and (max-device-width: 1024px) {
+  .el-message {
+    min-width: 80%;
+  }
+  .el-message-box {
+    width: 80%;
+  }
+  .status-card {
+    .el-card__header {
+      padding: 10px 17px;
+    }
+    .el-tag {
+      margin: 3px 4px 3px 0;
+    }
+    .status-account-container {
+      margin-bottom: 5px;
+    }
+    .status-actions-button {
+      margin: 3px 0 3px;
+    }
+    .status-actions {
+      display: flex;
+      flex-wrap: wrap;
+    }
+    .status-header {
+      display: flex;
+      flex-direction: column;
+    }
+  }
+}
+</style>
diff --git a/src/views/users/show.vue b/src/views/users/show.vue
index 7c733d13a1511aa3ede225d6645fe16bf9078371..f721a7f5aeab06616d9cea7d0fe6f4cfb1f27325 100644
--- a/src/views/users/show.vue
+++ b/src/views/users/show.vue
@@ -1,5 +1,5 @@
 <template>
-  <main v-if="!loading">
+  <main v-if="!userProfileLoading">
     <header>
       <el-avatar :src="user.avatar" size="large" />
       <h1>{{ user.display_name }}</h1>
@@ -71,23 +71,9 @@
         </el-col>
       </el-row>
       <el-col :span="18">
-        <el-timeline class="statuses">
-          <el-timeline-item v-for="status in statuses" :timestamp="createdAtLocaleString(status.created_at)" :key="status.id">
-            <el-card>
-              <strong v-if="status.spoiler_text">{{ status.spoiler_text }}</strong>
-              <p v-if="status.content" v-html="status.content" />
-              <div v-if="status.poll" class="poll">
-                <ul>
-                  <li v-for="(option, index) in status.poll.options" :key="index">
-                    {{ option.title }}
-                    <el-progress :percentage="optionPercent(status.poll, option)" />
-                  </li>
-                </ul>
-              </div>
-              <div v-for="(attachment, index) in status.media_attachments" :key="index" class="image">
-                <img :src="attachment.preview_url">
-              </div>
-            </el-card>
+        <el-timeline v-if="!statusesLoading" class="statuses">
+          <el-timeline-item v-for="status in statuses" :key="status.id">
+            <status :status="status" :user-id="user.id" :godmode="showPrivate"/>
           </el-timeline-item>
         </el-timeline>
       </el-col>
@@ -96,45 +82,36 @@
 </template>
 
 <script>
+import Status from '../status/Status'
+
 export default {
   name: 'UsersShow',
+  components: { Status },
   data() {
     return {
       showPrivate: false
     }
   },
   computed: {
-    loading() {
-      return this.$store.state.userProfile.loading
+    statuses() {
+      return this.$store.state.userProfile.statuses
+    },
+    statusesLoading() {
+      return this.$store.state.userProfile.statusesLoading
     },
     user() {
       return this.$store.state.userProfile.user
     },
-    statuses() {
-      return this.$store.state.userProfile.statuses
+    userProfileLoading() {
+      return this.$store.state.userProfile.userProfileLoading
     }
   },
   mounted: function() {
-    this.$store.dispatch('FetchData', { id: this.$route.params.id, godmode: false })
+    this.$store.dispatch('FetchUserProfile', { userId: this.$route.params.id, godmode: false })
   },
   methods: {
-    optionPercent(poll, pollOption) {
-      const allVotes = poll.options.reduce((acc, option) => (acc + option.votes_count), 0)
-      if (allVotes === 0) {
-        return 0
-      }
-
-      return +(pollOption.votes_count / allVotes * 100).toFixed(1)
-    },
-    createdAtLocaleString(createdAt) {
-      const date = new Date(createdAt)
-
-      return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`
-    },
     onTogglePrivate() {
-      console.log(this.showPrivate)
-
-      this.$store.dispatch('FetchData', { id: this.$route.params.id, godmode: this.showPrivate })
+      this.$store.dispatch('FetchUserProfile', { userId: this.$route.params.id, godmode: this.showPrivate })
     }
   }
 }
diff --git a/test/views/reports/groupedReport.test.js b/test/views/reports/groupedReport.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..b24d05e45ffaeec29447517c8170f8c9531f7d05
--- /dev/null
+++ b/test/views/reports/groupedReport.test.js
@@ -0,0 +1,47 @@
+import Vuex from 'vuex'
+import { mount, createLocalVue, config } from '@vue/test-utils'
+import Element from 'element-ui'
+import GroupedReport from '@/views/reports/components/GroupedReport'
+import storeConfig from './store.conf'
+import { cloneDeep } from 'lodash'
+import flushPromises from 'flush-promises'
+
+config.mocks["$t"] = () => {}
+
+const localVue = createLocalVue()
+localVue.use(Vuex)
+localVue.use(Element)
+
+jest.mock('@/api/reports')
+
+describe('Grouped report', () => {
+  let store
+
+  beforeEach(async() => {
+    store = new Vuex.Store(cloneDeep(storeConfig))
+    store.dispatch('FetchGroupedReports')
+    await flushPromises()
+  })
+
+  it('changes state of all reports in a group', async (done) => {
+    const groupedReports = store.state.reports.fetchedGroupedReports
+    const wrapper = mount(GroupedReport, {
+      store,
+      localVue,
+      propsData: {
+        groupedReports
+      }
+    })
+
+    expect(groupedReports[0].reports[0].state).toBe('open')
+    expect(groupedReports[0].reports[1].state).toBe('resolved')
+
+    const button = wrapper.find(`.grouped-report .el-dropdown-menu__item:nth-child(3)`)
+    button.trigger('click')
+    await flushPromises()
+
+    expect(store.state.reports.fetchedGroupedReports[0].reports[0].state).toBe('closed')
+    expect(store.state.reports.fetchedGroupedReports[0].reports[1].state).toBe('closed')
+    done()
+  })
+})
diff --git a/test/views/reports/index.test.js b/test/views/reports/index.test.js
index cb1f10dad5ab8ac82066279e97c965b69a11ee3d..eab73c81ca196919f67fd8ee0970b1007165fe9b 100644
--- a/test/views/reports/index.test.js
+++ b/test/views/reports/index.test.js
@@ -31,22 +31,7 @@ describe('Reports', () => {
 
     await flushPromises()
     const initialReports = store.state.reports.fetchedReports.length
-    expect(initialReports).toEqual(5)
-    done()
-  })
-
-  it('loads more reports on scroll', async (done) => {
-    const wrapper = mount(Reports, {
-      store,
-      localVue
-    })
-
-    await flushPromises()
-    expect(store.state.reports.fetchedReports.length).toEqual(5)
-
-    window.dispatchEvent(new CustomEvent('scroll', { detail: 2000 }))
-    await flushPromises()
-    expect(store.state.reports.fetchedReports.length).toEqual(7)
+    expect(initialReports).toEqual(7)
     done()
   })
 })
diff --git a/test/views/reports/report.test.js b/test/views/reports/report.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..cc91c6ca5f3ee656e657fffd93a50597bf5e9a80
--- /dev/null
+++ b/test/views/reports/report.test.js
@@ -0,0 +1,75 @@
+import Vuex from 'vuex'
+import { mount, createLocalVue, config } from '@vue/test-utils'
+import Element from 'element-ui'
+import Report from '@/views/reports/components/Report'
+import storeConfig from './store.conf'
+import { cloneDeep } from 'lodash'
+import flushPromises from 'flush-promises'
+
+config.mocks["$t"] = () => {}
+
+const localVue = createLocalVue()
+localVue.use(Vuex)
+localVue.use(Element)
+
+jest.mock('@/api/reports')
+
+describe('Report in a timeline', () => {
+  let store
+
+  beforeEach(async() => {
+    store = new Vuex.Store(cloneDeep(storeConfig))
+    store.dispatch('FetchReports')
+    await flushPromises()
+  })
+
+  it('changes report state from open to resolved', async (done) => {
+    const reports = store.state.reports.fetchedReports
+    const wrapper = mount(Report, {
+      store,
+      localVue,
+      propsData: {
+        reports
+      }
+    })
+    expect(reports[0].state).toBe('open')
+
+    const button = wrapper.find(`li.el-timeline-item:nth-child(1) li.el-dropdown-menu__item:nth-child(1)`)
+    button.trigger('click')
+    await flushPromises()
+    expect(store.state.reports.fetchedReports[0].state).toBe('resolved')
+    done()
+  })
+
+  it('changes report state from open to closed', async (done) => {
+    const reports = store.state.reports.fetchedReports
+    const wrapper = mount(Report, {
+      store,
+      localVue,
+      propsData: {
+        reports
+      }
+    })
+    expect(reports[3].state).toBe('open')
+
+    const button = wrapper.find(`li.el-timeline-item:nth-child(4) li.el-dropdown-menu__item:nth-child(2)`)
+    button.trigger('click')
+    await flushPromises()
+    expect(store.state.reports.fetchedReports[3].state).toBe('closed')
+    done()
+  })
+
+  it('shows statuses', () => {
+    const reports = store.state.reports.fetchedReports
+    const wrapper = mount(Report, {
+      store,
+      localVue,
+      propsData: {
+        reports
+      }
+    })
+
+    const statuses = wrapper.findAll(`.status-card`)
+    expect(statuses.length).toEqual(2)
+  })
+})
diff --git a/test/views/reports/reportsFilter.test.js b/test/views/reports/reportsFilter.test.js
index 60e9147adf21e018ce11c6845d34c13cc9e44f09..0701262cbb11319043313f2b5635eea532e27fd5 100644
--- a/test/views/reports/reportsFilter.test.js
+++ b/test/views/reports/reportsFilter.test.js
@@ -24,11 +24,11 @@ describe('Reports filter', () => {
   })
 
   it('shows open reports when "Open" filter is applied', async (done) => {
-    expect(store.state.reports.fetchedReports.length).toEqual(5)
+    expect(store.state.reports.fetchedReports.length).toEqual(7)
 
     store.dispatch('SetFilter', 'open')
     store.dispatch('ClearFetchedReports')
-    store.dispatch('FetchReports')
+    store.dispatch('FetchReports', 1)
     await flushPromises()
     expect(store.state.reports.fetchedReports.length).toEqual(2)
 
@@ -36,7 +36,7 @@ describe('Reports filter', () => {
   })
 
   it('shows resolved reports when "Resolved" filter is applied', async (done) => {
-    expect(store.state.reports.fetchedReports.length).toEqual(5)
+    expect(store.state.reports.fetchedReports.length).toEqual(7)
 
     store.dispatch('SetFilter', 'resolved')
     store.dispatch('ClearFetchedReports')
@@ -48,7 +48,7 @@ describe('Reports filter', () => {
   })
 
   it('shows closed reports when "Closed" filter is applied', async (done) => {
-    expect(store.state.reports.fetchedReports.length).toEqual(5)
+    expect(store.state.reports.fetchedReports.length).toEqual(7)
 
     store.dispatch('SetFilter', 'closed')
     store.dispatch('ClearFetchedReports')
@@ -60,7 +60,7 @@ describe('Reports filter', () => {
   })
 
   it('shows all users after removing filters', async (done) => {
-    expect(store.state.reports.fetchedReports.length).toEqual(5)
+    expect(store.state.reports.fetchedReports.length).toEqual(7)
 
     store.dispatch('SetFilter', 'open')
     store.dispatch('ClearFetchedReports')
@@ -72,7 +72,7 @@ describe('Reports filter', () => {
     store.dispatch('ClearFetchedReports')
     store.dispatch('FetchReports')
     await flushPromises()
-    expect(store.state.reports.fetchedReports.length).toEqual(5)
+    expect(store.state.reports.fetchedReports.length).toEqual(7)
 
     done()
   })
diff --git a/test/views/reports/status.test.js b/test/views/reports/status.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..2414fa8e375266fb458b22f046e84af0a28ea39b
--- /dev/null
+++ b/test/views/reports/status.test.js
@@ -0,0 +1,151 @@
+import Vuex from 'vuex'
+import { mount, createLocalVue, config } from '@vue/test-utils'
+import Element from 'element-ui'
+import Status from '@/views/status/Status'
+import storeConfig from './store.conf'
+import { cloneDeep } from 'lodash'
+import flushPromises from 'flush-promises'
+
+config.mocks["$t"] = () => {}
+
+const localVue = createLocalVue()
+localVue.use(Vuex)
+localVue.use(Element)
+
+jest.mock('@/api/reports')
+jest.mock('@/api/status')
+
+describe('Status in reports', () => {
+  let store
+
+  beforeEach(async() => {
+    store = new Vuex.Store(cloneDeep(storeConfig))
+    store.dispatch('FetchReports', 1)
+    await flushPromises()
+  })
+
+  it('adds sensitive flag to a status', async (done) => {
+    const status = store.state.reports.fetchedReports[4].statuses[0]
+    const wrapper = mount(Status, {
+      store,
+      localVue,
+      propsData: {
+        status,
+        page: 1,
+        userId: '7',
+        godmode: false
+      }
+    })
+    await flushPromises()
+
+    const changeStatusStub = jest.fn()
+    wrapper.setMethods({ changeStatus: changeStatusStub })
+
+    const button = wrapper.find(`li.el-dropdown-menu__item:nth-child(1)`)
+    button.trigger('click')
+
+    expect(wrapper.vm.changeStatus).toHaveBeenCalled()
+    expect(wrapper.vm.changeStatus).toHaveBeenCalledWith('11', true, 'public')
+    done()
+  })
+
+  it('removes sensitive flag to a status', async (done) => {
+    const status = store.state.reports.fetchedReports[4].statuses[1]
+    const wrapper = mount(Status, {
+      store,
+      localVue,
+      propsData: {
+        status,
+        page: 1,
+        userId: '7',
+        godmode: false
+      }
+    })
+    await flushPromises()
+
+    const changeStatusStub = jest.fn()
+    wrapper.setMethods({ changeStatus: changeStatusStub })
+
+    const button = wrapper.find(`li.el-dropdown-menu__item:nth-child(1)`)
+    button.trigger('click')
+
+    expect(wrapper.vm.changeStatus).toHaveBeenCalled()
+    expect(wrapper.vm.changeStatus).toHaveBeenCalledWith('10', false, 'unlisted')
+    done()
+  })
+
+  it('changes status visibility from public to unlisted', async (done) => {
+    const status = store.state.reports.fetchedReports[4].statuses[0]
+    const wrapper = mount(Status, {
+      store,
+      localVue,
+      propsData: {
+        status,
+        page: 1,
+        userId: '7',
+        godmode: false
+      }
+    })
+    await flushPromises()
+
+    const changeStatusStub = jest.fn()
+    wrapper.setMethods({ changeStatus: changeStatusStub })
+
+    const button = wrapper.find(`li.el-dropdown-menu__item:nth-child(3)`)
+    button.trigger('click')
+
+    expect(wrapper.vm.changeStatus).toHaveBeenCalled()
+    expect(wrapper.vm.changeStatus).toHaveBeenCalledWith('11', false, 'unlisted')
+    done()
+  })
+
+  it('changes status visibility from unlisted to private', async (done) => {
+    const status = store.state.reports.fetchedReports[4].statuses[1]
+    const wrapper = mount(Status, {
+      store,
+      localVue,
+      propsData: {
+        status,
+        page: 1,
+        userId: '7',
+        godmode: false
+      }
+    })
+    await flushPromises()
+
+    const changeStatusStub = jest.fn()
+    wrapper.setMethods({ changeStatus: changeStatusStub })
+
+    const button = wrapper.find(`li.el-dropdown-menu__item:nth-child(3)`)
+    button.trigger('click')
+
+    expect(wrapper.vm.changeStatus).toHaveBeenCalled()
+    expect(wrapper.vm.changeStatus).toHaveBeenCalledWith('10', true, 'private')
+    done()
+  })
+
+  it('deletes a status', async (done) => {
+    const status = store.state.reports.fetchedReports[4].statuses[1]
+    const wrapper = mount(Status, {
+      store,
+      localVue,
+      propsData: {
+        status,
+        page: 1,
+        userId: '7',
+        godmode: false
+      }
+    })
+    await flushPromises()
+
+    const deleteStatusStub = jest.fn()
+    wrapper.setMethods({ deleteStatus: deleteStatusStub })
+
+    const button = wrapper.find(`li.el-dropdown-menu__item:nth-child(4)`)
+    button.trigger('click')
+
+    expect(wrapper.vm.deleteStatus).toHaveBeenCalled()
+    expect(wrapper.vm.deleteStatus).toHaveBeenCalledWith('10')
+    done()
+  })
+})
diff --git a/test/views/reports/store.conf.js b/test/views/reports/store.conf.js
index a961ccca32ba18cb87f2869e632929214269bf08..72117897b11c69ffdb33af4572dea3008f2b48d1 100644
--- a/test/views/reports/store.conf.js
+++ b/test/views/reports/store.conf.js
@@ -2,6 +2,7 @@ import app from '@/store/modules/app'
 import user from '@/store/modules/user'
 import users from '@/store/modules/users'
 import reports from '@/store/modules/reports'
+import status from '@/store/modules/status'
 import getters from '@/store/getters'
 
 export default {
@@ -9,7 +10,8 @@ export default {
     app,
     user,
     users,
-    reports
+    reports,
+    status
   },
   getters
 }
diff --git a/test/views/reports/timelineItem.test.js b/test/views/reports/timelineItem.test.js
deleted file mode 100644
index 6e3b9f01ce3e6aba1d90a618c8b90470f67e5d5e..0000000000000000000000000000000000000000
--- a/test/views/reports/timelineItem.test.js
+++ /dev/null
@@ -1,157 +0,0 @@
-import Vuex from 'vuex'
-import { mount, createLocalVue, config } from '@vue/test-utils'
-import Element from 'element-ui'
-import TimelineItem from '@/views/reports/components/TimelineItem'
-import storeConfig from './store.conf'
-import { cloneDeep } from 'lodash'
-import flushPromises from 'flush-promises'
-
-config.mocks["$t"] = () => {}
-
-const localVue = createLocalVue()
-localVue.use(Vuex)
-localVue.use(Element)
-
-jest.mock('@/api/reports')
-
-describe('Report in a timeline', () => {
-  let store
-
-  beforeEach(async() => {
-    store = new Vuex.Store(cloneDeep(storeConfig))
-    store.dispatch('FetchReports')
-    await flushPromises()
-  })
-
-  it('changes report state from open to resolved', async (done) => {
-    const report = store.state.reports.fetchedReports[0]
-    const wrapper = mount(TimelineItem, {
-      store,
-      localVue,
-      propsData: {
-        report: report
-      }
-    })
-    expect(report.state).toBe('open')
-
-    const button = wrapper.find(`li.el-dropdown-menu__item:nth-child(${1})`)
-    button.trigger('click')
-    await flushPromises()
-    expect(store.state.reports.fetchedReports[0].state).toBe('resolved')
-    done()
-  })
-
-  it('changes report state from open to closed', async (done) => {
-    const report = store.state.reports.fetchedReports[3]
-    const wrapper = mount(TimelineItem, {
-      store,
-      localVue,
-      propsData: {
-        report: report
-      }
-    })
-    expect(report.state).toBe('open')
-
-    const button = wrapper.find(`li.el-dropdown-menu__item:nth-child(${2})`)
-    button.trigger('click')
-    await flushPromises()
-    expect(store.state.reports.fetchedReports[3].state).toBe('closed')
-    done()
-  })
-
-  it('shows statuses', () => {
-    const report = store.state.reports.fetchedReports[4]
-    const wrapper = mount(TimelineItem, {
-      store,
-      localVue,
-      propsData: {
-        report: report
-      }
-    })
-
-    const statuses = wrapper.findAll(`.status-card`)
-    expect(statuses.length).toEqual(2)
-  })
-
-  it('adds sensitive flag to a status', async (done) => {
-    const report = store.state.reports.fetchedReports[4]
-    const wrapper = mount(TimelineItem, {
-      store,
-      localVue,
-      propsData: {
-        report: report
-      }
-    })
-    expect(report.statuses[0].sensitive).toBe(false)
-
-    const button = wrapper.find(`.status-card li.el-dropdown-menu__item`)
-    button.trigger('click')
-    await flushPromises()
-    expect(store.state.reports.fetchedReports[4].statuses[0].sensitive).toEqual(true)
-    done()
-  })
-
-  it('removes sensitive flag to a status', async (done) => {
-    const report = store.state.reports.fetchedReports[4]
-    const wrapper = mount(TimelineItem, {
-      store,
-      localVue,
-      propsData: {
-        report: report
-      }
-    })
-    expect(report.statuses[1].sensitive).toBe(true)
-
-    const button = wrapper.find(`.status-card:nth-child(${2}) li.el-dropdown-menu__item`)
-    button.trigger('click')
-    await flushPromises()
-    expect(store.state.reports.fetchedReports[4].statuses[1].sensitive).toEqual(false)
-    done()
-  })
-
-  it('changes status visibility from public to unlisted', async (done) => {
-    const report = store.state.reports.fetchedReports[4]
-    const wrapper = mount(TimelineItem, {
-      store,
-      localVue,
-      propsData: {
-        report: report
-      }
-    })
-    expect(report.statuses[0].visibility).toBe('public')
-
-    const button = wrapper.find(`.status-card li.el-dropdown-menu__item:nth-child(${3})`)
-    button.trigger('click')
-    await flushPromises()
-    expect(store.state.reports.fetchedReports[4].statuses[0].visibility).toEqual('unlisted')
-    done()
-  })
-
-  it('changes status visibility from unlisted to private', async (done) => {
-    const report = store.state.reports.fetchedReports[4]
-    const wrapper = mount(TimelineItem, {
-      store,
-      localVue,
-      propsData: {
-        report: report
-      }
-    })
-    expect(report.statuses[1].visibility).toBe('unlisted')
-
-    const button = wrapper.find(`.status-card:nth-child(${2}) li.el-dropdown-menu__item:nth-child(${3})`)
-    button.trigger('click')
-    await flushPromises()
-    expect(store.state.reports.fetchedReports[4].statuses[1].visibility).toEqual('private')
-    done()
-  })
-
-  it('deletes a status', async (done) => {
-    const report = store.state.reports.fetchedReports[4]
-    expect(report.statuses.length).toEqual(2)
-
-    store.dispatch('DeleteStatus', { statusId: '11', reportId: '7'})
-    await flushPromises()
-    expect(store.state.reports.fetchedReports[4].statuses.length).toEqual(1)
-    done()
-  })
-})