mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-23 15:36:33 +00:00
fix(atlas): count shared days for every member, keep routes and multi-day tours honest (STA-02)
A day of a tour that names nobody now counts for every member of the trip, not only for its owner. In the planner an empty participant list means everyone, and a full member list is stored back as empty, so members got nothing for most shared tours. Only a day that names participants without the user stays theirs. The tours of a shared trip on no day or only on undated days are now named as not counting for members as well. A whole route a multi-day tour's stages were planned from is no longer dropped on the server as soon as any stage has a day. Each entry carries derived_from_place_id and the shared summary leaves the route out only while one of its stages is done, counted and in the period and type. A route walked last year now still counts when a stage of it is planned for next month or was left out because it fell through, in the Atlas and over MCP alike. A tour on several days is dated on the last of them, as is a recording on no day, so it no longer counts while it is still under way. The info text, the get_tour_activity_stats description and the wiki say so.
This commit is contained in:
@@ -1263,7 +1263,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'جولاتي المنجزة',
|
||||
'tours.stats.sub': 'بناءً على تخطيط رحلتك؛ وتحل المسارات الفعلية المرتبطة محله',
|
||||
'tours.stats.basisInfo':
|
||||
'تُحتسب الجولة بعد انتهاء يومها، بقيم تخطيطك. ويحل المسار الفعلي المرتبط محلها. لا تُحتسب إلا الأيام التي تشارك فيها.',
|
||||
'تُحتسب الجولة بعد انتهاء آخر أيامها، بقيم تخطيطك. ويحل المسار الفعلي المرتبط محلها. اليوم الذي يسمّي مشاركين يُحتسب لهم وحدهم.',
|
||||
'tours.stats.basisPlan': 'مخطط',
|
||||
'tours.stats.basisPlanHint': 'من تخطيط الرحلة، غير مقيس',
|
||||
'tours.stats.basisTrack': 'مسجّل',
|
||||
|
||||
@@ -1231,7 +1231,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Tamamladığım turlar',
|
||||
'tours.stats.sub': 'Səyahət planına əsasən; əlaqələndirilmiş faktiki izlər onu əvəz edir',
|
||||
'tours.stats.basisInfo':
|
||||
'Tur günü bitəndə planlamanın dəyərləri ilə sayılır. Əlaqələndirilmiş faktiki iz onları əvəz edir. Yalnız iştirak etdiyin günlər sayılır.',
|
||||
'Tur son günü bitəndə planlamanın dəyərləri ilə sayılır. Əlaqələndirilmiş faktiki iz onları əvəz edir. İştirakçıları göstərilən gün yalnız onlar üçün sayılır.',
|
||||
'tours.stats.basisPlan': 'Planlaşdırılıb',
|
||||
'tours.stats.basisPlanHint': 'Səyahət planından, ölçülməyib',
|
||||
'tours.stats.basisTrack': 'Qeydə alınıb',
|
||||
|
||||
@@ -1243,7 +1243,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Meus passeios realizados',
|
||||
'tours.stats.sub': 'Com base no planejamento da viagem; trilhas reais vinculadas o substituem',
|
||||
'tours.stats.basisInfo':
|
||||
'Um passeio conta quando o dia dele termina, com os valores do seu planejamento. Uma trilha real vinculada os substitui. Só contam os dias em que você participa.',
|
||||
'Um passeio conta quando o último dia dele termina, com os valores do seu planejamento. Uma trilha real vinculada os substitui. Um dia que indica participantes conta só para eles.',
|
||||
'tours.stats.basisPlan': 'Planejado',
|
||||
'tours.stats.basisPlanHint': 'Do planejamento da viagem, não medido',
|
||||
'tours.stats.basisTrack': 'Gravado',
|
||||
|
||||
@@ -1250,7 +1250,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Les meves excursions fetes',
|
||||
'tours.stats.sub': 'Segons la planificació del viatge; els traços reals vinculats la substitueixen',
|
||||
'tours.stats.basisInfo':
|
||||
'Una excursió compta quan el seu dia s’ha acabat, amb els valors de la teva planificació. Un traç real vinculat els substitueix. Només compten els dies en què participes.',
|
||||
'Una excursió compta quan el seu últim dia s’ha acabat, amb els valors de la teva planificació. Un traç real vinculat els substitueix. Un dia que indica participants només compta per a ells.',
|
||||
'tours.stats.basisPlan': 'Planificat',
|
||||
'tours.stats.basisPlanHint': 'De la planificació del viatge, no mesurat',
|
||||
'tours.stats.basisTrack': 'Enregistrat',
|
||||
|
||||
@@ -1229,7 +1229,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Moje absolvované výlety',
|
||||
'tours.stats.sub': 'Podle plánu cesty; propojené skutečné trasy ho nahrazují',
|
||||
'tours.stats.basisInfo':
|
||||
'Výlet se započítá, jakmile jeho den skončí, s hodnotami z tvého plánu. Propojená skutečná trasa je nahradí. Počítají se jen dny, kterých se účastníš.',
|
||||
'Výlet se započítá, jakmile skončí jeho poslední den, s hodnotami z tvého plánu. Propojená skutečná trasa je nahradí. Den, který uvádí účastníky, se počítá jen jim.',
|
||||
'tours.stats.basisPlan': 'Plánováno',
|
||||
'tours.stats.basisPlanHint': 'Z plánu cesty, neměřeno',
|
||||
'tours.stats.basisTrack': 'Zaznamenáno',
|
||||
|
||||
@@ -1257,7 +1257,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Meine Touraktivitäten',
|
||||
'tours.stats.sub': 'Auf Basis deiner Reiseplanung; verknüpfte Ist-Tracks ersetzen sie',
|
||||
'tours.stats.basisInfo':
|
||||
'Eine Tour zählt, sobald ihr Tag vorbei ist, mit den Werten deiner Planung. Ein verknüpfter Ist-Track ersetzt sie. Es zählen nur Tage, an denen du teilnimmst.',
|
||||
'Eine Tour zählt, sobald ihr letzter Tag vorbei ist, mit den Werten deiner Planung. Ein verknüpfter Ist-Track ersetzt sie. Ein Tag, der Teilnehmende nennt, zählt nur für sie.',
|
||||
'tours.stats.basisPlan': 'Geplant',
|
||||
'tours.stats.basisPlanHint': 'Aus deiner Reiseplanung, nicht gemessen',
|
||||
'tours.stats.basisTrack': 'Aufgezeichnet',
|
||||
|
||||
@@ -1218,7 +1218,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'My tour activities',
|
||||
'tours.stats.sub': 'Based on your trip planning; linked actual tracks replace it',
|
||||
'tours.stats.basisInfo':
|
||||
'A tour counts once its day is over, with the values of your planning. A linked actual track replaces them. Only days you take part in count.',
|
||||
'A tour counts once its last day is over, with the values of your planning. A linked actual track replaces them. A day that names participants counts only for them.',
|
||||
'tours.stats.basisPlan': 'Planned',
|
||||
'tours.stats.basisPlanHint': 'From your trip planning, not measured',
|
||||
'tours.stats.basisTrack': 'Recorded',
|
||||
|
||||
@@ -1243,7 +1243,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Mis excursiones realizadas',
|
||||
'tours.stats.sub': 'Según la planificación de tu viaje; los tracks reales vinculados la sustituyen',
|
||||
'tours.stats.basisInfo':
|
||||
'Una excursión cuenta cuando su día ha terminado, con los valores de tu planificación. Un track real vinculado los sustituye. Solo cuentan los días en los que participas.',
|
||||
'Una excursión cuenta cuando su último día ha terminado, con los valores de tu planificación. Un track real vinculado los sustituye. Un día que indica participantes solo cuenta para ellos.',
|
||||
'tours.stats.basisPlan': 'Planificado',
|
||||
'tours.stats.basisPlanHint': 'Según la planificación del viaje, no medido',
|
||||
'tours.stats.basisTrack': 'Grabado',
|
||||
|
||||
@@ -1227,7 +1227,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Minu tehtud retked',
|
||||
'tours.stats.sub': 'Reisi planeerimise põhjal; lingitud tegelikud rajad asendavad selle',
|
||||
'tours.stats.basisInfo':
|
||||
'Retk läheb arvesse, kui selle päev on läbi, sinu planeerimise väärtustega. Lingitud tegelik rada asendab need. Arvesse lähevad ainult päevad, millest võtad osa.',
|
||||
'Retk läheb arvesse, kui selle viimane päev on läbi, sinu planeerimise väärtustega. Lingitud tegelik rada asendab need. Päev, millel on osalejad nimetatud, läheb arvesse ainult neile.',
|
||||
'tours.stats.basisPlan': 'Planeeritud',
|
||||
'tours.stats.basisPlanHint': 'Reisi planeerimisest, mõõtmata',
|
||||
'tours.stats.basisTrack': 'Salvestatud',
|
||||
|
||||
@@ -1267,7 +1267,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Mes sorties réalisées',
|
||||
'tours.stats.sub': 'D’après la planification de ton voyage ; les traces réelles liées la remplacent',
|
||||
'tours.stats.basisInfo':
|
||||
'Une sortie compte une fois sa journée terminée, avec les valeurs de ta planification. Une trace réelle liée les remplace. Seuls les jours auxquels tu participes comptent.',
|
||||
'Une sortie compte une fois son dernier jour terminé, avec les valeurs de ta planification. Une trace réelle liée les remplace. Un jour qui nomme des participants ne compte que pour eux.',
|
||||
'tours.stats.basisPlan': 'Planifié',
|
||||
'tours.stats.basisPlanHint': 'D’après la planification du voyage, non mesuré',
|
||||
'tours.stats.basisTrack': 'Enregistré',
|
||||
|
||||
@@ -1270,7 +1270,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Οι εκδρομές μου',
|
||||
'tours.stats.sub': 'Με βάση τον σχεδιασμό του ταξιδιού· οι συνδεδεμένες πραγματικές διαδρομές τον αντικαθιστούν',
|
||||
'tours.stats.basisInfo':
|
||||
'Μια εκδρομή μετράει μόλις τελειώσει η μέρα της, με τις τιμές του σχεδιασμού σου. Μια συνδεδεμένη πραγματική διαδρομή τις αντικαθιστά. Μετράνε μόνο οι μέρες στις οποίες συμμετέχεις.',
|
||||
'Μια εκδρομή μετράει μόλις τελειώσει η τελευταία μέρα της, με τις τιμές του σχεδιασμού σου. Μια συνδεδεμένη πραγματική διαδρομή τις αντικαθιστά. Μια μέρα που ορίζει συμμετέχοντες μετράει μόνο για εκείνους.',
|
||||
'tours.stats.basisPlan': 'Σχεδιασμένο',
|
||||
'tours.stats.basisPlanHint': 'Από τον σχεδιασμό του ταξιδιού, χωρίς μέτρηση',
|
||||
'tours.stats.basisTrack': 'Καταγεγραμμένο',
|
||||
|
||||
@@ -1248,7 +1248,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Teljesített túráim',
|
||||
'tours.stats.sub': 'Az utazás tervezése alapján; az összekapcsolt tényleges nyomvonalak felváltják',
|
||||
'tours.stats.basisInfo':
|
||||
'Egy túra akkor számít, ha a napja véget ért, a tervezésed értékeivel. Egy összekapcsolt tényleges nyomvonal felváltja ezeket. Csak azok a napok számítanak, amelyeken részt veszel.',
|
||||
'Egy túra akkor számít, ha az utolsó napja véget ért, a tervezésed értékeivel. Egy összekapcsolt tényleges nyomvonal felváltja ezeket. Egy nap, amely résztvevőket nevez meg, csak nekik számít.',
|
||||
'tours.stats.basisPlan': 'Tervezett',
|
||||
'tours.stats.basisPlanHint': 'Az utazás tervezéséből, nem mért',
|
||||
'tours.stats.basisTrack': 'Rögzített',
|
||||
|
||||
@@ -1229,7 +1229,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Tur yang sudah kulakukan',
|
||||
'tours.stats.sub': 'Berdasarkan perencanaan perjalananmu; jejak aktual yang ditautkan menggantikannya',
|
||||
'tours.stats.basisInfo':
|
||||
'Tur dihitung setelah harinya berakhir, dengan nilai dari perencanaanmu. Jejak aktual yang ditautkan menggantikannya. Hanya hari yang kamu ikuti yang dihitung.',
|
||||
'Tur dihitung setelah hari terakhirnya berakhir, dengan nilai dari perencanaanmu. Jejak aktual yang ditautkan menggantikannya. Hari yang menyebut peserta hanya dihitung untuk mereka.',
|
||||
'tours.stats.basisPlan': 'Direncanakan',
|
||||
'tours.stats.basisPlanHint': 'Dari perencanaan perjalanan, tidak diukur',
|
||||
'tours.stats.basisTrack': 'Terekam',
|
||||
|
||||
@@ -1257,7 +1257,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Le mie escursioni svolte',
|
||||
'tours.stats.sub': 'In base alla pianificazione del viaggio; le tracce effettive collegate la sostituiscono',
|
||||
'tours.stats.basisInfo':
|
||||
'Un’escursione conta quando il suo giorno è finito, con i valori della tua pianificazione. Una traccia effettiva collegata li sostituisce. Contano solo i giorni a cui partecipi.',
|
||||
'Un’escursione conta quando il suo ultimo giorno è finito, con i valori della tua pianificazione. Una traccia effettiva collegata li sostituisce. Un giorno che indica dei partecipanti conta solo per loro.',
|
||||
'tours.stats.basisPlan': 'Pianificato',
|
||||
'tours.stats.basisPlanHint': 'Dalla pianificazione del viaggio, non misurato',
|
||||
'tours.stats.basisTrack': 'Registrato',
|
||||
|
||||
@@ -1193,7 +1193,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': '自分のツアー実績',
|
||||
'tours.stats.sub': '旅行の計画に基づく値。リンクした実際のトラックがあればそちらに置き換わります',
|
||||
'tours.stats.basisInfo':
|
||||
'ツアーはその日が終わると、計画の値で集計されます。リンクした実際のトラックがあればその値に置き換わります。参加している日だけが集計されます。',
|
||||
'ツアーは最終日が終わると、計画の値で集計されます。リンクした実際のトラックがあればその値に置き換わります。参加者が指定された日は、その参加者だけに集計されます。',
|
||||
'tours.stats.basisPlan': '計画',
|
||||
'tours.stats.basisPlanHint': '旅行の計画による値で、計測値ではありません',
|
||||
'tours.stats.basisTrack': '記録',
|
||||
|
||||
@@ -1191,7 +1191,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': '나의 투어 기록',
|
||||
'tours.stats.sub': '여행 계획 기준이며, 연결된 실제 트랙이 있으면 그것으로 대체됩니다',
|
||||
'tours.stats.basisInfo':
|
||||
'투어는 해당 날짜가 지나면 계획 값으로 집계됩니다. 연결된 실제 트랙이 있으면 그 값으로 대체됩니다. 참여하는 날만 집계됩니다.',
|
||||
'투어는 마지막 날이 지나면 계획 값으로 집계됩니다. 연결된 실제 트랙이 있으면 그 값으로 대체됩니다. 참가자가 지정된 날은 그 참가자에게만 집계됩니다.',
|
||||
'tours.stats.basisPlan': '계획',
|
||||
'tours.stats.basisPlanHint': '여행 계획의 값이며 측정값이 아닙니다',
|
||||
'tours.stats.basisTrack': '기록',
|
||||
|
||||
@@ -1250,7 +1250,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Mijn gemaakte tochten',
|
||||
'tours.stats.sub': 'Op basis van je reisplanning; gekoppelde werkelijke tracks vervangen die',
|
||||
'tours.stats.basisInfo':
|
||||
'Een tocht telt zodra zijn dag voorbij is, met de waarden van je planning. Een gekoppelde werkelijke track vervangt ze. Alleen dagen waaraan je meedoet tellen.',
|
||||
'Een tocht telt zodra zijn laatste dag voorbij is, met de waarden van je planning. Een gekoppelde werkelijke track vervangt ze. Een dag die deelnemers noemt, telt alleen voor hen.',
|
||||
'tours.stats.basisPlan': 'Gepland',
|
||||
'tours.stats.basisPlanHint': 'Uit je reisplanning, niet gemeten',
|
||||
'tours.stats.basisTrack': 'Opgenomen',
|
||||
|
||||
@@ -1271,7 +1271,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Moje odbyte wycieczki',
|
||||
'tours.stats.sub': 'Na podstawie planu podróży; połączone rzeczywiste trasy go zastępują',
|
||||
'tours.stats.basisInfo':
|
||||
'Wycieczka liczy się, gdy jej dzień się skończy, z wartościami z twojego planu. Połączona rzeczywista trasa je zastępuje. Liczą się tylko dni, w których bierzesz udział.',
|
||||
'Wycieczka liczy się, gdy skończy się jej ostatni dzień, z wartościami z twojego planu. Połączona rzeczywista trasa je zastępuje. Dzień ze wskazanymi uczestnikami liczy się tylko dla nich.',
|
||||
'tours.stats.basisPlan': 'Zaplanowane',
|
||||
'tours.stats.basisPlanHint': 'Z planu podróży, nie zmierzone',
|
||||
'tours.stats.basisTrack': 'Nagrane',
|
||||
|
||||
@@ -1278,7 +1278,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Мои пройденные туры',
|
||||
'tours.stats.sub': 'По планированию поездки; привязанные фактические треки заменяют его',
|
||||
'tours.stats.basisInfo':
|
||||
'Тур засчитывается, когда его день закончился, со значениями из твоего планирования. Привязанный фактический трек их заменяет. Учитываются только дни, в которых ты участвуешь.',
|
||||
'Тур засчитывается, когда закончился его последний день, со значениями из твоего планирования. Привязанный фактический трек их заменяет. День, в котором указаны участники, засчитывается только им.',
|
||||
'tours.stats.basisPlan': 'Запланировано',
|
||||
'tours.stats.basisPlanHint': 'Из планирования поездки, не измерено',
|
||||
'tours.stats.basisTrack': 'Записано',
|
||||
|
||||
@@ -1233,7 +1233,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Moje absolvované túry',
|
||||
'tours.stats.sub': 'Podľa plánu cesty; prepojené skutočné trasy ho nahrádzajú',
|
||||
'tours.stats.basisInfo':
|
||||
'Túra sa započíta, keď jej deň skončí, s hodnotami z tvojho plánu. Prepojená skutočná trasa ich nahradí. Počítajú sa len dni, na ktorých sa zúčastňuješ.',
|
||||
'Túra sa započíta, keď skončí jej posledný deň, s hodnotami z tvojho plánu. Prepojená skutočná trasa ich nahradí. Deň, ktorý uvádza účastníkov, sa počíta len im.',
|
||||
'tours.stats.basisPlan': 'Plánované',
|
||||
'tours.stats.basisPlanHint': 'Z plánu cesty, nemerané',
|
||||
'tours.stats.basisTrack': 'Zaznamenané',
|
||||
|
||||
@@ -1222,7 +1222,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Mina genomförda turer',
|
||||
'tours.stats.sub': 'Utifrån din reseplanering; länkade faktiska spår ersätter den',
|
||||
'tours.stats.basisInfo':
|
||||
'En tur räknas när dess dag är över, med värdena från din planering. Ett länkat faktiskt spår ersätter dem. Bara dagar du deltar i räknas.',
|
||||
'En tur räknas när dess sista dag är över, med värdena från din planering. Ett länkat faktiskt spår ersätter dem. En dag som anger deltagare räknas bara för dem.',
|
||||
'tours.stats.basisPlan': 'Planerat',
|
||||
'tours.stats.basisPlanHint': 'Från reseplaneringen, inte uppmätt',
|
||||
'tours.stats.basisTrack': 'Inspelat',
|
||||
|
||||
@@ -1174,7 +1174,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'ทัวร์ที่ฉันทำแล้ว',
|
||||
'tours.stats.sub': 'อิงจากการวางแผนทริป เส้นทางจริงที่เชื่อมไว้จะใช้แทน',
|
||||
'tours.stats.basisInfo':
|
||||
'ทัวร์จะนับเมื่อวันของทัวร์ผ่านไปแล้ว โดยใช้ค่าจากการวางแผนของคุณ เส้นทางจริงที่เชื่อมไว้จะใช้แทนค่าเหล่านั้น นับเฉพาะวันที่คุณเข้าร่วม',
|
||||
'ทัวร์จะนับเมื่อวันสุดท้ายของทัวร์ผ่านไปแล้ว โดยใช้ค่าจากการวางแผนของคุณ เส้นทางจริงที่เชื่อมไว้จะใช้แทนค่าเหล่านั้น วันที่ระบุผู้เข้าร่วมจะนับให้เฉพาะคนเหล่านั้น',
|
||||
'tours.stats.basisPlan': 'ตามแผน',
|
||||
'tours.stats.basisPlanHint': 'จากการวางแผนทริป ไม่ได้วัดจริง',
|
||||
'tours.stats.basisTrack': 'บันทึกจริง',
|
||||
|
||||
@@ -1229,7 +1229,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Tamamladığım turlar',
|
||||
'tours.stats.sub': 'Seyahat planına göre; bağlanan gerçek izler onun yerini alır',
|
||||
'tours.stats.basisInfo':
|
||||
'Bir tur, günü bittiğinde planlamandaki değerlerle sayılır. Bağlanan gerçek bir iz bunların yerini alır. Yalnızca katıldığın günler sayılır.',
|
||||
'Bir tur, son günü bittiğinde planlamandaki değerlerle sayılır. Bağlanan gerçek bir iz bunların yerini alır. Katılımcıları belirtilen bir gün yalnızca onlar için sayılır.',
|
||||
'tours.stats.basisPlan': 'Planlanan',
|
||||
'tours.stats.basisPlanHint': 'Seyahat planından, ölçülmedi',
|
||||
'tours.stats.basisTrack': 'Kaydedilen',
|
||||
|
||||
@@ -1264,7 +1264,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Мої пройдені тури',
|
||||
'tours.stats.sub': 'За плануванням подорожі; прив’язані фактичні треки замінюють його',
|
||||
'tours.stats.basisInfo':
|
||||
'Тур зараховується, коли його день завершився, зі значеннями з твого планування. Прив’язаний фактичний трек їх замінює. Враховуються лише дні, у яких ти береш участь.',
|
||||
'Тур зараховується, коли завершився його останній день, зі значеннями з твого планування. Прив’язаний фактичний трек їх замінює. День, у якому вказано учасників, зараховується лише їм.',
|
||||
'tours.stats.basisPlan': 'Заплановано',
|
||||
'tours.stats.basisPlanHint': 'З планування подорожі, не виміряно',
|
||||
'tours.stats.basisTrack': 'Записано',
|
||||
|
||||
@@ -1218,7 +1218,7 @@ const tours: TranslationStrings = {
|
||||
'tours.stats.title': 'Các chuyến tôi đã đi',
|
||||
'tours.stats.sub': 'Dựa trên kế hoạch chuyến đi; lộ trình thực tế được liên kết sẽ thay thế',
|
||||
'tours.stats.basisInfo':
|
||||
'Một chuyến được tính khi ngày của nó đã qua, với các giá trị từ kế hoạch của bạn. Lộ trình thực tế được liên kết sẽ thay thế chúng. Chỉ tính những ngày bạn tham gia.',
|
||||
'Một chuyến được tính khi ngày cuối của nó đã qua, với các giá trị từ kế hoạch của bạn. Lộ trình thực tế được liên kết sẽ thay thế chúng. Ngày có ghi người tham gia chỉ được tính cho những người đó.',
|
||||
'tours.stats.basisPlan': 'Theo kế hoạch',
|
||||
'tours.stats.basisPlanHint': 'Từ kế hoạch chuyến đi, không đo thực tế',
|
||||
'tours.stats.basisTrack': 'Đã ghi',
|
||||
|
||||
@@ -1133,7 +1133,8 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.compare.hide': '結束比較',
|
||||
'tours.stats.title': '我的遊程紀錄',
|
||||
'tours.stats.sub': '以你的行程規劃為準;已連結的實際軌跡會取代規劃值',
|
||||
'tours.stats.basisInfo': '遊程在其日期結束後計入,使用你的規劃值。已連結的實際軌跡會取代這些值。只計入你參加的日子。',
|
||||
'tours.stats.basisInfo':
|
||||
'遊程在其最後一天結束後計入,使用你的規劃值。已連結的實際軌跡會取代這些值。指定了參與者的日子只為這些參與者計入。',
|
||||
'tours.stats.basisPlan': '規劃',
|
||||
'tours.stats.basisPlanHint': '來自行程規劃,並非實測',
|
||||
'tours.stats.basisTrack': '已記錄',
|
||||
|
||||
@@ -1134,7 +1134,8 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.compare.hide': '结束比较',
|
||||
'tours.stats.title': '我的游览记录',
|
||||
'tours.stats.sub': '基于你的行程规划;已关联的实际轨迹会替代规划值',
|
||||
'tours.stats.basisInfo': '游览在其日期结束后计入,使用你的规划值。已关联的实际轨迹会替代这些值。只计入你参加的日子。',
|
||||
'tours.stats.basisInfo':
|
||||
'游览在其最后一天结束后计入,使用你的规划值。已关联的实际轨迹会替代这些值。指定了参与者的日子只为这些参与者计入。',
|
||||
'tours.stats.basisPlan': '规划',
|
||||
'tours.stats.basisPlanHint': '来自行程规划,并非实测',
|
||||
'tours.stats.basisTrack': '已记录',
|
||||
|
||||
@@ -9,17 +9,20 @@ import { z } from 'zod';
|
||||
*
|
||||
* - The plan's values stand in for the tour while nothing was recorded
|
||||
* (`basis: 'plan'`), and say so. A tour on several days still counts once
|
||||
* (`day_count` says on how many), on the first of them.
|
||||
* (`day_count` says on how many), on the last of them, so a tour still under
|
||||
* way is not done yet.
|
||||
* - A recorded track linked to an execution of the tour (ACT-01) takes the
|
||||
* plan's place (`basis: 'track'`), one entry per recording; the plan of that
|
||||
* tour is then not counted besides it, and the recording is never counted as
|
||||
* a tour of its own.
|
||||
* - An import some other tour of the trip was planned from (the whole route a
|
||||
* multi-day tour's stages were cut from) is left out while one of those
|
||||
* tours counts, so the route and its stages are never added up together.
|
||||
* multi-day tour's stages were cut from) is named by those tours in
|
||||
* `derived_from_place_id`, and the summary leaves it out while one of them
|
||||
* counts, so the route and its stages are never added up together. A stage
|
||||
* still ahead or left out does not hide the route.
|
||||
* - Only the user's own part counts: an execution names the user as one of its
|
||||
* participants, or names none and the trip is the user's own. Being able to
|
||||
* open someone else's trip makes none of its tours the user's.
|
||||
* participants, or names nobody, which in the planner means everyone of the
|
||||
* trip. A day that names participants without the user is not theirs.
|
||||
*
|
||||
* Whether an entry is done is the reader's question (`date` before today, in
|
||||
* the reader's own time zone): the server answers every entry it found, the
|
||||
@@ -39,7 +42,9 @@ export const tourActivityStatsEntrySchema = z.object({
|
||||
name: z.string(),
|
||||
tour_type: tourTypeKeySchema,
|
||||
trip: z.object({ id: idSchema, title: z.string() }),
|
||||
/** The day it was done on: the recording's day, else the first of the user's dated days the tour is on. */
|
||||
/** The whole route this tour was planned from, a stage of it; null for any other tour. */
|
||||
derived_from_place_id: idSchema.nullable(),
|
||||
/** The day it was done on: the recording's day, else the last of the user's dated days the tour is on. */
|
||||
date: tourActivityDateSchema,
|
||||
basis: tourActivityBasisSchema,
|
||||
/** The recording whose values these are; null for the plan. */
|
||||
@@ -59,8 +64,9 @@ export const tourActivityStatsResponseSchema = z.object({
|
||||
/** The newest first. */
|
||||
entries: z.array(tourActivityStatsEntrySchema),
|
||||
/**
|
||||
* Tours of the user's own trips that cannot count as done: on no day at all,
|
||||
* or only on days without a date. Said, so a missing tour is not a mystery.
|
||||
* Tours of the user's trips that cannot count as done: on no day at all, or
|
||||
* only on the user's days without a date. A whole route whose stages are on
|
||||
* the user's days is not among them. Said, so a missing tour is not a mystery.
|
||||
*/
|
||||
uncounted: z.object({
|
||||
unassigned: z.number().int().nonnegative(),
|
||||
|
||||
@@ -14,6 +14,7 @@ function entry(overrides: Partial<TourActivityStatsEntry> = {}): TourActivitySta
|
||||
name: 'Ridge',
|
||||
tour_type: 'hike',
|
||||
trip: { id: 5, title: 'Alps' },
|
||||
derived_from_place_id: null,
|
||||
date: '2026-07-02',
|
||||
basis: 'plan',
|
||||
track: null,
|
||||
@@ -183,4 +184,44 @@ describe('STA-02 summarizeTourActivities', () => {
|
||||
);
|
||||
expect(summary.done.map((item) => item.name)).toEqual(['Alpspitze', 'Zugspitze']);
|
||||
});
|
||||
|
||||
it('STA2-SUM-009: a whole route stays out while a stage planned from it is done and counted', () => {
|
||||
const route = entry({ place_id: 30, name: 'Whole route', distance_km: 60, date: '2025-08-01' });
|
||||
const stage = entry({ place_id: 31, distance_km: 20, derived_from_place_id: 30, date: '2025-08-02' });
|
||||
const summary = summarizeTourActivities([route, stage], { today: TODAY });
|
||||
expect(summary.done.map((item) => item.place_id)).toEqual([31]);
|
||||
expect(summary.totals.distanceKm.value).toBe(20);
|
||||
});
|
||||
|
||||
it('STA2-SUM-010: a stage still ahead or left out hides nothing, so the route walked before still counts', () => {
|
||||
const route = entry({ place_id: 30, name: 'Whole route', distance_km: 60, date: '2025-08-01' });
|
||||
const ahead = entry({ place_id: 31, derived_from_place_id: 30, date: '2026-11-02' });
|
||||
const upcoming = summarizeTourActivities([route, ahead], { today: TODAY });
|
||||
expect(upcoming.done.map((item) => item.place_id)).toEqual([30]);
|
||||
expect(upcoming.totals.distanceKm.value).toBe(60);
|
||||
expect(upcoming.upcoming).toBe(1);
|
||||
const leftOut = entry({ place_id: 32, derived_from_place_id: 30, date: '2025-08-02', excluded: true });
|
||||
const fellThrough = summarizeTourActivities([route, leftOut], { today: TODAY });
|
||||
expect(fellThrough.done.map((item) => [item.place_id, item.excluded])).toEqual([
|
||||
[32, true],
|
||||
[30, false],
|
||||
]);
|
||||
expect(fellThrough.totals.count).toBe(1);
|
||||
});
|
||||
|
||||
it('STA2-SUM-011: a stage outside the period does not hide the route either', () => {
|
||||
const route = entry({ place_id: 30, distance_km: 60, date: '2025-12-30' });
|
||||
const stage = entry({ place_id: 31, derived_from_place_id: 30, date: '2026-01-02' });
|
||||
const lastYear = summarizeTourActivities([route, stage], { today: TODAY, to: '2025-12-31' });
|
||||
expect(lastYear.done.map((item) => item.place_id)).toEqual([30]);
|
||||
});
|
||||
|
||||
it('STA2-SUM-012: a tour on two days is dated on the last one, so it is not done between them', () => {
|
||||
const twoDays = entry({ date: TODAY, day_count: 2 });
|
||||
expect(isTourActivityDone(twoDays, TODAY)).toBe(false);
|
||||
const summary = summarizeTourActivities([twoDays], { today: TODAY });
|
||||
expect(summary.totals.count).toBe(0);
|
||||
expect(summary.upcoming).toBe(1);
|
||||
expect(summarizeTourActivities([twoDays], { today: '2026-10-21' }).totals.count).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -76,14 +76,29 @@ function totalsOf(entries: readonly TourActivityStatsEntry[]): TourActivityTotal
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A whole route counts only while none of the stages planned from it does:
|
||||
* once a stage is done, counted and in the reader's period and type, the
|
||||
* stages stand for the route. A stage still ahead or left out hides nothing.
|
||||
*/
|
||||
function withoutRoutesOfCountedStages(
|
||||
entries: readonly TourActivityStatsEntry[],
|
||||
counted: readonly TourActivityStatsEntry[],
|
||||
): TourActivityStatsEntry[] {
|
||||
const routes = new Set(counted.map((entry) => entry.derived_from_place_id));
|
||||
return entries.filter((entry) => !routes.has(entry.place_id));
|
||||
}
|
||||
|
||||
/** The entries of the period and type, done and counted, summed as a whole and by type. */
|
||||
export function summarizeTourActivities(
|
||||
entries: readonly TourActivityStatsEntry[],
|
||||
filter: TourActivityFilter,
|
||||
): TourActivitySummary {
|
||||
const matching = entries.filter(
|
||||
const inScope = entries.filter(
|
||||
(entry) => inPeriod(entry.date, filter) && (!filter.type || entry.tour_type === filter.type),
|
||||
);
|
||||
const countedInScope = inScope.filter((entry) => !entry.excluded && isTourActivityDone(entry, filter.today));
|
||||
const matching = withoutRoutesOfCountedStages(inScope, countedInScope);
|
||||
const done = matching.filter((entry) => isTourActivityDone(entry, filter.today));
|
||||
const counted = done.filter((entry) => !entry.excluded);
|
||||
const byType = new Map<TourTypeKey, TourActivityStatsEntry[]>();
|
||||
|
||||
Reference in New Issue
Block a user