Phase 22: mapper round 2, response shaper, card detail modal, market filters
- mapper.rs: 22 new exact routes (squad list, trophies, rivals, objectives
sub-groups, catalogue, consumables, loan items, active messages, price
tiers, fitness, customization) + 5 new prefix routes (squad GET/DELETE by
ID, item chemistry PUT, SBC set GET); total exact routes now ≥55
- shaper.rs: shape /achievements → trophyData envelope; /squads → squads
list envelope; /packs/store → purchasablePacks envelope; also shapes
parameterised /squads/{id} responses
- dashboard: card detail modal (click any collection card → full stat view,
chemistry/training/loan info, quick-sell action); loan-only checkbox in
collection filters; position + min/max price filters in transfer market
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+220
-2
@@ -236,6 +236,116 @@ const EXACT: &[ExactRoute] = &[
|
||||
core_method: "GET", core_path: "/notifications",
|
||||
notes: "FUT notifications (plural form) → Core notifications",
|
||||
},
|
||||
// ── Squad list ────────────────────────────────────────────────────────────
|
||||
ExactRoute {
|
||||
ea_method: "GET", ea_path: "/ut/game/fut/squad/list",
|
||||
core_method: "GET", core_path: "/squads",
|
||||
notes: "FUT squad list → Core all squads",
|
||||
},
|
||||
ExactRoute {
|
||||
ea_method: "DELETE", ea_path: "/ut/game/fut/squad/active",
|
||||
core_method: "DELETE", core_path: "/squad",
|
||||
notes: "FUT delete active squad → Core delete squad (best-effort)",
|
||||
},
|
||||
// ── Achievements / Trophies ───────────────────────────────────────────────
|
||||
ExactRoute {
|
||||
ea_method: "GET", ea_path: "/ut/game/fut/trophies",
|
||||
core_method: "GET", core_path: "/achievements",
|
||||
notes: "FUT trophies → Core achievements",
|
||||
},
|
||||
ExactRoute {
|
||||
ea_method: "GET", ea_path: "/ut/game/fut/trophy",
|
||||
core_method: "GET", core_path: "/achievements",
|
||||
notes: "FUT trophy (singular) → Core achievements",
|
||||
},
|
||||
// ── Rivals extra endpoints ────────────────────────────────────────────────
|
||||
ExactRoute {
|
||||
ea_method: "GET", ea_path: "/ut/game/fut/rivals/rank",
|
||||
core_method: "GET", core_path: "/division",
|
||||
notes: "FUT rivals rank → Core division",
|
||||
},
|
||||
ExactRoute {
|
||||
ea_method: "POST", ea_path: "/ut/game/fut/rivals/result",
|
||||
core_method: "POST", core_path: "/matches/result",
|
||||
notes: "FUT rivals match result → Core match result",
|
||||
},
|
||||
ExactRoute {
|
||||
ea_method: "GET", ea_path: "/ut/game/fut/rivals/leaderboard",
|
||||
core_method: "GET", core_path: "/statistics",
|
||||
notes: "FUT rivals leaderboard → Core statistics (offline approximation)",
|
||||
},
|
||||
// ── Objectives sub-groups ─────────────────────────────────────────────────
|
||||
ExactRoute {
|
||||
ea_method: "GET", ea_path: "/ut/game/fut/objectives/group",
|
||||
core_method: "GET", core_path: "/objectives",
|
||||
notes: "FUT objectives group → Core objectives",
|
||||
},
|
||||
ExactRoute {
|
||||
ea_method: "GET", ea_path: "/ut/game/fut/objectives/daily",
|
||||
core_method: "GET", core_path: "/objectives",
|
||||
notes: "FUT daily objectives → Core objectives",
|
||||
},
|
||||
ExactRoute {
|
||||
ea_method: "GET", ea_path: "/ut/game/fut/objectives/weekly",
|
||||
core_method: "GET", core_path: "/objectives",
|
||||
notes: "FUT weekly objectives → Core objectives",
|
||||
},
|
||||
ExactRoute {
|
||||
ea_method: "POST", ea_path: "/ut/game/fut/objectives/group/claim",
|
||||
core_method: "POST", core_path: "/objectives/claim",
|
||||
notes: "FUT objectives group claim → Core objectives claim",
|
||||
},
|
||||
// ── Catalogue / Card search ───────────────────────────────────────────────
|
||||
ExactRoute {
|
||||
ea_method: "GET", ea_path: "/ut/game/fut/catalogue/item",
|
||||
core_method: "GET", core_path: "/cards",
|
||||
notes: "FUT catalogue items → Core card catalogue",
|
||||
},
|
||||
ExactRoute {
|
||||
ea_method: "GET", ea_path: "/ut/game/fut/catalogue",
|
||||
core_method: "GET", core_path: "/cards",
|
||||
notes: "FUT catalogue → Core card catalogue",
|
||||
},
|
||||
// ── Store / Pricing ───────────────────────────────────────────────────────
|
||||
ExactRoute {
|
||||
ea_method: "GET", ea_path: "/ut/game/fut/store/pricetiers",
|
||||
core_method: "GET", core_path: "/packs/store",
|
||||
notes: "FUT price tiers → Core pack store definitions",
|
||||
},
|
||||
// ── Consumables / Chemistry / Fitness ─────────────────────────────────────
|
||||
ExactRoute {
|
||||
ea_method: "GET", ea_path: "/ut/game/fut/consumables",
|
||||
core_method: "GET", core_path: "/chemistry-styles",
|
||||
notes: "FUT consumables → Core chemistry styles (approximation)",
|
||||
},
|
||||
ExactRoute {
|
||||
ea_method: "POST", ea_path: "/ut/game/fut/fitness",
|
||||
core_method: "GET", core_path: "/club",
|
||||
notes: "FUT fitness apply → Core club (placeholder, fitness not tracked)",
|
||||
},
|
||||
// ── Loan items ────────────────────────────────────────────────────────────
|
||||
ExactRoute {
|
||||
ea_method: "GET", ea_path: "/ut/game/fut/loanitems",
|
||||
core_method: "GET", core_path: "/collection",
|
||||
notes: "FUT loan items → Core collection (client filters is_loan)",
|
||||
},
|
||||
// ── Customization / Kit ───────────────────────────────────────────────────
|
||||
ExactRoute {
|
||||
ea_method: "GET", ea_path: "/ut/game/fut/customization",
|
||||
core_method: "GET", core_path: "/settings",
|
||||
notes: "FUT customization → Core settings",
|
||||
},
|
||||
ExactRoute {
|
||||
ea_method: "PUT", ea_path: "/ut/game/fut/customization",
|
||||
core_method: "PUT", core_path: "/settings",
|
||||
notes: "FUT save customization → Core save settings",
|
||||
},
|
||||
// ── Active messages / MOTD ────────────────────────────────────────────────
|
||||
ExactRoute {
|
||||
ea_method: "GET", ea_path: "/ut/game/fut/activeMessage",
|
||||
core_method: "GET", core_path: "/notifications",
|
||||
notes: "FUT active messages → Core notifications (mapped to nearest equivalent)",
|
||||
},
|
||||
];
|
||||
|
||||
// ── Prefix mappings (dynamic path segments after a known prefix) ───────────────
|
||||
@@ -300,6 +410,44 @@ fn prefix_routes() -> &'static [PrefixRoute] {
|
||||
core_path_fn: |suffix| format!("/collection/{suffix}"),
|
||||
notes: "FUT quick-sell item → Core delete owned card",
|
||||
},
|
||||
// /ut/game/fut/item/{owned_id} (PUT) → PUT /collection/{owned_id}/chemistry
|
||||
PrefixRoute {
|
||||
ea_method: "PUT",
|
||||
ea_prefix: "/ut/game/fut/item/",
|
||||
core_path_fn: |suffix| {
|
||||
// suffix is just the owned_card_id; game sends chemistry style in body
|
||||
format!("/collection/{suffix}/chemistry")
|
||||
},
|
||||
notes: "FUT apply chemistry style → Core update card chemistry",
|
||||
},
|
||||
// /ut/game/fut/squad/{id} (GET) → GET /squads/{id}
|
||||
// Note: must come after exact matches for /squad/active, /squad/0, etc.
|
||||
PrefixRoute {
|
||||
ea_method: "GET",
|
||||
ea_prefix: "/ut/game/fut/squad/",
|
||||
core_path_fn: |suffix| {
|
||||
// Skip known non-ID suffixes already handled as exact routes
|
||||
match suffix {
|
||||
"active" | "chemistry" | "list" => "/squad".to_string(),
|
||||
_ => format!("/squads/{suffix}"),
|
||||
}
|
||||
},
|
||||
notes: "FUT squad by ID → Core squad by ID",
|
||||
},
|
||||
// /ut/game/fut/squad/{id} (DELETE) → DELETE /squads/{id}
|
||||
PrefixRoute {
|
||||
ea_method: "DELETE",
|
||||
ea_prefix: "/ut/game/fut/squad/",
|
||||
core_path_fn: |suffix| format!("/squads/{suffix}"),
|
||||
notes: "FUT delete squad by ID → Core delete squad",
|
||||
},
|
||||
// /ut/game/fut/sbc/set/{set_id} (GET) → GET /sbc/{set_id}
|
||||
PrefixRoute {
|
||||
ea_method: "GET",
|
||||
ea_prefix: "/ut/game/fut/sbc/set/",
|
||||
core_path_fn: |suffix| format!("/sbc/{suffix}"),
|
||||
notes: "FUT SBC set details → Core individual SBC",
|
||||
},
|
||||
// /ut/game/fut/store/pack/{pack_id}/open → POST /packs/open/{pack_id}
|
||||
PrefixRoute {
|
||||
ea_method: "POST",
|
||||
@@ -549,7 +697,77 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_total_exact_routes_count() {
|
||||
// Ensure we have a meaningful number of exact mappings
|
||||
assert!(EXACT.len() >= 35, "expected at least 35 exact mappings, got {}", EXACT.len());
|
||||
assert!(EXACT.len() >= 55, "expected at least 55 exact mappings, got {}", EXACT.len());
|
||||
}
|
||||
|
||||
// ── Phase 22 new mappings ─────────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn test_squad_list_maps() {
|
||||
let m = map_to_core("GET", "/ut/game/fut/squad/list");
|
||||
assert!(m.is_some());
|
||||
assert_eq!(m.unwrap().core_path, "/squads");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_squad_by_id_get_maps() {
|
||||
let m = map_to_core_with_method("GET", "/ut/game/fut/squad/abc-squad-id");
|
||||
assert!(m.is_some());
|
||||
assert_eq!(m.unwrap().core_path, "/squads/abc-squad-id");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_squad_by_id_delete_maps() {
|
||||
let m = map_to_core_with_method("DELETE", "/ut/game/fut/squad/abc-squad-id");
|
||||
assert!(m.is_some());
|
||||
assert_eq!(m.unwrap().core_path, "/squads/abc-squad-id");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_item_put_chemistry_maps() {
|
||||
let m = map_to_core_with_method("PUT", "/ut/game/fut/item/owned-999");
|
||||
assert!(m.is_some());
|
||||
assert_eq!(m.unwrap().core_path, "/collection/owned-999/chemistry");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sbc_set_get_maps() {
|
||||
let m = map_to_core_with_method("GET", "/ut/game/fut/sbc/set/sbc-123");
|
||||
assert!(m.is_some());
|
||||
assert_eq!(m.unwrap().core_path, "/sbc/sbc-123");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trophies_maps() {
|
||||
let m = map_to_core("GET", "/ut/game/fut/trophies");
|
||||
assert!(m.is_some());
|
||||
assert_eq!(m.unwrap().core_path, "/achievements");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rivals_result_maps() {
|
||||
let m = map_to_core("POST", "/ut/game/fut/rivals/result");
|
||||
assert!(m.is_some());
|
||||
assert_eq!(m.unwrap().core_path, "/matches/result");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_catalogue_item_maps() {
|
||||
let m = map_to_core("GET", "/ut/game/fut/catalogue/item");
|
||||
assert!(m.is_some());
|
||||
assert_eq!(m.unwrap().core_path, "/cards");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_objectives_daily_maps() {
|
||||
let m = map_to_core("GET", "/ut/game/fut/objectives/daily");
|
||||
assert!(m.is_some());
|
||||
assert_eq!(m.unwrap().core_path, "/objectives");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_active_message_maps() {
|
||||
let m = map_to_core("GET", "/ut/game/fut/activeMessage");
|
||||
assert!(m.is_some());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user