Skip to content

Commit

Permalink
Implement custom notifications
Browse files Browse the repository at this point in the history
You can now set custom notification settings for users, magazine, entries and posts: `Loud`, `Default` or `Muted`.

Move the logic of "fetch an endpoint and get html. Replace html node with selector x with the result of the fetch" to another controller, so it can be used outside of subjects (`Entry`, `EntryComment`, `Post` and `PostComment`)

# Conflicts:
#	config/packages/doctrine.yaml
  • Loading branch information
BentiGorlich committed Dec 10, 2024
1 parent 6bae56c commit 07863d2
Show file tree
Hide file tree
Showing 47 changed files with 907 additions and 221 deletions.
46 changes: 46 additions & 0 deletions assets/controllers/html_refresh_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Controller } from "@hotwired/stimulus";
import { fetch, ok } from "../utils/http";

/* stimulusFetch: 'lazy' */
export default class extends Controller {
/**
* Calls the address attached to the nearest link node. Replaces the outer html of the nearest `cssclass` parameter
* with the response from the link
*/
async linkCallback(event) {
event.preventDefault();
const { cssclass: cssClass, refreshlink: refreshLink, refreshselector: refreshSelector } = event.params

const a = event.target.closest('a');
let subjectController = this.application.getControllerForElementAndIdentifier(this.element, 'subject')

try {
if (subjectController) {
subjectController.loadingValue = true;
}

let response = await fetch(a.href);

response = await ok(response);
response = await response.json();

event.target.closest(`.${cssClass}`).outerHTML = response.html;

const refreshElement = this.element.querySelector(refreshSelector)

if (!!refreshLink && refreshLink !== "" && !!refreshElement) {
let response = await fetch(refreshLink);

response = await ok(response);
response = await response.json();
refreshElement.outerHTML = response.html;
}
} catch (e) {
console.error(e)
} finally {
if (subjectController) {
subjectController.loadingValue = false;
}
}
}
}
40 changes: 0 additions & 40 deletions assets/controllers/subject_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,46 +199,6 @@ export default class extends Controller {
}
}

/**
* Calls the address attached to the nearest link node. Replaces the outer html of the nearest `cssclass` parameter
* with the response from the link
*/
async linkCallback(event) {
const { cssclass: cssClass, refreshlink: refreshLink, refreshselector: refreshSelector } = event.params
event.preventDefault();

const a = event.target.closest('a');

try {
this.loadingValue = true;

let response = await fetch(a.href, {
method: 'GET',
});

response = await ok(response);
response = await response.json();

event.target.closest(`.${cssClass}`).outerHTML = response.html;

const refreshElement = this.element.querySelector(refreshSelector)
console.log("linkCallback refresh stuff", refreshLink, refreshSelector, refreshElement)

if (!!refreshLink && refreshLink !== "" && !!refreshElement) {
let response = await fetch(refreshLink, {
method: 'GET',
});

response = await ok(response);
response = await response.json();
refreshElement.outerHTML = response.html;
}
} catch (e) {
} finally {
this.loadingValue = false;
}
}

loadingValueChanged(val) {
const submitButton = this.containerTarget.querySelector('form button[type="submit"]');

Expand Down
1 change: 1 addition & 0 deletions assets/styles/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
@import 'components/infinite_scroll';
@import 'components/sidebar-subscriptions';
@import 'components/settings_row';
@import 'components/notification_switch';
@import 'pages/post_single';
@import 'pages/post_front';
@import 'pages/page_bookmarks';
Expand Down
2 changes: 1 addition & 1 deletion assets/styles/components/_entry.scss
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@
text-decoration: underline;
}

button, input[type='submit'], a {
button, input[type='submit'], a:not(.notification-setting) {
@include mbin-btn-link;
}
}
Expand Down
5 changes: 4 additions & 1 deletion assets/styles/components/_magazine.scss
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,14 @@
}
}

&__description {
margin-top: 2.5rem;
}

&__subscribe {
display: flex;
flex-direction: row;
justify-content: center;
margin-bottom: 2.5rem;
flex-wrap: wrap;

div {
Expand Down
58 changes: 58 additions & 0 deletions assets/styles/components/_notification_switch.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.notification-switch-container .notification-switch {
align-items: center;
justify-content: center;
}

.entry-info,
.user-main {
.notification-switch > * {
opacity: .75;
}
}

footer .notification-switch {
padding: 0.25em 0;
margin-top: 0;
line-height: 1.25em;
}

.notification-switch {
display: flex;
flex-direction: row;
margin-top: .25em;
line-height: 1.5;

>* {
cursor: pointer;
padding: .25em .375em;
border: var(--kbin-button-secondary-border);
background: var(--kbin-button-secondary-bg);
color: var(--kbin-button-secondary-text-color);

&:hover:not(.active) {
background: var(--kbin-button-secondary-hover-bg);
color: var(--kbin-button-secondary-text-hover-color);
}

&.active {
cursor: unset;
background: var(--kbin-button-primary-bg);
color: var(--kbin-button-primary-text-color);

&:hover {
background: var(--kbin-button-primary-hover-bg);
color: var(--kbin-button-primary-text-hover-color);
}
}

&:last-child {
border-radius: 0 1em 1em 0;
padding-right: .75em;
}

&:first-child {
border-radius: 1em 0 0 1em;
padding-left: .75em;
}
}
}
4 changes: 2 additions & 2 deletions assets/styles/components/_popover.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
z-index: var(--z-index-popover, 25);

a {
color: var(--kbin-meta-link-color) !important;
color: var(--kbin-meta-link-color);
line-height: normal;
display: inline-block;

&:hover {
color: var(--kbin-meta-link-color-hover) !important;
color: var(--kbin-meta-link-color-hover);
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions assets/styles/components/_post.scss
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
margin-bottom: 0;
opacity: .75;

a {
a:not(.notification-setting) {
color: var(--kbin-meta-link-color);
font-weight: bold;

Expand All @@ -72,7 +72,7 @@
}
}

aside {
aside:not(.notification-switch) {
grid-area: vote;
}

Expand Down Expand Up @@ -131,13 +131,13 @@
line-height: 1rem;
}

& > a.active,
& > a:not(.notification-setting).active,
& > li button.active {
text-decoration: underline;
}

button,
a {
a:not(.notification-setting) {
font-size: .8rem;
@include mbin-btn-link;
}
Expand All @@ -147,7 +147,7 @@
}
}

a {
a:not(.notification-setting) {
@include mbin-btn-link;
}

Expand Down
6 changes: 5 additions & 1 deletion assets/styles/components/_sidebar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@
}
}

a {
a:not(.notification-setting) {
color: var(--kbin-meta-link-color);
}

Expand All @@ -257,6 +257,10 @@
}
}

.entry-info ul.info {
margin-top: 2.5rem;
}

.settings {
display: flex;
gap: 1rem;
Expand Down
1 change: 0 additions & 1 deletion assets/styles/components/_user.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
display: flex;
flex-direction: row;
justify-content: center;
margin-bottom: 2.5rem;
opacity: .75;

div {
Expand Down
2 changes: 1 addition & 1 deletion assets/styles/layout/_section.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
margin-bottom: .5rem;
padding: 2rem 1rem;

a {
a:not(.notification-setting) {
color: var(--kbin-section-title-link-color);
overflow-wrap: anywhere;

Expand Down
6 changes: 6 additions & 0 deletions config/mbin_routes/notification_settings.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
change_notification_setting:
controller: App\Controller\NotificationSettingsController::changeSetting
path: /cns/{subject_type}/{subject_id}/{status}
requirements:
subject_type: user|magazine|entry|post
status: Default|Loud|Muted
8 changes: 8 additions & 0 deletions config/mbin_routes/notification_settings_api.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
api_notification_settings_update:
controller: App\Controller\Api\Notification\NotificationSettingApi::update
path: /api/notification/update/{targetType}/{targetId}/{setting}
requirements:
targetType: entry|post|magazine|user
setting: Default|Loud|Muted
methods: [ GET ]
format: json
2 changes: 2 additions & 0 deletions config/packages/doctrine.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ doctrine:
types:
citext: App\DoctrineExtensions\DBAL\Types\Citext
enumApplicationStatus: App\DoctrineExtensions\DBAL\Types\EnumApplicationStatus
enumNotificationStatus: App\DoctrineExtensions\DBAL\Types\EnumNotificationStatus
mapping_types:
user_type: string
citext: citext
enumApplicationStatus: string
enumNotificationStatus: string

# IMPORTANT: You MUST configure your server version,
# either here or in the DATABASE_URL env var (see .env file)
Expand Down
47 changes: 47 additions & 0 deletions migrations/Version20241125210454.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20241125210454 extends AbstractMigration
{
public function getDescription(): string
{
return 'Create the notification_settings table for customized notification settings';
}

public function up(Schema $schema): void
{
$this->addSql('CREATE TYPE enumNotificationStatus AS ENUM(\'Default\', \'Muted\', \'Loud\')');
$this->addSql('CREATE SEQUENCE notification_settings_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE notification_settings (id INT NOT NULL, user_id INT NOT NULL, entry_id INT DEFAULT NULL, post_id INT DEFAULT NULL, magazine_id INT DEFAULT NULL, target_user_id INT DEFAULT NULL, notification_status enumNotificationStatus DEFAULT \'Default\' NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_B0559860A76ED395 ON notification_settings (user_id)');
$this->addSql('CREATE INDEX IDX_B0559860BA364942 ON notification_settings (entry_id)');
$this->addSql('CREATE INDEX IDX_B05598604B89032C ON notification_settings (post_id)');
$this->addSql('CREATE INDEX IDX_B05598603EB84A1D ON notification_settings (magazine_id)');
$this->addSql('CREATE INDEX IDX_B05598606C066AFE ON notification_settings (target_user_id)');
$this->addSql('CREATE UNIQUE INDEX notification_settings_user_target ON notification_settings (user_id, entry_id, post_id, magazine_id, target_user_id)');
$this->addSql('COMMENT ON COLUMN notification_settings.notification_status IS \'(DC2Type:EnumNotificationStatus)\'');
$this->addSql('ALTER TABLE notification_settings ADD CONSTRAINT FK_B0559860A76ED395 FOREIGN KEY (user_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE notification_settings ADD CONSTRAINT FK_B0559860BA364942 FOREIGN KEY (entry_id) REFERENCES entry (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE notification_settings ADD CONSTRAINT FK_B05598604B89032C FOREIGN KEY (post_id) REFERENCES post (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE notification_settings ADD CONSTRAINT FK_B05598603EB84A1D FOREIGN KEY (magazine_id) REFERENCES magazine (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE notification_settings ADD CONSTRAINT FK_B05598606C066AFE FOREIGN KEY (target_user_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
}

public function down(Schema $schema): void
{
$this->addSql('DROP SEQUENCE notification_settings_id_seq CASCADE');
$this->addSql('ALTER TABLE notification_settings DROP CONSTRAINT FK_B0559860A76ED395');
$this->addSql('ALTER TABLE notification_settings DROP CONSTRAINT FK_B0559860BA364942');
$this->addSql('ALTER TABLE notification_settings DROP CONSTRAINT FK_B05598604B89032C');
$this->addSql('ALTER TABLE notification_settings DROP CONSTRAINT FK_B05598603EB84A1D');
$this->addSql('ALTER TABLE notification_settings DROP CONSTRAINT FK_B05598606C066AFE');
$this->addSql('DROP TABLE notification_settings');
$this->addSql('DROP TYPE enumNotificationStatus');
}
}
Loading

0 comments on commit 07863d2

Please sign in to comment.