Skip to content

Commit

Permalink
Merge pull request #29 from jahseng-lee/feature/visa-information-v2
Browse files Browse the repository at this point in the history
Visa Information v2
  • Loading branch information
jahseng-lee authored Apr 10, 2024
2 parents a23b166 + a86ca4a commit 4c23122
Show file tree
Hide file tree
Showing 26 changed files with 723 additions and 32 deletions.
1 change: 1 addition & 0 deletions app/assets/stylesheets/application.bootstrap.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ $background-link-hover-dark: lighten($primary, 20%);
@import 'reviews';
@import 'search_location';
@import 'users';
@import 'visa_informations';

body {
padding-top: 4rem;
Expand Down
6 changes: 6 additions & 0 deletions app/assets/stylesheets/visa_informations.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.edit-visa-form {
height: 100%;

position: sticky;
top: 5rem;
}
56 changes: 56 additions & 0 deletions app/controllers/issues_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
class IssuesController < ApplicationController
def index
authorize(Issue)

@issues = Issue.unresolved
end

def create
@issue = Issue.new(create_params)
authorize(@issue)

respond_to do |format|
format.turbo_stream do
unless @issue.save
render turbo_stream: turbo_stream.append(
"modal-flash-error",
partial: "issues/alert_error_create"
)
return
end
end
end
end

def update # a.k.a. "Resolve"
# Weird update - just resolves the issue.
# The policy _should_ check the user is admin. Assume that no admins
# are trying to maliciously resolve all issues
@issue = Issue.find(params[:id])
authorize(@issue)

@issue.update!(resolved: true)

respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.replace(
"issue-#{@issue.id}",
partial: "issues/alert_success_resolve"
)
end
end
end

private

def create_params
params.require(:issue).permit(
:reporter_id,
:entity_id,
:entity_type,
:additional_information,
:issue_type,
:body
)
end
end
12 changes: 4 additions & 8 deletions app/controllers/locations/citizenships_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Controller responsible for adding citizenships from the
# VisaInforation#show page. This differs from the CitizenshipsController
# VisaInformation#show page. This differs from the CitizenshipsController
# which is used on the Profile#show page
module Locations
class CitizenshipsController < ApplicationController
Expand All @@ -19,13 +19,9 @@ def create
)

if @citizenship.save
@visa_information = (
VisaInformation.find_by(
country: @location.country,
citizenship: @citizenship.country
)
) || (
VisaInforation.generic(country: @location.country)
@visa_information = VisaInformation.find_by(
country: @location.country,
citizenship: @citizenship.country
)

flash.now[:success_save_citizenship] = "Added citizenship!" \
Expand Down
107 changes: 100 additions & 7 deletions app/controllers/visa_informations_controller.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,115 @@
class VisaInformationsController < ApplicationController
before_action :initialize_markdown_renderer
skip_before_action :authenticate_user!, only: [:show]
skip_before_action :authenticate_user!, only: [:show, :content]

def show
@location = Location.find(params[:location_id])
end

if current_user && current_user.citizenships.any?
@visa_information = VisaInformation.find_by(
country: @location.country,
# Assume only one citizenship for now
citizenship: current_user.citizenships.first.country
def edit
@location = Location.find(params[:location_id])
@visa_information = params[:id].present? ? (
VisaInformation.find_by(id: params[:id])
) : (
VisaInformation.generic(country: @location.country)
)
@visa_informations = VisaInformation
.includes(:citizenship)
.where(
country: @location.country
)
.order("countries.name")
end

def update
@location = Location.find(params[:location_id])
@visa_information = VisaInformation.find(params[:id])

@visa_information.assign_attributes(
body: update_params[:body]
)

if @visa_information.save
flash.now[:success_update_visa] = "Updated visa info."
else
flash.now[:error_update_visa] = "Couldn't update visa info." \
" Please try again."
end

respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.replace(
"update-visa-info-form",
partial: "visa_informations/update_visa_info_form",
locals: {
location: @location,
visa_information: @visa_information
}
)
end
end
end

def content
@location = Location.find(params[:location_id])

if @visa_information.nil?
if current_user.nil? || current_user.citizenship.nil?
@visa_information = VisaInformation.generic(
country: @location.country
)
else
citizenship_country = current_user.citizenship.country
@visa_information = VisaInformation.find_by(
country: @location.country,
# Assume only one citizenship for now
citizenship: citizenship_country
)

# Couldn't find VisaInformation for the @location.country and the
# current_user.citizenship.country - create one instead
if @visa_information.nil?
@visa_information = VisaInformation.create!(
country: @location.country,
# Assume only one citizenship for now
citizenship: citizenship_country,
body: ChatGpt.generate_visa_info(
country: @location.country,
citizenship_country: citizenship_country
)
)
end
end

respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.replace(
"location-visa-information",
partial: "visa_informations/location_visa_information",
locals: {
user: current_user,
visa_information: @visa_information
}
)
end
end
end

def report_issue_modal
@location = Location.find(params[:location_id])

respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.append(
"site-modals",
partial: "visa_informations/report_issue_modal"
)
end
end
end

private

def update_params
params.require(:visa_information).permit(:body)
end
end
23 changes: 23 additions & 0 deletions app/helpers/issues_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module IssuesHelper
def helper_issue_entity_link(issue:)
return "No entity" if issue.entity.nil?

if issue.entity_type.constantize == Country
# We don't have a Country page, so link to the Visa page
# found in additional information Location#name
location = Location.find_by(
name: issue.additional_information["location"]
)

return link_to(
location_visa_information_path(
location_id: location.id
),
target: "_blank"
) do
"<i class='bi bi-box-arrow-up-right'></i>\n" \
"Reported on visa page for #{location.name_utf8}".html_safe
end
end
end
end
10 changes: 10 additions & 0 deletions app/helpers/visa_informations_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module VisaInformationsHelper
def helper_edit_visa_info_heading(location:, visa_information:)
heading = "Editing visa information for #{location.country.name}"
if visa_information.citizenship.present?
heading << " for citizens of #{visa_information.citizenship.name}"
end

heading
end
end
5 changes: 5 additions & 0 deletions app/lib/chat_gpt.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ def self.generate_generic_visa_info(country:)
end

def self.generate_visa_info(country:, citizenship_country:)
unless Rails.env.production?
return "Visa info. for citizenship: #{citizenship_country.name}," \
" country: #{country.name}."
end

prompt = "Could you write me an informational article that explains" \
" the visa options for a digital nomad who is a" \
" #{citizenship_country.name} citizen visiting #{country.name}?" \
Expand Down
87 changes: 87 additions & 0 deletions app/models/issue.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
class Issue < ApplicationRecord
belongs_to :reporter,
foreign_key: :reporter_id,
optional: true,
class_name: "User"

# It may seem like we're replicating string enums here, and it is.
# But for some reason, string enums aren't playing nice.
# enum issue_type: { other: "Other" } is actually saving it to the
# DB as "other", with the capitalised string doing... nothing.
# This contradicts the docs, so leaving for now...
MISSING_VISA_INFO = "Missing visa information"
INCORRECT_VISA_INFO = "Incorrect visa information"
ERROR_VISA_INFO = "Visa information is not loading/causing error"
OTHER = "Other"
ISSUE_TYPES = [
MISSING_VISA_INFO,
INCORRECT_VISA_INFO,
ERROR_VISA_INFO,
OTHER,
]

validate :issue_type_exists
validate :issue_type_entity_match
validate :entity_exists

scope :unresolved, -> { where(resolved: false) }

def self.visa_issue_types
[
MISSING_VISA_INFO,
INCORRECT_VISA_INFO,
ERROR_VISA_INFO,
OTHER
]
end

def additional_information
JSON.parse(self[:additional_information])
end

def entity
return nil if entity_type.nil? || entity_id.nil?

if entity_type.constantize == Country
"Country: #{Country.find(entity_id).name}"
end
end

private

def issue_type_exists
unless ISSUE_TYPES.include?(issue_type)
errors.add(
:issue_type, "must be declared in Issue::ISSUE_TYPES."
)
end
end

def issue_type_entity_match
if entity_type == "Country" &&
!Issue.visa_issue_types.include?(issue_type)
errors.add(
:issue_type,
"must be in Issue.visa_issue_types if the entity_type is" \
" 'Country'."
)
end
end

def entity_exists
return if entity_type.nil?

if entity_id.nil?
errors.add(:entity_id, "can't be empty if entity_type is specified")
return
end

if entity_type.constantize.find_by(id: entity_id).nil?
errors.add(
:entity_id,
"can't find entity with entity_type: #{entity_type}," \
" id: #{entity_id}"
)
end
end
end
13 changes: 13 additions & 0 deletions app/policies/issue_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class IssuePolicy < ApplicationPolicy
def index?
user.admin?
end

def create?
record.reporter == user
end

def update?
index?
end
end
5 changes: 5 additions & 0 deletions app/views/issues/_alert_error_create.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="alert alert-danger alert-dismissible fade show" role="alert">
Oops, looks like something went wrong on our end. We're looking into it
ASAP.
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
4 changes: 4 additions & 0 deletions app/views/issues/_alert_success_create.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="alert alert-success alert-dismissible fade show" role="alert">
Thanks for reporting the issue. Our team will look into it ASAP.
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
4 changes: 4 additions & 0 deletions app/views/issues/_alert_success_resolve.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="alert alert-success alert-dismissible fade show" role="alert">
Issue resolved
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
Loading

0 comments on commit 4c23122

Please sign in to comment.