RecentActivity.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <template>
  2. <div class="content recent-activity-tab">
  3. <div v-if="activities.length > 0">
  4. <h4 class="section-title">Recent activity</h4>
  5. <p class="section-description">
  6. This is a log of all actions
  7. {{ userId === myUserId ? "you have" : `${username} has` }}
  8. taken recently.
  9. </p>
  10. <hr class="section-horizontal-rule" />
  11. <div id="activity-items" @scroll="handleScroll">
  12. <activity-item
  13. class="item activity-item universal-item"
  14. v-for="activity in activities"
  15. :key="activity._id"
  16. :activity="activity"
  17. >
  18. <template #actions>
  19. <confirm
  20. v-if="userId === myUserId"
  21. @confirm="hideActivity(activity._id)"
  22. >
  23. <a content="Hide Activity" v-tippy>
  24. <i class="material-icons hide-icon"
  25. >visibility_off</i
  26. >
  27. </a>
  28. </confirm>
  29. </template>
  30. </activity-item>
  31. </div>
  32. </div>
  33. <div v-else>
  34. <h3>No recent activity.</h3>
  35. </div>
  36. </div>
  37. </template>
  38. <script>
  39. import { mapState, mapGetters, mapActions } from "vuex";
  40. import Toast from "toasters";
  41. import ActivityItem from "@/components/ActivityItem.vue";
  42. import ws from "@/ws";
  43. import Confirm from "@/components/Confirm.vue";
  44. export default {
  45. components: { ActivityItem, Confirm },
  46. props: {
  47. userId: {
  48. type: String,
  49. default: ""
  50. }
  51. },
  52. data() {
  53. return {
  54. username: "",
  55. activities: [],
  56. position: 1,
  57. maxPosition: 1,
  58. offsettedFromNextSet: 0,
  59. isGettingSet: false
  60. };
  61. },
  62. computed: {
  63. ...mapState({
  64. ...mapState("modalVisibility", {
  65. modals: state => state.modals
  66. }),
  67. myUserId: state => state.user.auth.userId
  68. }),
  69. ...mapGetters({
  70. socket: "websockets/getSocket"
  71. })
  72. },
  73. mounted() {
  74. if (this.myUserId !== this.userId) {
  75. ws.onConnect(() =>
  76. this.socket.dispatch(
  77. "apis.joinRoom",
  78. `profile.${this.userId}.activities`
  79. )
  80. );
  81. this.getUsernameFromId(this.userId).then(username => {
  82. if (username) this.username = username;
  83. });
  84. }
  85. this.socket.dispatch("activities.length", this.userId, res => {
  86. if (res.status === "success") {
  87. this.maxPosition = Math.ceil(res.data.length / 15) + 1;
  88. this.getSet();
  89. }
  90. });
  91. this.socket.on("event:activity.updated", res => {
  92. this.activities.find(
  93. activity => activity._id === res.data.activityId
  94. ).payload.message = res.data.message;
  95. });
  96. this.socket.on("event:activity.created", res => {
  97. this.activities.unshift(res.data.activity);
  98. this.offsettedFromNextSet += 1;
  99. });
  100. this.socket.on("event:activity.hidden", res => {
  101. this.activities = this.activities.filter(
  102. activity => activity._id !== res.data.activityId
  103. );
  104. this.offsettedFromNextSet -= 1;
  105. });
  106. this.socket.on("event:activity.removeAllForUser", () => {
  107. this.activities = [];
  108. this.position = 1;
  109. this.maxPosition = 1;
  110. this.offsettedFromNextSet = 0;
  111. });
  112. },
  113. beforeUnmount() {
  114. this.socket.dispatch(
  115. "apis.leaveRoom",
  116. `profile.${this.userId}.activities`,
  117. () => {}
  118. );
  119. },
  120. methods: {
  121. hideActivity(activityId) {
  122. this.socket.dispatch("activities.hideActivity", activityId, res => {
  123. if (res.status !== "success") new Toast(res.message);
  124. });
  125. },
  126. getSet() {
  127. if (this.isGettingSet) return;
  128. if (this.position >= this.maxPosition) return;
  129. this.isGettingSet = true;
  130. this.socket.dispatch(
  131. "activities.getSet",
  132. this.userId,
  133. this.position,
  134. this.offsettedFromNextSet,
  135. res => {
  136. if (res.status === "success") {
  137. this.activities.push(...res.data.activities);
  138. this.position += 1;
  139. }
  140. this.isGettingSet = false;
  141. }
  142. );
  143. },
  144. handleScroll(event) {
  145. const scrollPosition =
  146. event.target.clientHeight + event.target.scrollTop;
  147. const bottomPosition = event.target.scrollHeight;
  148. if (this.loadAllSongs) return false;
  149. if (scrollPosition + 100 >= bottomPosition) this.getSet();
  150. return this.maxPosition === this.position;
  151. },
  152. ...mapActions("user/auth", ["getUsernameFromId"])
  153. }
  154. };
  155. </script>
  156. <style lang="scss" scoped>
  157. .night-mode #activity-items .activity-item {
  158. background-color: var(--dark-grey-2) !important;
  159. border: 0 !important;
  160. }
  161. #activity-items {
  162. overflow: auto;
  163. min-height: auto;
  164. max-height: 570px;
  165. }
  166. .content a {
  167. border-bottom: 0;
  168. }
  169. </style>