Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add story pinned option #975

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions rails/app/assets/stylesheets/cms/_cards.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@

&:hover {
box-shadow: 0 0 10px $lighter-gray;

.edit-icon-unpinned {
visibility: visible;
}
}

&--narrow {
Expand Down Expand Up @@ -117,3 +121,7 @@
word-wrap: break-word;
}
}

.story-header {
display: flex;
}
53 changes: 52 additions & 1 deletion rails/app/assets/stylesheets/cms/_icons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,55 @@
&::before {
content: "\1F4CD";
}
}
}

.edit-icon-pinned, .edit-icon-unpinned, .view-icon-pinned {
height: fit-content;
margin-inline-start: auto;
}

.edit-icon-unpinned {
visibility: hidden;
}

.edit-icon-pinned, .edit-icon-unpinned {
&:hover {
box-shadow: 0 0 10px $lighter-gray;
}
}

.icon-button, .view-icon-pinned {
max-width: 25px;
max-height: 25px;
padding: 0;
}

.icon-button {
border: none;
background-color: inherit;

&:hover {
cursor: pointer;

.icon-unpinned {
fill: $dark-gray;
}

.icon-pinned {
fill: $red;
}
}
}

.icon-unpinned, .icon-pinned {
max-height: 18px;
width: 100%;
}

.icon-unpinned {
fill: $light-gray;
}

.icon-pinned {
fill: $black;
}
griseduardo marked this conversation as resolved.
Show resolved Hide resolved
7 changes: 7 additions & 0 deletions rails/app/assets/stylesheets/components/card.scss
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,13 @@ $el-shadow: 0 1px 4px $lighter-gray;
.stories {
overflow-x: hidden;
flex: 5 0 0;

.pinned {
float: right;
width: 18px;
height: 18px;
};

.container {
padding-bottom: 3rem;

Expand Down
25 changes: 25 additions & 0 deletions rails/app/controllers/dashboard/stories_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ def new

def create
authorize Story

if ActiveModel::Type::Boolean.new.cast(story_params[:story_pinned])
community_stories.update_all(story_pinned: false)
end

@story = community_stories.new(story_params.except(:media))

if @story.save
Expand All @@ -44,6 +49,10 @@ def edit
def update
@story = authorize community_stories.find(params[:id])

if !@story.story_pinned && ActiveModel::Type::Boolean.new.cast(story_params[:story_pinned])
community_stories.update_all(story_pinned: false)
end

if @story.update(story_params.except(:media))
story_params[:media]&.each do |media|
m = @story.media.create(media: media)
Expand All @@ -55,6 +64,21 @@ def update
end
end

def pin
@story = authorize community_stories.find(params[:id])
community_stories.update_all(story_pinned: false)
@story.update(story_pinned: true)

redirect_to stories_path
end

def unpin
@story = authorize community_stories.find(params[:id])
@story.update(story_pinned: false)

redirect_to stories_path
end

def destroy
@story = authorize community_stories.find(params[:id])

Expand Down Expand Up @@ -88,6 +112,7 @@ def story_params
:topic,
:interview_location_id,
:interviewer_id,
:story_pinned,
media: [],
speaker_ids: [],
place_ids: []
Expand Down
6 changes: 6 additions & 0 deletions rails/app/javascript/components/Sort.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ class Sort extends Component {
return {value: value, label: this.props.t(value)};
}

storyPinnedSort = (sortedStories) => (
sortedStories.sort(story => story.story_pinned ? -1 : 1)
)

handleSort = (option) => {
this.setState({
sortSelectValue: option.value
Expand Down Expand Up @@ -93,6 +97,8 @@ class Sort extends Component {
}
}

sortedStories = this.storyPinnedSort(sortedStories)

this.props.handleStoriesChanged(sortedStories);
}

Expand Down
35 changes: 25 additions & 10 deletions rails/app/javascript/components/Story.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React from "react";
import PropTypes from "prop-types";
import StoryMedia from "./StoryMedia";
import { useTranslation } from 'react-i18next';
import StoryMedia from "./StoryMedia";

const Story = props => {
const { t } = useTranslation();
const { story, storyClass } = props;
const { onStoryClick, story, storyClass } = props;

const renderSpeakers = speakers => {
return (
Expand Down Expand Up @@ -34,14 +34,23 @@ const Story = props => {
}

return (
<React.Fragment>
<>
<li
className={storyClass}
onClick={() => props.onStoryClick(story)}
onKeyDown={() => props.onStoryClick(story)}
onClick={() => onStoryClick(story)}
onKeyDown={() => onStoryClick(story)}
key={story.id}
role="presentation"
>
{
story.story_pinned && (
<div className="pinned">
<svg viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg">
<path d="m634-448 86 77v60H510v241l-30 30-30-30v-241H240v-60l80-77v-333h-50v-60h414v60h-50v333Z"/>
</svg>
</div>
)
}
<div className="speakers">
{renderSpeakers(story.speakers)}
</div>
Expand All @@ -61,14 +70,20 @@ const Story = props => {
))
}
{
story.language &&
<p>
<b>{t("language")}:</b> {story.language}
</p>
story.language && (
<p>
<b>
{t("language")}
:
</b>
{' '}
{story.language}
</p>
)
}
</div>
</li>
</React.Fragment>
</>
);
}

Expand Down
1 change: 1 addition & 0 deletions rails/app/models/story.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def public_points
# desc :text
# language :string
# permission_level :integer
# story_pinned :boolean default(FALSE)
# title :string
# topic :string
# created_at :datetime not null
Expand Down
7 changes: 5 additions & 2 deletions rails/app/pages/stories_page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ def relation
stories = stories.joins(:speaker_stories).where(speaker_stories: {speaker_id: @meta[:speaker]}) if @meta[:speaker].present?
stories = stories.where(permission_level: @meta[:visibility]) if @meta[:visibility].present?

stories.order(@meta[:sort_by] => @meta[:sort_dir])
stories.order(
story_pinned: :desc,
@meta[:sort_by] => @meta[:sort_dir]
)
end
end
end
8 changes: 8 additions & 0 deletions rails/app/policies/story_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ def update?
edit?
end

def pin?
edit?
end

def unpin?
edit?
end

def destroy?
user.admin? || user.editor?
end
Expand Down
5 changes: 5 additions & 0 deletions rails/app/views/dashboard/stories/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
</div>
<% end %>

<%= f.label :pin_story %>
<div class="checklist">
<%= f.check_box :story_pinned, {}, "true", "false" %>
</div>

<%= f.label :speaker_ids, class: "required" %>
<div class="checklist">
<%= f.collection_check_boxes :speaker_ids, current_community.speakers, :id, :name, required: true %>
Expand Down
28 changes: 24 additions & 4 deletions rails/app/views/dashboard/stories/_stories.html.erb
Original file line number Diff line number Diff line change
@@ -1,10 +1,30 @@
<% @stories.each do |story| %>
<%= link_to story, class: "card" do %>
<div>
<h3>
<span class="card__heading--small"><%= story.topic %></span>
<%= story.title %>
</h3>
<div class="story-header">
<div>
<h3 style="width:max-content">
<span class="card__heading--small"><%= story.topic %></span>
<%= story.title %>
</h3>
</div>
<% if current_user.member? && story.story_pinned %>
<div class="view-icon-pinned">
<svg class="icon-pinned"><use href="#icon-thumbtack"></svg>
</div>
<% end %>
<% if current_user.admin? || current_user.editor? %>
<% if story.story_pinned %>
<%= button_to unpin_story_path(story), method: :patch, data: { remote: false }, locale: true, form_class: "edit-icon-pinned", class: "icon-button" do %>
<svg class="icon-pinned"><use href="#icon-thumbtack"></svg>
<% end %>
<% else %>
<%= button_to pin_story_path(story), method: :patch, data: { remote: false }, locale: true, form_class: "edit-icon-unpinned", class: "icon-button" do %>
<svg class="icon-unpinned"><use href="#icon-thumbtack"></svg>
<% end %>
<% end %>
<% end %>
</div>

<% if story.language.present? %>
<span class="badge badge-red"><%= story.language %></span>
Expand Down
2 changes: 1 addition & 1 deletion rails/app/views/home/_home.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
json.stories stories do |story|
json.extract! story, :title, :desc, :id, :created_at
json.extract! story, :title, :desc, :id, :created_at, :story_pinned
json.points story.places.map(&:point_geojson)
json.places story.places
json.language story.language
Expand Down
6 changes: 5 additions & 1 deletion rails/app/views/shared/_icons.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@
<path d="M10.5 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0z"/>
<path d="M0 8s3-5.5 8-5.5S16 8 16 8s-3 5.5-8 5.5S0 8 0 8zm8 3.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7z"/>
</symbol>
</svg>

<symbol id="icon-thumbtack" viewBox="0 -960 960 960">
<path d="m634-448 86 77v60H510v241l-30 30-30-30v-241H240v-60l80-77v-333h-50v-60h414v60h-50v333Z"/>
</symbol>
</svg>
2 changes: 2 additions & 0 deletions rails/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
delete :name_audio, action: :delete_name_audio
end
resources :stories do
patch :pin, on: :member
patch :unpin, on: :member
delete '/media/:id/delete', action: :delete_media, as: :delete_media
end
resource :theme, only: [:update, :edit, :show]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddStoryPinnedToStories < ActiveRecord::Migration[6.1]
def change
add_column :stories, :story_pinned, :boolean, default: false
end
end
3 changes: 2 additions & 1 deletion rails/db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2023_08_08_135800) do
ActiveRecord::Schema.define(version: 2023_10_09_012520) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
Expand Down Expand Up @@ -154,6 +154,7 @@
t.integer "interviewer_id"
t.integer "community_id"
t.string "topic"
t.boolean "story_pinned", default: false
end

create_table "themes", force: :cascade do |t|
Expand Down
Loading