@@ -2,8 +2,114 @@ const API_BASE_URL = 'https://fantasyonline2.com/api/public';
22 const API_KEY = process . env . API_KEY ; // Replace with your actual key if needed
33 let embeddedItemData = null ; // Initialize as null
44
5+ < << << << HEAD
56 // Mock data for demonstration (replace with your actual data loading)
67 async function loadEmbeddedItemData ( ) {
8+ === = ===
9+ // Load the JSON file and assign its contents to embeddedItemData
10+ async function loadEmbeddedItemData ( ) {
11+ try {
12+ console . log ( 'Attempting to load item-data.json...' ) ;
13+ const response = await fetch ( 'item-data.json' ) ; // Ensure the path is correct
14+ console . log ( 'Fetch response status:' , response . status ) ;
15+
16+ if ( ! response . ok ) {
17+ throw new Error ( `Failed to load JSON file: ${ response . statusText } ` ) ;
18+ }
19+ const jsonData = await response . json ( ) ;
20+ console . log ( 'Raw JSON data:' , jsonData ) ;
21+
22+ embeddedItemData = jsonData ;
23+ console . log ( 'Embedded item data loaded:' , embeddedItemData ) ;
24+ } catch ( error ) {
25+ console . error ( 'Error loading embedded item data:' , error ) ;
26+ }
27+ }
28+
29+ // Call the function to load the JSON file
30+ loadEmbeddedItemData ( ) ;
31+
32+ let currentPage = 1 ;
33+ let totalPages = 1 ;
34+ let currentSort = 'TimeLeft' ;
35+ let currentDirection = 'DESC' ;
36+ let lastApiSearchTerm = '' ; // Store term used for last API call
37+ let isLoading = false ;
38+ let itemDatabase = null ;
39+ let currentMarketListings = [ ] ; // Stores full data for the current page from API
40+ let currentlyDisplayedListings = [ ] ; // Stores the listings currently shown (after filtering)
41+ let abortController = null ;
42+ let lastUpdateTime = null ;
43+ let showProfitableOnlyState = false ; // Tracks if the profitable filter *should* be active
44+ let isComprehensiveSearchActive = false ; // Tracks if we are *currently showing* comprehensive results
45+ let comprehensiveSearchResults = [ ] ;
46+ let searchedPages = 0 ;
47+ let totalSearchPages = 0 ;
48+ let comprehensiveSearchAborted = false ;
49+ let personalPrices = { } ; // Holds user-defined prices {itemId: price}
50+ let selectedItemId = null ; // Track the currently selected item ID for the details panel
51+
52+ // DOM Elements
53+ const searchForm = document . getElementById ( 'search-form' ) ;
54+ const searchInput = document . getElementById ( 'search-input' ) ;
55+ const searchButton = document . getElementById ( 'search-button' ) ;
56+ const sortBySelect = document . getElementById ( 'sort-by' ) ;
57+ const sortDirectionSelect = document . getElementById ( 'sort-direction' ) ;
58+ const messageContainer = document . getElementById ( 'message-container' ) ;
59+ const databaseStatus = document . getElementById ( 'database-status' ) ;
60+ const resultsContainer = document . getElementById ( 'results-container' ) ;
61+ const resultsTable = document . getElementById ( 'results-table' ) ;
62+ const resultsBody = document . getElementById ( 'results-body' ) ;
63+ const prevPageButton = document . getElementById ( 'prev-page' ) ;
64+ const nextPageButton = document . getElementById ( 'next-page' ) ;
65+ const currentPageSpan = document . getElementById ( 'current-page' ) ;
66+ const totalPagesSpan = document . getElementById ( 'total-pages' ) ;
67+ const itemDetailsColumn = document . getElementById ( 'item-details-column' ) ;
68+ const detailsIcon = document . getElementById ( 'details-icon' ) ;
69+ const detailsName = document . getElementById ( 'details-name' ) ;
70+ const detailsRecentlyListedPrice = document . getElementById ( 'details-recently-listed-price' ) ;
71+ const detailsBuyPrice = document . getElementById ( 'details-buy-price' ) ;
72+ const detailsSellPrice = document . getElementById ( 'details-sell-price' ) ;
73+ const detailsError = document . getElementById ( 'details-error' ) ;
74+ const lastUpdatedTimestampSpan = document . getElementById ( 'last-updated-timestamp' ) ;
75+ const refreshButton = document . getElementById ( 'refresh-button' ) ;
76+ const detailsPotentialProfit = document . getElementById ( 'details-potential-profit' ) ;
77+ const detailsPersonalProfit = document . getElementById ( 'details-personal-profit' ) ;
78+ const showProfitableButton = document . getElementById ( 'show-profitable-only' ) ;
79+ const personalPriceInput = document . getElementById ( 'details-personal-price' ) ;
80+ const searchProgressModal = document . getElementById ( 'search-progress-modal' ) ;
81+ const searchProgressContent = document . getElementById ( 'search-progress-content' ) ;
82+ const searchProgressMessage = document . getElementById ( 'search-progress-message' ) ;
83+ const searchProgressBarContainer = document . getElementById ( 'search-progress-bar-container' ) ;
84+ const searchProgressBar = document . getElementById ( 'search-progress-bar' ) ;
85+ const cancelSearchButton = document . getElementById ( 'cancel-search-button' ) ;
86+
87+
88+ // --- Local Storage Functions ---
89+ function loadPersonalPrices ( ) {
90+ try {
91+ const storedPrices = localStorage . getItem ( 'fo2PersonalPrices' ) ;
92+ personalPrices = storedPrices ? JSON . parse ( storedPrices ) : { } ;
93+ console . log ( "Loaded personal prices:" , Object . keys ( personalPrices ) . length ) ;
94+ } catch ( error ) {
95+ console . error ( "Failed to load personal prices:" , error ) ;
96+ personalPrices = { } ; // Reset on error
97+ }
98+ }
99+
100+ function savePersonalPrice ( itemId , price ) {
101+ if ( itemId == null ) return ;
102+ const stringItemId = String ( itemId ) ;
103+
104+ const priceValue = price === '' ? null : parseFloat ( price ) ;
105+
106+ if ( priceValue === null || ( ! isNaN ( priceValue ) && priceValue >= 0 ) ) {
107+ if ( priceValue === null || price === '' ) {
108+ delete personalPrices [ stringItemId ] ;
109+ } else {
110+ personalPrices [ stringItemId ] = priceValue ;
111+ }
112+ > >>> >>> parent of 4 d7103b ( removing last update timestamp )
7113 try {
8114 console . log ( 'Loading mock item data...' ) ;
9115 // Mock data structure - replace with your actual JSON loading
@@ -109,6 +215,57 @@ const API_BASE_URL = 'https://fantasyonline2.com/api/public';
109215 displayItemDetails ( itemId ) ;
110216 }
111217 }
218+ < << << << HEAD
219+ = === ===
220+ } ) ;
221+ console . log ( 'Database load successfully:' , ( validItems ) ) ;
222+ // databaseStatus.innerHTML = `<div class="database-status"><span>Item database loaded successfully (${validItems} items)</span></div>`;
223+ return true ;
224+ } catch ( error ) {
225+ console . error ( 'Database load error:' , error ) ;
226+ // databaseStatus.innerHTML = `<div class="database-status error"><span>Failed to load item database: ${error.message}</span><button onclick="location.reload()">Retry</button></div>`;
227+ return false ;
228+ }
229+ }
230+
231+ function findItemById ( itemId ) { return itemDatabase ?. [ String ( itemId ) ] || null ; }
232+ function formatNumber ( num ) { return ( num == null || isNaN ( num ) ) ? 'N/A' : num . toLocaleString ( ) ; }
233+ function formatPrice ( price ) { return ( price == null || price === "" || isNaN ( price ) ) ? 'N/A' : `${ formatNumber ( price ) } Coins` ; }
234+ function setTableLoading ( loading ) { if ( loading ) { resultsBody . innerHTML = `<tr><td colspan="3" style="text-align:center; padding: 30px;"><div class="loading-spinner"></div></td></tr>` ; } }
235+ function updateTimestampDisplay ( ) { lastUpdatedTimestampSpan . textContent = lastUpdateTime ? `Last Updated: ${ lastUpdateTime . toLocaleTimeString ( ) } ` : 'Last Updated: Never' ; }
236+
237+ async function searchMarket ( page = currentPage , term = searchInput . value . trim ( ) , sort = currentSort , direction = currentDirection ) {
238+ const isForComprehensive = isComprehensiveSearchActive ; // Snapshot state
239+ if ( isLoading && ! isForComprehensive ) return { error : "Already loading" } ;
240+
241+ isLoading = true ;
242+ disableControls ( true , isForComprehensive ) ; // Disable controls
243+ if ( ! isForComprehensive ) {
244+ setTableLoading ( true ) ;
245+ messageContainer . innerHTML = '' ;
246+ }
247+ lastApiSearchTerm = term ;
248+
249+ if ( abortController ) { abortController . abort ( "New search started" ) ; }
250+ abortController = new AbortController ( ) ;
251+ const signal = abortController . signal ;
252+
253+ try {
254+ const response = await fetch ( `${ API_BASE_URL } /market/search` , {
255+ method : 'POST' ,
256+ headers : { 'Content-Type' : 'application/json' , 'x-api-key' : API_KEY } ,
257+ body : JSON . stringify ( { search_term : term , sort_by : sort , sort_direction : direction , page : page } ) ,
258+ signal : signal
259+ } ) ;
260+
261+ if ( ! response . ok ) {
262+ let errorData ;
263+ try { errorData = await response . json ( ) ; } catch { errorData = null ; }
264+ let errorMsg = `API Error: ${ response . status } ${ response . statusText } . ${ errorData ?. message || '' } ` ;
265+ if ( response . status === 429 ) errorMsg = `API Rate Limit Hit. Please wait. ${ errorData ?. message || '' } ` ;
266+ else if ( response . status === 401 ) errorMsg = `API Authentication Error (Invalid Key?). ${ errorData ?. message || '' } ` ;
267+ throw new Error ( errorMsg ) ;
268+ > >>> >>> parent of 4 d7103b ( removing last update timestamp )
112269 }
113270
114271 async function loadItemDatabase ( ) {
@@ -132,6 +289,15 @@ const API_BASE_URL = 'https://fantasyonline2.com/api/public';
132289 return false ;
133290 }
134291 }
292+ << < << << HEAD
293+ === = ===
294+ updatePagination ( ) ;
295+ applyClientSideFilter ( ) ; // Filter and display the new data
296+ resultsContainer . style . display = 'flex' ;
297+ lastUpdateTime = new Date ( ) ;
298+ updateTimestampDisplay ( ) ;
299+ return data ; // Return data
300+ > >>> >>> parent of 4 d7103b ( removing last update timestamp )
135301
136302 function findItemById ( itemId ) {
137303 return itemDatabase ?. [ String ( itemId ) ] || null ;
@@ -600,11 +766,21 @@ const API_BASE_URL = 'https://fantasyonline2.com/api/public';
600766 }
601767 } ) ;
602768
769+ < << << << HEAD
603770 personalPriceInput . addEventListener ( 'change' , ( ) => {
604771 if ( selectedItemId ) {
605772 savePersonalPrice ( selectedItemId , personalPriceInput . value ) ;
606773 }
607774 } ) ;
775+ = === ===
776+ // --- Initial Load ---
777+ async function initializeApp ( ) {
778+ try {
779+ loadPersonalPrices ( ) ; // Load personal prices (if applicable)
780+ await loadEmbeddedItemData ( ) ; // Ensure JSON data is loaded before proceeding
781+ const dbLoaded = await loadItemDatabase ( ) ; // Load the item database after JSON is loaded
782+ updateTimestampDisplay ( ) ; // Update timestamp display
783+ > >>> >>> parent of 4 d7103b ( removing last update timestamp )
608784
609785 showProfitableButton . addEventListener ( 'click' , function ( ) {
610786 if ( isLoading ) return ;
0 commit comments