dev #1
					 1 changed files with 149 additions and 143 deletions
				
			
		|  | @ -751,7 +751,8 @@ export default function Page() { | |||
|   }, [categories]); | ||||
| 
 | ||||
| function formatTrophies(value: number) { | ||||
|   const sign = value > 0 ? '+' : ''; | ||||
|   const sign = value > 0 ? '' : '+'; | ||||
|    | ||||
|   return `${sign}${value} trophies`; | ||||
| } | ||||
| 
 | ||||
|  | @ -1117,30 +1118,31 @@ function summarizeProfileDefenses(defenses: ProfileDefense[]): Summary { | |||
|               <details> | ||||
|                 <summary><h3>Existing Categories</h3></summary> | ||||
|                 <ul className="list compact"> | ||||
|                 {categories.length ? ( | ||||
|                   categories.map((category) => ( | ||||
|                     <li key={category.id} className="list-item"> | ||||
|                       <div className="defense-header"> | ||||
|                         <span>{category.name}</span> | ||||
|                         <div className="defense-meta"> | ||||
|                           <button | ||||
|                             type="button" | ||||
|                             className="ghost small" | ||||
|                             onClick={() => handleDeleteCategory(category.id)} | ||||
|                           > | ||||
|                             Delete | ||||
|                           </button> | ||||
|                   {categories.length ? ( | ||||
|                     categories.map((category) => ( | ||||
|                       <li key={category.id} className="list-item"> | ||||
|                         <div className="defense-header"> | ||||
|                           <span>{category.name}</span> | ||||
|                           <div className="defense-meta"> | ||||
|                             <button | ||||
|                               type="button" | ||||
|                               className="ghost small" | ||||
|                               onClick={() => handleDeleteCategory(category.id)} | ||||
|                             > | ||||
|                               Delete | ||||
|                             </button> | ||||
|                           </div> | ||||
|                         </div> | ||||
|                       </div> | ||||
|                       <div className="defense-meta"> | ||||
|                         <span>{new Date(category.createdAt).toLocaleDateString()}</span> | ||||
|                       </div> | ||||
|                     </li> | ||||
|                   )) | ||||
|                 ) : ( | ||||
|                   <li>No categories yet.</li> | ||||
|                 )} | ||||
|               </ul> | ||||
|                         <div className="defense-meta"> | ||||
|                           <span>{new Date(category.createdAt).toLocaleDateString()}</span> | ||||
|                         </div> | ||||
|                       </li> | ||||
|                     )) | ||||
|                   ) : ( | ||||
|                     <li>No categories yet.</li> | ||||
|                   )} | ||||
|                 </ul> | ||||
|               </details> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div className="card"> | ||||
|  | @ -1202,40 +1204,41 @@ function summarizeProfileDefenses(defenses: ProfileDefense[]): Summary { | |||
|               <details> | ||||
|                 <summary><h3>Manage Bases</h3></summary> | ||||
|                 <ul className="list compact"> | ||||
|                 {bases.length ? ( | ||||
|                   bases.map((base) => ( | ||||
|                     <li key={base.id} className="list-item"> | ||||
|                       <div className="defense-header"> | ||||
|                         <div> | ||||
|                           <strong>{base.title}</strong>{' '} | ||||
|                           {base.isPrivate ? <span className="badge muted">Private</span> : null} | ||||
|                   {bases.length ? ( | ||||
|                     bases.map((base) => ( | ||||
|                       <li key={base.id} className="list-item"> | ||||
|                         <div className="defense-header"> | ||||
|                           <div> | ||||
|                             <strong>{base.title}</strong>{' '} | ||||
|                             {base.isPrivate ? <span className="badge muted">Private</span> : null} | ||||
|                           </div> | ||||
|                           <div className="defense-meta"> | ||||
|                             <button | ||||
|                               type="button" | ||||
|                               className="ghost small" | ||||
|                               onClick={() => startEditingBase(base.id)} | ||||
|                             > | ||||
|                               Edit | ||||
|                             </button> | ||||
|                             <button | ||||
|                               type="button" | ||||
|                               className="ghost small" | ||||
|                               onClick={() => handleDeleteBase(base.id)} | ||||
|                             > | ||||
|                               Delete | ||||
|                             </button> | ||||
|                           </div> | ||||
|                         </div> | ||||
|                         <div className="defense-meta"> | ||||
|                           <button | ||||
|                             type="button" | ||||
|                             className="ghost small" | ||||
|                             onClick={() => startEditingBase(base.id)} | ||||
|                           > | ||||
|                             Edit | ||||
|                           </button> | ||||
|                           <button | ||||
|                             type="button" | ||||
|                             className="ghost small" | ||||
|                             onClick={() => handleDeleteBase(base.id)} | ||||
|                           > | ||||
|                             Delete | ||||
|                           </button> | ||||
|                           <span>{new Date(base.createdAt).toLocaleDateString()}</span> | ||||
|                         </div> | ||||
|                       </div> | ||||
|                       <div className="defense-meta"> | ||||
|                         <span>{new Date(base.createdAt).toLocaleDateString()}</span> | ||||
|                       </div> | ||||
|                     </li> | ||||
|                   )) | ||||
|                 ) : ( | ||||
|                   <li>No bases yet.</li> | ||||
|                 )} | ||||
|               </ul> | ||||
|                       </li> | ||||
|                     )) | ||||
|                   ) : ( | ||||
|                     <li>No bases yet.</li> | ||||
|                   )} | ||||
|                 </ul> | ||||
|               </details> | ||||
|             </div> | ||||
|             {baseBeingEdited && ( | ||||
|               <div className="subsection"> | ||||
|  | @ -1396,50 +1399,51 @@ function summarizeProfileDefenses(defenses: ProfileDefense[]): Summary { | |||
|               <details> | ||||
|                 <summary><h3>Manage Attacks</h3></summary> | ||||
|                 <ul className="list compact"> | ||||
|                 {defenses.length ? ( | ||||
|                   defenses.slice(0, 10).map((defense) => { | ||||
|                     const categoryName = | ||||
|                       categoryNameMap.get(defense.armyCategoryId) || defense.categoryName || '(No category)'; | ||||
|                     return ( | ||||
|                       <li key={defense.id} className="list-item"> | ||||
|                         <div className="defense-header"> | ||||
|                           <div> | ||||
|                             <strong>{defense.baseTitle}</strong>{' '} | ||||
|                             <span className="badge">{categoryName}</span> | ||||
|                   {defenses.length ? ( | ||||
|                     defenses.slice(0, 10).map((defense) => { | ||||
|                       const categoryName = | ||||
|                         categoryNameMap.get(defense.armyCategoryId) || defense.categoryName || '(No category)'; | ||||
|                       return ( | ||||
|                         <li key={defense.id} className="list-item"> | ||||
|                           <div className="defense-header"> | ||||
|                             <div> | ||||
|                               <strong>{defense.baseTitle}</strong>{' '} | ||||
|                               <span className="badge">{categoryName}</span> | ||||
|                             </div> | ||||
|                             <div className="defense-meta"> | ||||
|                               <button | ||||
|                                 type="button" | ||||
|                                 className="ghost small" | ||||
|                                 onClick={() => startEditingDefense(defense.id)} | ||||
|                               > | ||||
|                                 Edit | ||||
|                               </button> | ||||
|                               <button | ||||
|                                 type="button" | ||||
|                                 className="ghost small" | ||||
|                                 onClick={() => handleDeleteDefense(defense.id)} | ||||
|                               > | ||||
|                                 Delete | ||||
|                               </button> | ||||
|                             </div> | ||||
|                           </div> | ||||
|                           <div className="defense-meta"> | ||||
|                             <button | ||||
|                               type="button" | ||||
|                               className="ghost small" | ||||
|                               onClick={() => startEditingDefense(defense.id)} | ||||
|                             > | ||||
|                               Edit | ||||
|                             </button> | ||||
|                             <button | ||||
|                               type="button" | ||||
|                               className="ghost small" | ||||
|                               onClick={() => handleDeleteDefense(defense.id)} | ||||
|                             > | ||||
|                               Delete | ||||
|                             </button> | ||||
|                             <span>{defense.stars}★</span> | ||||
|                             <span>{defense.percent}%</span> | ||||
|                             <span>{formatTrophies(defense.trophies)}</span> | ||||
|                             <span>{new Date(defense.createdAt).toLocaleString()}</span> | ||||
|                           </div> | ||||
|                         </div> | ||||
|                         <div className="defense-meta"> | ||||
|                           <span>{defense.stars}★</span> | ||||
|                           <span>{defense.percent}%</span> | ||||
|                           <span>{formatTrophies(defense.trophies)}</span> | ||||
|                           <span>{new Date(defense.createdAt).toLocaleString()}</span> | ||||
|                         </div> | ||||
|                       </li> | ||||
|                     ); | ||||
|                   }) | ||||
|                 ) : ( | ||||
|                   <li>No attacks logged yet.</li> | ||||
|                 )} | ||||
|               </ul> | ||||
|               {defenses.length > 10 ? ( | ||||
|                 <p className="muted">Showing the latest 10 entries.</p> | ||||
|               ) : null} | ||||
|                         </li> | ||||
|                       ); | ||||
|                     }) | ||||
|                   ) : ( | ||||
|                     <li>No attacks logged yet.</li> | ||||
|                   )} | ||||
|                 </ul> | ||||
|                 {defenses.length > 10 ? ( | ||||
|                   <p className="muted">Showing the latest 10 entries.</p> | ||||
|                 ) : null} | ||||
|               </details> | ||||
|             </div> | ||||
|             {defenseBeingEdited && ( | ||||
|               <div className="subsection"> | ||||
|  | @ -1710,28 +1714,29 @@ function summarizeProfileDefenses(defenses: ProfileDefense[]): Summary { | |||
|             <details open> | ||||
|               <summary><h3>Army Categories vs This Base</h3></summary> | ||||
|               <ul id="base-detail-categories" className="list"> | ||||
|               {baseDetail && baseDetail.categories.length ? ( | ||||
|                 baseDetail.categories.map((category) => ( | ||||
|                   <li | ||||
|                     key={category.categoryId} | ||||
|                     className="list-item clickable" | ||||
|                     onClick={() => openCategoryDetail(category.categoryId)} | ||||
|                   > | ||||
|                     <div className="defense-header"> | ||||
|                       <strong>{category.name}</strong> | ||||
|                       <span className="badge">{category.count} attacks</span> | ||||
|                     </div> | ||||
|                     <div className="defense-meta"> | ||||
|                       <span>{category.averageStars}★ avg</span> | ||||
|                       <span>{category.averagePercent}% avg</span> | ||||
|                       <span>{formatTrophies(category.averageTrophies)} avg</span> | ||||
|                     </div> | ||||
|                   </li> | ||||
|                 )) | ||||
|               ) : ( | ||||
|                 <li>No army categories have attacked this base yet.</li> | ||||
|               )} | ||||
|             </ul> | ||||
|                 {baseDetail && baseDetail.categories.length ? ( | ||||
|                   baseDetail.categories.map((category) => ( | ||||
|                     <li | ||||
|                       key={category.categoryId} | ||||
|                       className="list-item clickable" | ||||
|                       onClick={() => openCategoryDetail(category.categoryId)} | ||||
|                     > | ||||
|                       <div className="defense-header"> | ||||
|                         <strong>{category.name}</strong> | ||||
|                         <span className="badge">{category.count} attacks</span> | ||||
|                       </div> | ||||
|                       <div className="defense-meta"> | ||||
|                         <span>{category.averageStars}★ avg</span> | ||||
|                         <span>{category.averagePercent}% avg</span> | ||||
|                         <span>{formatTrophies(category.averageTrophies)} avg</span> | ||||
|                       </div> | ||||
|                     </li> | ||||
|                   )) | ||||
|                 ) : ( | ||||
|                   <li>No army categories have attacked this base yet.</li> | ||||
|                 )} | ||||
|               </ul> | ||||
|             </details> | ||||
|           </div> | ||||
|           <div className="card"> | ||||
|             <details open> | ||||
|  | @ -1776,30 +1781,31 @@ function summarizeProfileDefenses(defenses: ProfileDefense[]): Summary { | |||
|             <details open> | ||||
|               <summary><h3>Defenses</h3></summary> | ||||
|               <ul id="base-detail-defenses" className="list"> | ||||
|               {defenses.filter((defense) => defense.baseId === selectedBaseId).length ? ( | ||||
|                 defenses | ||||
|                   .filter((defense) => defense.baseId === selectedBaseId) | ||||
|                   .map((defense) => { | ||||
|                     const date = new Date(defense.createdAt); | ||||
|                     const categoryName = categoryNameMap.get(defense.armyCategoryId) || '(No category)'; | ||||
|                     return ( | ||||
|                       <li key={defense.id} className="list-item"> | ||||
|                         <div className="defense-header"> | ||||
|                           <strong>{categoryName}</strong> | ||||
|                           <div> | ||||
|                             <strong>{defense.stars}★</strong> • {defense.percent}% • {formatTrophies(defense.trophies)} | ||||
|                 {defenses.filter((defense) => defense.baseId === selectedBaseId).length ? ( | ||||
|                   defenses | ||||
|                     .filter((defense) => defense.baseId === selectedBaseId) | ||||
|                     .map((defense) => { | ||||
|                       const date = new Date(defense.createdAt); | ||||
|                       const categoryName = categoryNameMap.get(defense.armyCategoryId) || '(No category)'; | ||||
|                       return ( | ||||
|                         <li key={defense.id} className="list-item"> | ||||
|                           <div className="defense-header"> | ||||
|                             <strong>{categoryName}</strong> | ||||
|                             <div> | ||||
|                               <strong>{defense.stars}★</strong> • {defense.percent}% • {formatTrophies(defense.trophies)} | ||||
|                             </div> | ||||
|                           </div> | ||||
|                         </div> | ||||
|                         <div className="defense-meta"> | ||||
|                           <span>{date.toLocaleString()}</span> | ||||
|                         </div> | ||||
|                       </li> | ||||
|                     ); | ||||
|                   }) | ||||
|               ) : ( | ||||
|                 <li>No defenses recorded for this base yet.</li> | ||||
|               )} | ||||
|             </ul> | ||||
|                           <div className="defense-meta"> | ||||
|                             <span>{date.toLocaleString()}</span> | ||||
|                           </div> | ||||
|                         </li> | ||||
|                       ); | ||||
|                     }) | ||||
|                 ) : ( | ||||
|                   <li>No defenses recorded for this base yet.</li> | ||||
|                 )} | ||||
|               </ul> | ||||
|             </details> | ||||
|           </div> | ||||
|         </section> | ||||
| 
 | ||||
|  | @ -1888,7 +1894,7 @@ function summarizeProfileDefenses(defenses: ProfileDefense[]): Summary { | |||
|                 </ul> | ||||
|               </div> | ||||
|               <div className="card"> | ||||
|                 <details> | ||||
|                 <details open> | ||||
|                   <summary><h3>Recent Resets</h3></summary> | ||||
|                   <ul className="list compact"> | ||||
|                     {profileSelectedBase.trophyResets.length ? ( | ||||
|  | @ -1897,7 +1903,7 @@ function summarizeProfileDefenses(defenses: ProfileDefense[]): Summary { | |||
|                           <div className="defense-header"> | ||||
|                             <span>{new Date(reset.date).toLocaleDateString()}</span> | ||||
|                             <div className="defense-meta"> | ||||
|                               <span>{reset.trophiesAtStart} trophies </span> | ||||
|                               <span>{reset.trophiesAtStart} trophies at start</span> | ||||
|                               <span>{formatTrophies(reset.trophiesLost)} lost</span> | ||||
|                               <span>{reset.numberOfDefenses} defenses</span> | ||||
|                             </div> | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue