From 0c26ecaa02e49b5238c55fe7718fded336a2aa94 Mon Sep 17 00:00:00 2001 From: Anna Date: Wed, 6 Oct 2021 21:02:31 -0400 Subject: [PATCH] fix: properly sort duties --- assets/listings.js | 67 +++++------------------ src/listing.rs | 115 +++++++++++++++++++++++++++++++++++++++ src/listing_container.rs | 2 + src/template/listings.rs | 1 + src/web.rs | 9 +++ templates/listings.html | 23 ++------ 6 files changed, 146 insertions(+), 71 deletions(-) diff --git a/assets/listings.js b/assets/listings.js index 6be02c5..d688367 100644 --- a/assets/listings.js +++ b/assets/listings.js @@ -2,18 +2,11 @@ let stateWasNull = false; const state = { - allowed: {}, + allowed: [], centre: "All", list: null, }; - const categoryDefaults = { - type: 0, - category: 0, - highEnd: false, - contentKind: -1, - }; - function addJsClass() { document.children[0].className = 'js'; } @@ -23,8 +16,12 @@ if (saved !== null) { try { saved = JSON.parse(saved); + if (!Array.isArray(saved.allowed)) { + saved = {}; + stateWasNull = true; + } } catch (e) { - saved = {} + saved = {}; stateWasNull = true; } @@ -49,33 +46,16 @@ }); } - function getOptionValues(option) { - return { - type: option.dataset.type || categoryDefaults.type, - category: option.dataset.category || categoryDefaults.category, - highEnd: option.dataset.highEnd || categoryDefaults.highEnd, - contentKind: option.dataset.contentKind || categoryDefaults.contentKind, - }; - } - function reflectState() { let category = document.getElementById('category-filter'); for (let option of category.options) { - let values = getOptionValues(option); - let key = `${values.type}/${values.category}/${values.highEnd}`; - if (state.allowed[key] === undefined) { - if (stateWasNull) { - state.allowed[key] = []; - } else { - continue; - } - } - if (stateWasNull) { - state.allowed[key].push(values.contentKind); + console.log('was null'); + state.allowed.push(option.value); } - option.selected = state.allowed[key].includes(-1) || state.allowed[key].includes(values.contentKind); + console.log(`allowed includes ${option.value} = ${state.allowed.includes(option.value)}`) + option.selected = state.allowed.includes(option.value); } let dataCentre = document.getElementById('data-centre-filter'); @@ -96,18 +76,9 @@ function refilter() { function categoryFilter(item) { - let data = item.elm.dataset; - let type = data.type; - let category = data.category; - let highEnd = data.highEnd; - let contentKind = data.contentKind; + let category = item.elm.dataset.pfCategory; - let allowedContentKind = state.allowed[`${type}/${category}/${highEnd}`]; - if (allowedContentKind === undefined) { - return false; - } - - return allowedContentKind.includes(-1) || allowedContentKind.includes(contentKind); + return category === 'unknown' || state.allowed.includes(category); } function dataCentreFilter(item) { @@ -156,23 +127,15 @@ let select = document.getElementById('category-filter'); select.addEventListener('change', () => { - let allowed = new Map(); + let allowed = []; for (let option of select.options) { if (!option.selected) { continue; } - let values = getOptionValues(option); - - let key = `${values.type}/${values.category}/${values.highEnd}`; - if (allowed[key] === undefined) { - allowed[key] = []; - } - - if (!allowed[key].includes(values.contentKind)) { - allowed[key].push(values.contentKind); - } + let category = option.value; + allowed.push(category); } state.allowed = allowed; diff --git a/src/listing.rs b/src/listing.rs index 9c0d853..a5f03fb 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -5,6 +5,7 @@ use ffxiv_types::{Role, World}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; use sestring::SeString; +use crate::ffxiv::duties::{ContentKind, DutyInfo}; #[derive(Debug, Deserialize, Serialize, PartialEq)] pub struct PartyFinderListing { @@ -54,6 +55,8 @@ impl PartyFinderListing { } (DutyType::Other, DutyCategory::TheHunt) => return Cow::from("The Hunt"), (DutyType::Other, DutyCategory::Duty) if self.duty == 0 => return Cow::from("None"), + (DutyType::Other, DutyCategory::DeepDungeons) if self.duty == 1 => return Cow::from("The Palace of the Dead"), + (DutyType::Other, DutyCategory::DeepDungeons) if self.duty == 2 => return Cow::from("Heaven-on-High"), (DutyType::Normal, _) => { if let Some(info) = crate::ffxiv::DUTIES.get(&u32::from(self.duty)) { return Cow::from(info.name); @@ -168,6 +171,39 @@ impl PartyFinderListing { .map(|info| info.content_kind.as_u32()) .unwrap_or_default() } + + pub fn pf_category(&self) -> Option { + let duty_type = self.duty_type; + let duty_info = crate::ffxiv::DUTIES.get(&u32::from(self.duty)); + let duty_category = self.category; + + let category = match (duty_type, duty_info, duty_category) { + (DutyType::Other, None, _) => PartyFinderCategory::None, + (DutyType::Roulette, _, _) => PartyFinderCategory::DutyRoulette, + (DutyType::Normal, Some(DutyInfo { high_end: true, .. }), _) => PartyFinderCategory::HighEndDuty, + (DutyType::Normal, Some(DutyInfo { content_kind: ContentKind::Dungeons, .. }), _) => PartyFinderCategory::Dungeons, + (DutyType::Normal, Some(DutyInfo { content_kind: ContentKind::Guildhests, .. }), _) => PartyFinderCategory::Guildhests, + (DutyType::Normal, Some(DutyInfo { content_kind: ContentKind::Trials, .. }), _) => PartyFinderCategory::Trials, + (DutyType::Normal, Some(DutyInfo { content_kind: ContentKind::Raids, .. }), _) => PartyFinderCategory::Raids, + (DutyType::Normal, Some(DutyInfo { content_kind: ContentKind::PvP, .. }), _) => PartyFinderCategory::Pvp, + (_, _, DutyCategory::QuestBattles) => PartyFinderCategory::QuestBattles, + (_, _, DutyCategory::Fates) => PartyFinderCategory::Fates, + (_, _, DutyCategory::TreasureHunt) => PartyFinderCategory::TreasureHunt, + (_, _, DutyCategory::TheHunt) => PartyFinderCategory::TheHunt, + (DutyType::Normal, _, DutyCategory::GatheringForays) => PartyFinderCategory::GatheringForays, + (DutyType::Other, _, DutyCategory::DeepDungeons) => PartyFinderCategory::DeepDungeons, + (DutyType::Normal, _, DutyCategory::AdventuringForays) => PartyFinderCategory::AdventuringForays, + _ => return None, + }; + + Some(category) + } + + pub fn html_pf_category(&self) -> &'static str { + self.pf_category() + .map(|cat| cat.as_str()) + .unwrap_or("unknown") + } } #[derive(Debug, Deserialize, Serialize, PartialEq)] @@ -444,3 +480,82 @@ impl JobFlags { cjs } } + +#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)] +pub enum PartyFinderCategory { + DutyRoulette, + Dungeons, + Guildhests, + Trials, + Raids, + HighEndDuty, + Pvp, + QuestBattles, + Fates, + TreasureHunt, + TheHunt, + GatheringForays, + DeepDungeons, + AdventuringForays, + None, +} + +impl PartyFinderCategory { + pub const ALL: [Self; 15] = [ + Self::DutyRoulette, + Self::Dungeons, + Self::Guildhests, + Self::Trials, + Self::Raids, + Self::HighEndDuty, + Self::Pvp, + Self::QuestBattles, + Self::Fates, + Self::TreasureHunt, + Self::TheHunt, + Self::GatheringForays, + Self::DeepDungeons, + Self::AdventuringForays, + Self::None, + ]; + + pub fn as_str(self) -> &'static str { + match self { + Self::DutyRoulette => "DutyRoulette", + Self::Dungeons => "Dungeons", + Self::Guildhests => "Guildhests", + Self::Trials => "Trials", + Self::Raids => "Raids", + Self::HighEndDuty => "HighEndDuty", + Self::Pvp => "Pvp", + Self::QuestBattles => "QuestBattles", + Self::Fates => "Fates", + Self::TreasureHunt => "TreasureHunt", + Self::TheHunt => "TheHunt", + Self::GatheringForays => "GatheringForays", + Self::DeepDungeons => "DeepDungeons", + Self::AdventuringForays => "AdventuringForays", + Self::None => "None", + } + } + + pub fn name(self) -> &'static str { + match self { + Self::DutyRoulette => "Duty Roulette", + Self::Dungeons => "Dungeons", + Self::Guildhests => "Guildhests", + Self::Trials => "Trials", + Self::Raids => "Raids", + Self::HighEndDuty => "High-end Duty", + Self::Pvp => "PvP", + Self::QuestBattles => "Quest Battles", + Self::Fates => "FATEs", + Self::TreasureHunt => "Treasure Hunt", + Self::TheHunt => "The Hunt", + Self::GatheringForays => "Gathering Forays", + Self::DeepDungeons => "Deep Dungeons", + Self::AdventuringForays => "Adventuring Forays", + Self::None => "None", + } + } +} diff --git a/src/listing_container.rs b/src/listing_container.rs index 36132f3..8f693b0 100644 --- a/src/listing_container.rs +++ b/src/listing_container.rs @@ -14,6 +14,8 @@ pub struct ListingContainer { pub struct QueriedListing { #[serde(with = "mongodb::bson::serde_helpers::chrono_datetime_as_bson_datetime")] pub updated_at: DateTime, + #[serde(with = "mongodb::bson::serde_helpers::chrono_datetime_as_bson_datetime")] + pub updated_minute: DateTime, pub time_left: f64, pub listing: PartyFinderListing, } diff --git a/src/template/listings.rs b/src/template/listings.rs index ed6b7b2..c48b4f8 100644 --- a/src/template/listings.rs +++ b/src/template/listings.rs @@ -2,6 +2,7 @@ use askama::Template; use crate::listing_container::QueriedListing; use std::borrow::Borrow; use crate::sestring_ext::SeStringExt; +use crate::listing::PartyFinderCategory; #[derive(Debug, Template)] #[template(path = "listings.html")] diff --git a/src/web.rs b/src/web.rs index 4486e51..bce5fce 100644 --- a/src/web.rs +++ b/src/web.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use std::convert::{Infallible, TryFrom}; use anyhow::{Result, Context}; use std::sync::Arc; @@ -180,6 +181,14 @@ fn listings(state: Arc) -> BoxedFilter<(impl Reply, )> { } } + containers.sort_by(|a, b| a.time_left.partial_cmp(&b.time_left).unwrap_or(Ordering::Equal)); + + containers.sort_by_key(|container| container.listing.pf_category()); + containers.reverse(); + + containers.sort_by_key(|container| container.updated_minute); + containers.reverse(); + Ok(ListingsTemplate { containers, }) diff --git a/templates/listings.html b/templates/listings.html index dd9891a..8d86d45 100644 --- a/templates/listings.html +++ b/templates/listings.html @@ -41,21 +41,9 @@ Remote Party Finder @@ -72,10 +60,7 @@ Remote Party Finder class="listing" data-id="{{ listing.id }}" data-centre="{{ listing.data_centre_name().unwrap_or_default() }}" - data-type="{{ listing.duty_type.as_u8() }}" - data-category="{{ listing.category.as_u32() }}" - data-high-end="{{ listing.high_end() }}" - data-content-kind={{ listing.content_kind() }}> + data-pf-category="{{ listing.html_pf_category() }}">
{%- let duty_class %} {%- if listing.is_cross_world() %}