Skip to content

feat: add issuer specific fip validity to operator pages#684

Open
MoritzWeber0 wants to merge 68 commits intomainfrom
feat/fip-validity
Open

feat: add issuer specific fip validity to operator pages#684
MoritzWeber0 wants to merge 68 commits intomainfrom
feat/fip-validity

Conversation

@MoritzWeber0
Copy link
Member

@MoritzWeber0 MoritzWeber0 commented Feb 8, 2026

For each FIP issues a file called validity.yaml can be added to the corresponding operator directory, including information which how many coupons for which operator are issued. For example, let's have a look the at validity.yaml for FIP issuer DB:

_anchors:
  coupon-4fields: &coupon-4fields
    status: valid
    text:
      de: "1 Freifahrtschein mit jeweils 4 Feldern pro Jahr. Jedes Feld ist zwei Tage gültig."
      en: "1 coupon with 4 fields each per year. Each field is valid for two days."
      fr: "1 coupon avec 4 champs chacun par an. Chaque champ est valable deux jours."
  coupon-not-available: &coupon-not-available
    status: invalid
    text:
      de: "Nicht verfügbar"
      en: "Not available"
      fr: "Non disponible"
  reduced-50: &reduced-50
    status: valid
    text:
      de: "50 % Rabatt"
      en: "50 % discount"
      fr: "50 % de réduction"
pkp:
  fip-coupon: *coupon-4fields
  fip-coupon-relatives: *coupon-4fields
  fip-reduced-ticket: *reduced-50
zssk:
  fip-coupon: *coupon-4fields
  fip-coupon-relatives: *coupon-not-available
  fip-reduced-ticket: *reduced-50

Resolves #446

TODO:

@netlify
Copy link

netlify bot commented Feb 8, 2026

Deploy Preview for fipguide ready!

Name Link
🔨 Latest commit b5bf5ea
🔍 Latest deploy log https://app.netlify.com/projects/fipguide/deploys/69b33e9e704d810008899fbf
😎 Deploy Preview https://deploy-preview-684--fipguide.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@MoritzWeber0
Copy link
Member Author

Should be ready for review now, @lenderom @therobrob. I'll keep it in the draft state until #680 is merged as this PR is based on it and should not be merged before.

@lenderom
Copy link
Member

lenderom commented Feb 9, 2026

@MoritzWeber0 Thank you for your implementation. I think this will help many of our collegues. Do you think we should implement a kind of "Default" per employer? Like usually SNCF gives 1 Coupon with 4 Fields and we only specify the deviations on the operator site?

@MoritzWeber0
Copy link
Member Author

MoritzWeber0 commented Feb 9, 2026

@MoritzWeber0 Thank you for your implementation. I think this will help many of our collegues. Do you think we should implement a kind of "Default" per employer? Like usually SNCF gives 1 Coupon with 4 Fields and we only specify the deviations on the operator site?

I'm against an implicitly added default. We should only add explicit information if we have it, otherwise let's fall back to unknown. The only reason would be less boilerplate (the YAML section grows a bit too quickly maybe). But there are probably better solutions like defining some defaults globally and then just reference them via a one-liner.

@lenderom
Copy link
Member

lenderom commented Feb 9, 2026

@MoritzWeber0 Thank you for your implementation. I think this will help many of our collegues. Do you think we should implement a kind of "Default" per employer? Like usually SNCF gives 1 Coupon with 4 Fields and we only specify the deviations on the operator site?

I'm against an implicitly added default. We should only add explicit information if we have it, otherwise let's fall back to unknown. The only reason would be less boilerplate (the YAML section grows a bit too quickly maybe). But there are probably better solutions like defining some defaults globally and then just reference them via a one-liner.

Yeah I was more thinking about the boilerplate, not a "default" information but a way to avoid writing on every page "SBB employees have 8 fields every field is valid for one day" :D
But it's not a must have. Just an idea to avoid extremly large yaml metadata :)

@lenderom
Copy link
Member

lenderom commented Feb 9, 2026

Another point I was thinking about was the considerationfo things like #681

It doesn't have to be implemented in this PR, I was just thinking about covering this problem in your implementation. For example instead of having a row in the table for the FIP Coupon there could be a text like "unlimited free travel". But we could also find other ways of covering this topic :)

@MoritzWeber0
Copy link
Member Author

Another point I was thinking about was the considerationfo things like #681

It doesn't have to be implemented in this PR, I was just thinking about covering this problem in your implementation. For example instead of having a row in the table for the FIP Coupon there could be a text like "unlimited free travel". But we could also find other ways of covering this topic :)

This is the reason why I removed some of the structured data from the previous PR and made it more flexible with the text :)
But for #681 I would need more information about who exactly gets those free benefits. So rather a separate PR.

Copy link
Member

@therobrob therobrob left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve just reviewed the technical parts, not the md-files.

Two further comments:

  • for me it seems slightly confusing showing the grey status with question marks for cases, where we don’t know the information from all operators. It suggests we have no information at all. I think this case is very common, until we don’t have the information from all operators.
    Edit: why do we handle the same case ("we don’t have information from all operators") in two different ways?
    One time we say "valid" and one time we say "unknown" – where’s the difference between them?
Bildschirmfoto 2026-02-09 um 19 32 08
  • this leads me to the second aspect: the button for the dialog isn’t optimal in my opinion. It is not self-explanatory, because there is no label and there is the second status-icon to the left (two icons, two different meanings for interacting). I envision a single, comprehensive button, so the user can click the whole information.

@MoritzWeber0 MoritzWeber0 force-pushed the feat/add-dialogs branch 2 times, most recently from 1b5a622 to ea75e56 Compare February 10, 2026 08:02
Base automatically changed from feat/add-dialogs to main February 24, 2026 21:35
@MoritzWeber0 MoritzWeber0 marked this pull request as ready for review February 25, 2026 16:51
@MoritzWeber0
Copy link
Member Author

The table is now also available in the reverse format to find out for which operator how many coupons can be requested: https://deploy-preview-684--fipguide.netlify.app/de/fip-validity/

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds issuer-specific FIP validity data (via per-issuer validity.yaml) and renders it on operator pages and on a new comparison page, so users can see coupon issuance and FIP50/75 reductions depending on their FIP card issuer.

Changes:

  • Introduce new Hugo shortcodes/partials to render FIP validity badges, dialogs, issuer dropdowns, and comparison tables.
  • Add issuer validity.yaml datasets for multiple issuers and update many operator pages to use the new fip-validity shortcode.
  • Add comparison page (/fip-validity) plus JS/CSS to drive issuer selection UI and responsive table/card layouts.

Reviewed changes

Copilot reviewed 115 out of 115 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
layouts/shortcodes/fip-validity.html New shortcode wrapper for rendering a single validity badge + optional dialog.
layouts/shortcodes/fip-validity-comparison.html New shortcode wrapper for rendering the comparison UI.
layouts/partials/fip-validity/main.html Renders the clickable validity badge and (optionally) the dialog trigger/content.
layouts/partials/fip-validity/dialog.html Builds issuer-specific dialog content by reading issuers’ validity.yaml.
layouts/partials/fip-validity/issuer-dropdown.html Dropdown UI for selecting the FIP issuer (used on comparison page and dialogs).
layouts/partials/fip-validity/value.html Renders a single status/value cell (icon + localized text).
layouts/partials/fip-validity/table.html Renders the comparison table for an issuer/type across operators.
layouts/partials/fip-validity/comparison.html Assembles the full comparison page UI for coupon + reduced ticket.
layouts/news/single.html Adds wrapper class to enable horizontal overflow handling for wide content (tables).
layouts/_default/single.html Adds wrapper class to enable horizontal overflow handling for wide content (tables).
i18n/de.yaml Adds German translations for FIP validity UI texts and descriptions.
i18n/en.yaml Adds English translations for FIP validity UI texts and descriptions.
i18n/fr.yaml Adds French translations for FIP validity UI texts and descriptions.
content/fip-validity/index.de.md New DE comparison landing page embedding the comparison shortcode.
content/fip-validity/index.en.md New EN comparison landing page embedding the comparison shortcode.
content/fip-validity/index.fr.md New FR comparison landing page embedding the comparison shortcode.
content/generalinformation/faq/what-rules-apply-to-fip-coupons/_index.de.md Updates FAQ answer to point to the new comparison page.
content/generalinformation/faq/what-rules-apply-to-fip-coupons/_index.en.md Updates FAQ answer to point to the new comparison page.
content/generalinformation/faq/what-rules-apply-to-fip-coupons/_index.fr.md Updates FAQ answer to point to the new comparison page.
content/operator/db/validity.yaml Adds DB-issued card validity matrix for multiple target operators.
content/operator/gb/validity.yaml Adds GB-issued card validity matrix for multiple target operators.
content/operator/ns/validity.yaml Adds NS-issued card validity matrix for multiple target operators.
content/operator/sncb/validity.yaml Adds SNCB-issued card validity matrix for multiple target operators.
content/operator/sncf/validity.yaml Adds SNCF-issued card validity matrix for multiple target operators.
content/operator/cd/validity.yaml Adds ČD-issued card validity matrix for multiple target operators.
content/operator/bdz/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/bdz/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/bdz/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/bls/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/bls/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/bls/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/bsb/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/bsb/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/bsb/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/cd/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/cd/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/cd/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/cfl/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/cfl/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/cfl/index.fr.md Replaces inline validity list with fip-validity shortcodes (and normalizes apostrophes).
content/operator/cp/index.de.md Replaces inline validity list with fip-validity shortcodes (incl. Global Fare).
content/operator/cp/index.en.md Replaces inline validity list with fip-validity shortcodes (incl. Global Fare).
content/operator/cp/index.fr.md Replaces inline validity list with fip-validity shortcodes (incl. Global Fare).
content/operator/db/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/db/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/db/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/dsb/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/dsb/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/dsb/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/eurostar/index.de.md Replaces inline validity list with fip-validity shortcodes (dialog disabled).
content/operator/eurostar/index.en.md Replaces inline validity list with fip-validity shortcodes (dialog disabled).
content/operator/eurostar/index.fr.md Replaces inline validity list with fip-validity shortcodes (dialog disabled).
content/operator/euskotren/index.de.md Replaces inline validity list with fip-validity shortcodes (uses additional).
content/operator/euskotren/index.en.md Replaces inline validity list with fip-validity shortcodes (uses additional).
content/operator/euskotren/index.fr.md Replaces inline validity list with fip-validity shortcodes (uses additional).
content/operator/fs/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/fs/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/fs/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/gb/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/gb/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/gb/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/gysev/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/gysev/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/gysev/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/kd/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/kd/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/kd/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/ltg/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/ltg/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/ltg/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/ns/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/ns/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/ns/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/oebb/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/oebb/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/oebb/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/pkp/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/pkp/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/pkp/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/renfe/index.de.md Replaces inline validity list with fip-validity shortcodes (incl. Global Fare).
content/operator/renfe/index.en.md Replaces inline validity list with fip-validity shortcodes (incl. Global Fare).
content/operator/renfe/index.fr.md Replaces inline validity list with fip-validity shortcodes (incl. Global Fare).
content/operator/sbb/index.de.md Replaces inline validity list with fip-validity shortcodes; normalizes heading text.
content/operator/sbb/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/sbb/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/sncb/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/sncb/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/sncb/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/sncf/index.de.md Replaces inline validity list with fip-validity shortcodes (incl. Global Fare, dialog disabled).
content/operator/sncf/index.en.md Replaces inline validity list with fip-validity shortcodes (incl. Global Fare, dialog disabled).
content/operator/sncf/index.fr.md Replaces inline validity list with fip-validity shortcodes (incl. Global Fare, dialog disabled).
content/operator/sp/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/sp/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/sp/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/stl/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/stl/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/stl/index.fr.md Replaces inline validity list with fip-validity shortcodes.
content/operator/zssk/index.de.md Replaces inline validity list with fip-validity shortcodes.
content/operator/zssk/index.en.md Replaces inline validity list with fip-validity shortcodes.
content/operator/zssk/index.fr.md Replaces inline validity list with fip-validity shortcodes.
assets/js/main.js Registers the new comparison behavior script in the main bundle.
assets/js/fipValidityComparison.js Adds issuer selection + persistence + syncing across dropdown instances.
assets/js/dropdown.js Registers dropdown behavior for the new issuer dropdown instances; adds closeDropdown export.
assets/sass/main.scss Includes the new fip-validity.scss stylesheet.
assets/sass/fip-validity.scss New styling for validity badges, tables, cards, and issuer dropdown layout.
assets/sass/styles.scss Enables horizontal scrolling for content wrapper (wide tables).
assets/sass/dropdown.scss Adjusts dropdown menu border/margins (used by issuer dropdown).
assets/sass/dialog.scss Adjusts dialog body height behavior (supports full-height dialogs).
assets/sass/button.scss Improves disabled button interaction styling/behavior.
assets/sass/_variables.scss Adds CSS variables for validity colors and a visible border token.
archetypes/operator/index.de.md Updates operator archetype to use the new fip-validity shortcodes.
archetypes/operator/index.en.md Updates operator archetype to use the new fip-validity shortcodes.
archetypes/operator/index.fr.md Updates operator archetype to use the new fip-validity shortcodes.
AGENTS.md Updates translation reference table wording/formatting.
.pre-commit-config.yaml Adjusts YAML hook configuration for the new validity YAML files.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.


{{< fip-validity type="fip-coupon" status="valid" >}}
{{< fip-validity type="fip-reduced-ticket" status="valid" >}}
{{< fip-validity type="fip-global-fare" status="valid" >}}
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as in the EN archetype: the Global Fare shortcode will open a dialog that looks up fipValidity.fip-global-fare-description, but that translation key is missing. Add the missing translation keys or disable the dialog for this type in the archetype.

Suggested change
{{< fip-validity type="fip-global-fare" status="valid" >}}
{{< fip-validity type="fip-global-fare" status="valid" disable_dialog="true" >}}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

content Improvements or additions to the content (countries, news, operators, general content) technical Technical issues, e.g. related to Hugo, HTML, CSS, deployment, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Issue with operator ÖBB Number of FIP Coupons and Reduction

4 participants