You are responsible for keeping your account information secure and confidential You are the only person who should use your account and have access to your account’s password and login details. To improve your account security, we advise using a password with a combination of numbers, lowercase letters and uppercase letters. We are not responsible for any loss or damage incurred to your account and cannot be held responsible for its theft (e.g., via phishing). Note that we will never ask you for your log-in details such as your password.
Your activity on the platform To ensure safe and productive participation, there are some restrictions on the type of content that may be published on this platform. Any content you post on the platform must be free of:
Private data Confidential data and personal information about others, such as telephone numbers and addresses may not be posted without their express authorization and consent.
Spam / malware / phishing / viruses / worms / Trojans Malicious content or links that are meant violate others’ privacy or to damage or disrupt others’ browsers or computers.
Threats, insults and other inappropriate content Personal attacks and insults, threatening behavior or language, discriminatory comments, profanity and other offensive language.
Advertising and commercial activity Content posted with the sole purpose of advertising a commercial service or product.
Copyrighted material Content that infringes upon intellectual property rights (e.g., copyrighted images).
Illegal activities Content that in any way promotes illegal activities.
Submissions and other content that includes any of the above may be edited, deleted or otherwise prevented from being posted, and the account may be temporarily blocked or permanently deleted. New or additional accounts created to avoid temporary or permanent suspension may also be monitored and deleted.
Applicable laws The use of an account may not infringe upon applicable laws. This includes any violation of privacy legislation, intellectual property rights, the criminal code, etc.
We cannot be held liable in any way for content posted on the platform that does not adhere to the above rules and laws. Violations can be reported to support@govocal.com and may result in the relevant messages being deleted and/or the underlying account being suspended or permanently revoked.
It is possible that content posted on the platform can contain harmful files or links. By downloading files or accessing hyperlinks via the platform, you assume the risk and responsibility for any damage that may incur.
Property rights This platform is protected by intellectual property rights related to its content, source code, databases, etc. Any original content that you post on the platform may be visible to the public and falls under the Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) Public License, which allows your content to be shared or adapted with attribution. You may not otherwise reproduce, distribute, modify or transmit the platform and any of its contents that do not fall under the public domain without permission.
+ privacy_policy_title: Polisi Preifatrwydd
+ privacy_policy_body: >
+ Responsible for the processing of the Data:
CitizenLab NV - Pachecolaan 34 - 1000 Brussels - Belgium
Contact e-mail address: support@govocal.com
Organization: //insert client contacts
1. PRIVACY POLICY This ‘Privacy Policy’ applies to the ‘Personal Data’ collected by Go Vocal on behalf of the organization through this website.
2. WHAT ARE PERSONAL DATA? In this Privacy Policy, Personal Data refers to information that makes it possible to identify you. An identifiable person is someone who can be identified, either directly or indirectly, in particular by referring to an identification number or to one or more factors that are linked to physical, physiological, mental, economic, cultural or social identity. A typical example of personal information is your name and email address.
3. WHAT PERSONAL DATA DO WE COLLECT? We might collect your Personal Data from the following three sources:
3.1 Personal Data that you provide during the registration process on the Platform, some of which are optional. The personal data that we might collect from you are:
First and last name E-mail address Year of birth Gender Area of residence Preferred language This list can be extended on request of the organization. If you choose to sign-in via a 3rd party authentication provider as Google Accounts, Facebook or FranceConnect, we will get this data from them. If you choose to verify your identity with a 3rd party identity provider as COW, FranceConnect or CSAM, we will get this information from them.
3.2 Personal data that you provide when taking participative action on our platform. Every action you take on the platform (voting, posting an idea, writing a comment, answering a poll,…) is registered and stored. This data is also linked to your registration data (3.1), implying that the organization can link your platform profile to this participation data.
3.3 Personal Data that we collect when you visit our platform. We (and third party processors acting on our behalf) collect information about usage of our platform for assessing the good functioning and security of the platform. To this end, we collect technical information that can identify you, such as your IP address and browser details. By using our services you agree to this data being collected.
We also gather usage data to improve our services, you can opt-out of this collection at all time from the consent manager.
4. HOW DO WE USE PERSONAL DATA? We might use your personal data for the following purposes:
First and foremost, to communicate your input to the organization with relevant context, and to draw aggregated reports of all the data collected on this platform to assist their decision-making. To create and maintain your user profile on this website. To manage the identification and authentication of users. To provide information about your community and/or alert you when activities on the platform may interest you. You can opt-out of user emails from your user profile at any time. To improve our services and monitor their functionalities. The personal data is only stored and processed for the period required for the purpose of the processing. After that, the data will be deleted or anonymized.
5. WITH WHOM DO WE SHARE YOUR PERSONAL DATA? We share your personal data with the organization on behalf of which we gather this data. We share your data to the sub-processors working on our behalf. We will never sell or rent your personal data to other service providers, nor will we share your Personal Data with any service providers who are not compliant with the GDPR.
6. WHERE DO WE TRANSFER YOUR PERSONAL DATA TO? We only transfer your Personal Data to service providers established outside the European Economic Area if they comply to art 44 GDPR.
7. WHAT RIGHTS DO YOU HAVE? You have the right to view your personal data at any time, as well as the right to be informed of the use that Go Vocal makes of your personal data.
7.1 Right to rectification, erasure and restriction of processing You are free to decide whether or not to provide your personal data to Go Vocal. In addition, you always have the right to request Go Vocal to correct, supplement or remove your personal data. You acknowledge that a refusal to provide or a request for the erasure of personal data means that certain services can no longer be delivered. You may also request that the processing of your personal data is limited. If you choose to remove your account from the platform, the personal data that was collected about you will be removed from our servers. Some personal information about you might remain in the logging data we keep for security and legal reasons for up to 30 days.
7.2 Right to object You have the right to object to the processing of your personal data for serious and legitimate reasons. In addition, you always have the right to object to the use of your personal data for direct marketing purposes; in such cases, you do not have to state reasons.
7.3 Right to data portability You have the right to obtain the personal data you have provided to Go Vocal in a structured, typical and machine-readable form and/or have such transferred to different controllers.
7.4 Right to withdraw consent Insofar as the processing is based on your prior consent, you have the right to withdraw this approval.
7.5 Exercising your rights You can exercise your rights by contacting Go Vocal to this end, either by email to support@govocal.com, by post to Pachecolaan 34, 1000 Brussels, Belgium or by using the “Contact us” form on our Website, provided you enclose a copy of the front of your identity card.
7.6 Automated decision-making and profiling The processing of your personal data does not include profiling and shall also not be subjected by Go Vocal to automated decision-making.
7.7 Right to lodge a complaint You have the right to lodge a complaint to the Privacy authority of your country, or the Belgian Privacy Authority under which authority Go Vocal falls: Drukpersstraat 35, 1000 Brussels, Belgium, Tel +32 (0)2 274 48 00, Fax +32 (0)2 274 48 35, e-mail: contact@adp-gba.be. This does not affect relief before a civil court.
8. ADDITIONAL INFORMATION ON DATA COLLECTION AND PROCESSING Legal procedures Go Vocal and the Organization we process this data for might use the Personal Data of the User for legal purposes, for the court or legal proceedings preceding phases in the event of unlawful use of this Application or the related services. The User is aware that Go Vocal and the Organization we work with might be obliged to disclose the personal data at the request of competent government institutions for the processing of the Data. The legal basis for this processing is the acceptance of the terms and conditions (contractual basis) and given consent.
Security Measures Go Vocal has developed security measures which have been adjusted at the technological and organisational level to prevent the destruction, loss, falsification, changing, prohibited access or the erroneous disclosure to third parties of personal data as well as any other prohibited processing of this data. Under no circumstances can Go Vocal be held liable for any direct or indirect loss resulting from the incorrect or unlawful use of your personal data by a third party. You must at all times comply with the security instructions, including by preventing all prohibited access to your login details and password. You are solely responsible for the use made from the website on your computer, IP-address and your identification details, as well as for the confidentiality of such.
Changes to this privacy policy Go Vocal reserves the right to change this privacy policy at any time by notifying Users on this page. We encourage you to check this page for possible changes. The date of the last change is indicated at the bottom of the page. If a User objects to any change in the policy, the User must not continue to use this Application. Unless otherwise indicated, the valid Privacy Policy applicable at that time applies to all Personal Data that we have collected.
Most recent update: 17/12/2019
+ infopage_title: Tudalen Gwybodaeth
+ infopage_body: "This all-in-one participation platform is an initiative of your municipality or organisation and can be used for different public consultation processes: collecting ideas, voting, discussing, surveys, polls, participatory budgeting, online mapping, scenario planning, support for advisory boards and committees, ...
\nOn the home page, you'll see which processes are active and in which phase they currently are.
\n
\nHow do I sign in on the platform? \nSigning in is done easily by giving your first and last name and your e-mail address. You could also use your Google or Facebook account. Only your first and last name will be visible to others.
\nCan I use the platform myself, e.g. to organise a public consultation? \nAbsolutely. Ask the responsible within your municipality or organisation to give you the needed permission rights to become a project moderator. Once granted these permissions, you can set up your own project and timeline and share the information you want (video, documents, images, ...). This will also allow you to invite others to the platform, enabling them to post ideas within your project, vote or comment.
\nCan I participate as an association/organisation/committee? \nYes, that's possible. Given that only your first and last name are visible to others on the platform, you can simply use your organisation's name while setting up your profile.
\nWhy would I use this platform and not create a website myself? \nA team of dedicated developers and specialists in online participation (Go Vocal , commissioned by your municipality or organisation) is improving and updating this platform on a daily basis. Even the smallest bug gets tackled immediately and if you have creative proposals, they can help you pointing out which features of the platform can be used for this or which ones are in the pipeline.
\n
\nNeed more information? Do you want to use the platform? Questions or feedback? Contact the responsible within your municipality or organisation. Or contact Go Vocal through support@govocal.com.
"
+ faq_title: FAQ
+ faq_body: "What is this platform for? This platform is designed as a central hub to share information and get input and feedback. Participation projects that are currently active are shown on the homepage - each participation project may have a different mode of engagement, whether it’s adding an idea, commenting on a proposal, voting on and prioritising projects, or taking a survey.
How do I participate? You can always browse public projects, but you’ll need to sign up in order to take an action. This helps to maintain a community feel and ensure the legitimacy of the input.
What information can people see about me? Your name, photo and bio, if you’ve added one, are visible. You can always change these in your Settings.
Why can’t I post my input or submit a comment? Posting, commenting and voting may be enabled only during certain times or phases of a project. In some instances, a project may only be open to contributions from a certain stakeholder group.
If posting is currently enabled for a project, you’ll see a button that prompts you to submit a post. Alternatively, you can browse other active projects for additional engagement opportunities.
How do I edit or delete my input? If you’ve posted your input but want to make edits or delete it, you can find this option by clicking on the three small dots on the top right of the post.
What are the community guidelines and moderation policies? Our community guidelines are here to help ensure that the platform is a safe space for everyone to participate. Please ensure your posts are free of:
\n Personal attacks, insults, abusive or discriminatory comments \n Offensive language including profanity \n Marketing or advertising material \n Personal information about other individuals \n Copyrighted material such as images \n Any posts or comments that do not adhere to these guidelines may be edited or deleted, or in extreme instances, prevented from being posted. Please review our Terms & Conditions for more information.
How do I report an offensive post? Click on the three small dots on the top right corner of the post to report it. Please indicate the reason you are reporting the content - this will send a notification for the post to be reviewed.
Why am I having difficulty signing up or logging in? If you’re unable to sign up, it may be because you’ve already registered with the same email address or previously received an invitation to join the platform. If you see a message that your email address is taken by a pending invite, please check your email and follow the link in the invitation to register your account. If you can’t find the invite, try looking in your spam box or request a new invitation.
How do I reset my password? You can always request to reset your password from the log in page. If you reset your password, a link will be sent to your email address - follow the instructions to change your password. For security reasons, the link is valid for one hour. If the link has expired, you can simply click on ‘Forgot password?’ in the log in page again to generate a new reset link.
If you didn’t receive the email, check to make sure that it’s not in your spam and that you’re sending the link to the same email address that you signed up with.
What will you do with my data? Review our privacy policy for more information on data collection and usage. In short, we will never use your data for advertising, marketing or other types of spam.
What emails will I receive? You may receive emails related to your account and your activity on the platform, for instance, when someone responds to one of your posts. You can control which emails you receive in your Settings. There is a section called “Notifications” where you can turn email notifications on and off.
How do I delete my account? In your Settings there is the option to delete your account. Input that you’ve posted will remain published, but your name will be removed from the post and replaced with ‘unknown author.’ If you’d like to delete all of your input, please do so before deleting your account.
"
+ initiatives_title: Cynigion
+ initiatives_body: >
+ What's a citizen's proposal? As a resident of $|orgName| you can place your proposal on the agenda via this platform. These proposals are preferably concrete ideas that are linked to local policy and arise from a need, desire or dream. It can be your own proposal or a collaborative one. Maybe you'd like to change or improve an existing situation or start a new project.
The involvement of $|orgName| in the implementation of your proposal must be both necessary and possible. In an ideal scenario, you're also available for further reflection or cooperation, but that is not an obligation. "Reducing the speed limit on the highway to 80 km/h" is therefore not a strong proposal, while "Turning the main street into a pedestrian area" is. So bring on your proposals! If more information is needed, you'll receive an update or reaction.
Why post a proposal on this platform? This is the official participation platform of $|orgName|, which offers the following benefits:
$|orgName| is officially involved as this platform's owner, and actively monitors what happens here. When you post a proposal, the person in charge automatically receives a message. You don't have to contact them to make sure your proposal is taken into account. This platform has been developed specifically for official participatory actions, like citizens' proposals. Every element, from the user experience to the step-by-step approach, is built precisely for this purpose. When using traditional social media, your proposal could disappear into the overload of stimuli, and an ordinary e-mail quickly disappears into a full inbox. Your fellow citizens are also present on this platform. They can support and refine your proposal. The more creative your proposal is and the more support it manages to gather, the more chance it will be implemented! How do you get started? First, check whether your proposal meets the following criteria:
$|initiativesEligibilityCriteria|
What can you expect when your proposal reaches $|initiativesVotingThreshold| votes within $|initiativesDaysLimit| days? $|initiativesThresholdReachedMessage|
What happens to the proposals that do not receive $|initiativesVotingThreshold| votes on time? That happens, but don't worry. Your proposal will remain on the platform. The status of your proposal will automatically change to 'Expired'. As a result, voting will no longer be possible. If you wish, you can choose to delete your own proposal at any time.
+ nav_bar_items:
+ home:
+ title: Cartref
+ projects:
+ title: Pob prosiect
+ all_input:
+ title: Pob mewnbwn
+ proposals:
+ title: Cynigion
+ events:
+ title: Digwyddiadau
+ about:
+ title: Ynghylch
+ faq:
+ title: FAQ
+ projects:
+ open_idea_project_title: Syniad? Dewch ag ef i'ch cyngor!
+ open_idea_project_description_preview: Efallai bod gennych chi syniad nad yw'n cyd-fynd ag un o'r prosiectau presennol? Na phostio fan hyn, casglu cefnogaeth a'i gael ar yr agenda wleidyddol!
+ open_idea_project_description: >
+ Yma, gallwch ddechrau eich syniad eich hun os nad yw'n cyd-fynd ag un o'r prosiectau presennol.
Yr amcan? I gael eich syniad ar yr agenda wleidyddol.
Sut? Trwy gasglu cefnogaeth, sef o leiaf 100 pleidlais mewn 3 mis. Gallwch wneud hynny drwy wneud eich syniad yn 'ddeniadol' yn gyntaf. Ysgrifennwch ef mewn ffordd glir a deniadol, ychwanegwch ddelweddau, rhowch ddadleuon cryf yn seiliedig ar ffeithiau, ychwanegwch atodiadau gyda manylion pellach neu wybodaeth gefndir, ... Ar ôl i chi wneud hynny, dechreuwch rannu'ch syniad ar gyfryngau cymdeithasol neu drwy e-bost. Gwahoddwch bobl i ymuno â'r drafodaeth ar eich syniad, neu'n syml, darbwyllwch nhw i'w gefnogi drwy bleidleisio o'i blaid.
Am beth? Gall eich syniad ymwneud â llawer o bethau, cyn belled â'i fod yn gysylltiedig â'ch dinas a'i pholisi. Gall fod yn broblem rydych chi'n ei chael, yn ddatrysiad rydych chi'n ei ragweld neu hyd yn oed yn gyfuniad o'r ddau. Gall fod yn wyllt ac yn y tymor hir, neu'n ddiriaethol iawn ac yn fuddugoliaeth gyflym.
Ac wedyn? A wnaethoch chi gyrraedd 100 pleidlais mewn 3 mis? Llongyfarchiadau! Bydd y ddinas nawr yn cymryd eich syniad i ystyriaeth. Os ystyrir bod eich syniad yn ymarferol ac nad yw'n niweidio grwpiau neu unigolion penodol, cewch gyfle i gyflwyno'ch cynnig yn ystod cyfarfod y cyngor. Yn ystod yr un cyfarfod, bydd aelodau'r cyngor yn rhoi adborth uniongyrchol i chi ar yr hyn y byddant neu na fyddant yn ei wneud â'ch syniad a pham. Os na fyddwch yn casglu 100 o bleidleisiau mewn 3 mis, ni fydd eich cynnig yn cael ei ystyried.
Rydym yn chwilfrydig i ddysgu am eich syniadau!
+ phases:
+ open_idea_phase_title: Cyfnod presennol
+ native_survey_title: Arolwg
+ native_survey_button: Cymerwch yr arolwg
+ events:
+ council_meeting_title: Cyfarfod y Cyngor
+ council_meeting_description: >
+ Yn ystod cyfarfod y cyngor hwn, bydd y mentrau dinasyddion hynny a enillodd 100 o bleidleisiau mewn llai na 3 mis, yn cael eu cyflwyno.
Bydd y cyngor wedyn yn rhannu eu barn ar bob syniad.
+ custom_fields:
+ users:
+ gender:
+ title: Rhyw
+ birthyear:
+ title: Blwyddyn geni
+ domicile:
+ title: Man preswylio
+ education:
+ title: Addysg
+ ideas:
+ title:
+ title: Teitl
+ description:
+ body:
+ title: Disgrifiad
+ description:
+ author_id:
+ title: Awdur
+ topic_ids:
+ title: Tagiau
+ description:
+ location:
+ title: Lleoliad
+ description:
+ proposed_budget:
+ title: Cyllideb Arfaethedig
+ description:
+ budget:
+ title: Cyllideb
+ images:
+ title: Delweddau
+ description:
+ attachments:
+ title: Ymlyniadau
+ description:
+ section1:
+ description:
+ section2:
+ title: Delweddau ac atodiadau
+ description:
+ section3:
+ title: Manylion
+ description:
+ other_text_field:
+ title: Os dewisoch chi '{other_option}', beth ydych chi'n ei feddwl?
+ custom_forms:
+ categories:
+ main_content:
+ idea:
+ title: Beth yw eich syniad?
+ question:
+ title: Beth yw eich cwestiwn?
+ contribution:
+ title: Beth yw eich cyfraniad?
+ project:
+ title: Beth yw eich prosiect?
+ issue:
+ title: Beth yw eich sylw?
+ option:
+ title: Beth yw eich opsiwn?
+ details:
+ title: Manylion
+ attachements:
+ title: Delweddau ac atodiadau
+ extra:
+ title: Gwybodaeth Ychwanegol
+ custom_field_options:
+ gender:
+ male: Gwryw
+ female: Benyw
+ unspecified: Arall
+ domicile:
+ outside: Rhywle arall
+ education:
+ ISCED2: Addysg uwchradd is
+ ISCED3: Addysg uwchradd uwch
+ ISCED4: Addysg ôl-uwchradd nad yw'n drydyddol
+ ISCED5: Addysg drydyddol cylch byr
+ ISCED6: Baglor neu gyfwerth
+ ISCED7: Meistr neu gyfwerth
+ ISCED8: Doethurol neu gyfwerth
+ initiatives:
+ default_threshold_reached_message: >
+ Gwahoddir y cychwynwyr i gyflwyno eu cynnig yng nghyfarfod nesaf y cyngor. Byddwn yn darparu diweddariad swyddogol.
+ default_eligibility_criteria: >
+ It must fall within the policy areas and competencies of local policy It serves the public interest rather than your individual interest It does not discriminate based on gender, race, age, or background It does not harm others
+ default_posting_tips: >
+ Cymerwch amser i ymhelaethu ar eich cynnig. Os oes angen, teipiwch ddrafft yn gyntaf ac yna copïwch-pasiwch ef yma. Dewiswch deitl ystyrlon sy'n esbonio'n glir beth mae eich cynnig yn ei olygu. Delweddwch eich cynnig gyda delwedd addas i'w helpu i sefyll allan! Ychwanegu atodiadau perthnasol, megis fideos, enghreifftiau ysbrydoledig, manylion technegol neu gynlluniau. Rhannwch eich syniad ar gyfryngau cymdeithasol a sianeli eraill i gasglu cefnogaeth gan eraill.
+ reset_password_mailer:
+ send_reset_password:
+ cta_reset_password: 'Ailosod eich cyfrinair'
+ message_you_reset_your_password: 'Gwnaethoch gais am ailosodiad cyfrinair ar gyfer y llwyfan cyfranogiad o %{organizationName}. Cliciwch y botwm isod i ddewis cyfrinair newydd, diogel. Daw''r ddolen i ben mewn 1 awr.'
+ subject: '%{organizationName}: Ailosodwch eich cyfrinair'
+ title_reset_your_password: 'Dewiswch gyfrinair newydd'
+ xlsx_export:
+ anonymous: 'Anhysbys'
+ column_headers:
+ assignee_fullname: 'Aseinai'
+ assignee_email: 'E-bost aseinai'
+ attachments: 'Ymlyniadau'
+ author_email: 'E-bost awdur'
+ author_fullname: 'Enw awdur'
+ author_id: 'ID Awdur'
+ budget: 'Cyllideb'
+ comments_count: 'Sylwadau'
+ cost: 'Cost'
+ created_at: 'Cyflwynwyd yn'
+ description: 'Disgrifiad'
+ dislikes_count: 'Cas bethau'
+ email: 'Ebost'
+ first_name: 'Enw(au) cyntaf'
+ image_url: 'URL delwedd'
+ input_id: 'ID'
+ input_url: 'URL'
+ last_name: 'Enw olaf'
+ latitude: 'Lledred'
+ likes_count: 'Hoffi'
+ location: 'Lleoliad'
+ longitude: 'Hydred'
+ participants: 'Cyfranogwyr'
+ picks: 'Picks'
+ project: 'Prosiect'
+ published_at: 'Cyhoeddwyd yn'
+ registration_completed_at: 'Cwblhawyd y cofrestriad yn'
+ status: 'Statws'
+ submitted_at: 'Cyflwynwyd yn'
+ tags: 'Tagiau'
+ title: 'Teitl'
+ votes_count: 'Pleidleisiau'
+ form_builder:
+ default_select_field:
+ title: 'Eich cwestiwn'
+ option1: 'Opsiwn 1'
+ option2: 'Opsiwn 2'
+ form_end_page:
+ title: 'Diolch am gymryd rhan'
+ description: "Cyflwynwch eich atebion trwy ddewis 'Cyflwyno' isod."
+ pdf_export:
+ personal_data: 'Data personol'
+ personal_data_explanation_public: "Byddwn yn cyflwyno eich mewnbwn i %{organizationName}'s llwyfan cyfranogiad ar-lein. Os hoffech i'ch enw gael ei arddangos fel awdur y mewnbwn hwn a derbyn diweddariadau sy'n berthnasol i'ch mewnbwn trwy e-bost, llenwch y meysydd canlynol ar y dudalen hon a byddwn yn creu cyfrif i chi. Ni fydd eich e-bost yn gyhoeddus a bydd yn cael ei ddefnyddio gan %{organizationName}yn unig. Os ydych am aros yn ddienw, neu os nad ydych yn cytuno i ni ddefnyddio eich data personol yn y modd hwn, gallwch eu gadael yn wag."
+ personal_data_explanation_private: "Byddwn yn cyflwyno eich mewnbwn i %{organizationName}'s llwyfan cyfranogiad ar-lein. Os ydych chi eisiau derbyn diweddariadau sy'n berthnasol i'ch mewnbwn trwy e-bost, llenwch y meysydd canlynol ar y dudalen hon a byddwn yn creu cyfrif i chi. Ni fydd eich data'n gyhoeddus a dim ond %{organizationName}fydd yn ei ddefnyddio. Os nad ydych yn cytuno i ni ddefnyddio eich data personol yn y modd hwn, gallwch eu gadael yn wag."
+ first_name: 'Enw(au) cyntaf'
+ last_name: 'Enw olaf'
+ email_address: 'Cyfeiriad ebost'
+ by_checking_this_box: "Trwy dicio'r blwch hwn rwy'n cydsynio i'm data gael ei ddefnyddio i greu cyfrif ar lwyfan cyfranogiad %{organizationName}."
+ optional: 'dewisol'
+ permission: 'Caniatâd'
+ choose_as_many: 'Dewiswch gymaint ag y dymunwch'
+ this_answer: 'Bydd yr ateb hwn yn cael ei rannu â chymedrolwyr yn unig, ac nid â''r cyhoedd.'
+ page: 'Tudalen'
+ date_published: 'Dyddiad Cyhoeddi (dd-mm-bbbb)'
+ instructions: 'Cyfarwyddiadau'
+ write_as_clearly: 'Ysgrifennwch fel yn glir ag y gallwch – efallai y bydd y ffurflenni hyn yn cael eu sganio'
+ write_in_language: 'Ysgrifennwch eich atebion yn yr un iaith â''r ffurflen hon'
+ linear_scale_print_description: 'Ysgrifennwch rif rhwng %{min_label} a %{max_label} yn unig'
+ project_copy:
+ title_suffix: 'Copi'
+ confirmations_mailer:
+ send_confirmation_code:
+ subject: "Cadarnhewch eich cyfeiriad e-bost ar gyfer llwyfan cyfranogiad %{organizationName}"
+ header: "Eich Cod Cadarnhau"
+ header_message: "Helo %{firstName}!"
+ confirm_email_address: "Cadarnhewch eich cyfeiriad e-bost"
+ thanks_for_signing_up1: "Diolch am eich cyfranogiad. Rhowch y cod cadarnhau hwn yn y ffenestr ar lwyfan cyfranogiad %{organizationName}:"
+ best_regards: "Cofion gorau,"
+ ignore_email: "Os na wnaethoch ofyn am god, gallwch anwybyddu'r e-bost hwn yn ddiogel."
+ expire_code: "Bydd y cod hwn yn dod i ben yn "
+ 24_hours: "24 awr."
+ copy_paste_the_link_below: "Copïwch a gludwch y cod isod i'r ffurflen gofrestru ar y platfform."
+ the_link_is_valid_for: "Mae'r ddolen hon yn ddilys am 24 awr. Os yw'r ddolen wedi dod i ben, gallwch ofyn am god newydd ."
+ did_you_receive_this_email_in_error: "A wnaethoch chi dderbyn yr e-bost hwn mewn camgymeriad? Rhowch wybod i ni ."
+ user_blocked_mailer:
+ send_user_blocked_email:
+ subject: 'Mae''ch cyfrif wedi''i analluogi dros dro'
+ title_user_blocked: 'Mae''ch cyfrif wedi''i analluogi dros dro'
+ paragraph_1_without_reason: "Mae eich cyfrif ar y platfform cyfranogiad o %{organizationName} wedi'i analluogi dros dro am dorri'r canllawiau cymunedol."
+ paragraph_1_with_reason: "Mae eich cyfrif ar y platfform cyfranogiad o %{organizationName} wedi'i analluogi dros dro am y rheswm canlynol:"
+ for_more_information: "I gael rhagor o wybodaeth am hyn, gallwch edrych ar y %{termsAndConditionsPage}"
+ you_can_sign_in_again_from: "Gallwch fewngofnodi eto o %{date}"
+ user:
+ anon_first_name: "Defnyddiwr"
+ time:
+ am: yn
+ formats:
+ hour_of_day: "%l %p"
+ pm: pm
+ voting_method:
+ default_voting_term_singular: "pleidlais"
+ default_voting_term_plural: "pleidleisiau"
diff --git a/back/config/locales/de-DE.yml b/back/config/locales/de-DE.yml
index 832ba629a9ed..e5ff050b8350 100644
--- a/back/config/locales/de-DE.yml
+++ b/back/config/locales/de-DE.yml
@@ -278,8 +278,8 @@ de:
description: "Antworten übermitteln, indem Sie unten auf \"Einreichen\" klicken."
pdf_export:
personal_data: 'Persönliche Daten'
- personal_data_explanation_public: "Wir werden Ihren Beitrag an die Online-Beteiligungsplattform von %{organizationName} weiterleiten. Wenn Sie möchten, dass Ihr Name als Autor*in dieses Beitrags angezeigt wird und Sie Aktualisierungen zu Ihrem Beitrag per E-Mail erhalten, füllen Sie bitte die folgenden Felder auf dieser Seite aus und wir erstellen ein Konto für Sie. Ihre E-Mail ist nicht öffentlich und wird nur von %{organizationName} verwendet. Wenn Sie anonym bleiben möchten oder nicht damit einverstanden sind, dass wir Ihre persönlichen Daten auf diese Weise verwenden, können Sie die Felder leer lassen."
- personal_data_explanation_private: "Wir werden Ihren Beitrag an die Online-Beteiligungsplattform von %{organizationName}weiterleiten. Wenn Sie Aktualisierungen, die für Ihren Beitrag relevant sind, per E-Mail erhalten möchten, füllen Sie bitte die folgenden Felder auf dieser Seite aus und wir werden ein Konto für Sie anlegen. Ihre Daten sind nicht öffentlich und werden nur von %{organizationName}verwendet. Wenn Sie nicht damit einverstanden sind, dass wir Ihre persönlichen Daten auf diese Weise verwenden, können Sie die Felder leer lassen."
+ personal_data_explanation_public: "Wir werden Ihren Beitrag auf der Online-Beteiligungsplattform von %{organizationName} veröffentlichen. Wenn Sie möchten, dass Ihr Name als Autor*in dieses Beitrags angezeigt wird und Sie Aktualisierungen zu Ihrem Beitrag per E-Mail erhalten, füllen Sie bitte die folgenden Felder auf dieser Seite aus und wir erstellen ein Konto für Sie. Ihre E-Mail ist nicht öffentlich und wird nur von %{organizationName} verwendet. Wenn Sie anonym bleiben möchten oder nicht damit einverstanden sind, dass wir Ihre persönlichen Daten auf diese Weise verwenden, können Sie die Felder leer lassen."
+ personal_data_explanation_private: "Wir werden Ihren Beitrag auf der Online-Beteiligungsplattform von %{organizationName} veröffentlichen. Wenn Sie Aktualisierungen, die für Ihren Beitrag relevant sind, per E-Mail erhalten möchten, füllen Sie bitte die folgenden Felder auf dieser Seite aus und wir werden ein Konto für Sie anlegen. Ihre Daten sind nicht öffentlich und werden nur von %{organizationName} verwendet. Wenn Sie nicht damit einverstanden sind, dass wir Ihre persönlichen Daten auf diese Weise verwenden, können Sie die Felder leer lassen."
first_name: 'Vorname'
last_name: 'Nachname'
email_address: 'E-Mail-Adresse'
diff --git a/back/db/migrate/20240731181623_add_page_layout_to_custom_fields.rb b/back/db/migrate/20240731181623_add_page_layout_to_custom_fields.rb
new file mode 100644
index 000000000000..4463829696cf
--- /dev/null
+++ b/back/db/migrate/20240731181623_add_page_layout_to_custom_fields.rb
@@ -0,0 +1,22 @@
+class AddPageLayoutToCustomFields < ActiveRecord::Migration[7.0]
+ # rubocop:disable Rails/ApplicationRecord
+ class StubCustomField < ActiveRecord::Base
+ self.table_name = 'custom_fields'
+ end
+ # rubocop:enable Rails/ApplicationRecord
+
+ def change
+ add_column :custom_fields, :page_layout, :string
+
+ reversible do |dir|
+ dir.up do
+ page_fields = StubCustomField.where(input_type: 'page')
+ page_fields.update_all(page_layout: 'default')
+ end
+
+ dir.down do
+ StubCustomField.update_all(page_layout: nil)
+ end
+ end
+ end
+end
diff --git a/back/db/structure.sql b/back/db/structure.sql
index ea7e7032c41b..a5f13efd61b9 100644
--- a/back/db/structure.sql
+++ b/back/db/structure.sql
@@ -2226,7 +2226,8 @@ CREATE TABLE public.custom_fields (
select_count_enabled boolean DEFAULT false NOT NULL,
maximum_select_count integer,
minimum_select_count integer,
- random_option_ordering boolean DEFAULT false NOT NULL
+ random_option_ordering boolean DEFAULT false NOT NULL,
+ page_layout character varying
);
@@ -7514,6 +7515,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20240612134240'),
('202407081751'),
('20240722090955'),
-('20240729141927');
+('20240729141927'),
+('20240731181623');
diff --git a/back/engines/commercial/analysis/config/locales/cy-GB.yml b/back/engines/commercial/analysis/config/locales/cy-GB.yml
new file mode 100644
index 000000000000..224c73bdd450
--- /dev/null
+++ b/back/engines/commercial/analysis/config/locales/cy-GB.yml
@@ -0,0 +1,3 @@
+cy:
+ analysis:
+ example_tag_n: Tag enghreifftiol %{n}
diff --git a/back/engines/commercial/bulk_import_ideas/spec/services/exporters/idea_pdf_form_exporter_spec.rb b/back/engines/commercial/bulk_import_ideas/spec/services/exporters/idea_pdf_form_exporter_spec.rb
index 6f456632130a..3e9d6f7b0032 100644
--- a/back/engines/commercial/bulk_import_ideas/spec/services/exporters/idea_pdf_form_exporter_spec.rb
+++ b/back/engines/commercial/bulk_import_ideas/spec/services/exporters/idea_pdf_form_exporter_spec.rb
@@ -17,13 +17,13 @@
create(:custom_field_option, custom_field: select_field, key: 'yes', title_multiloc: { 'en' => 'Yes' })
create(:custom_field_option, custom_field: select_field, key: 'no', title_multiloc: { 'en' => 'No' })
- create(:custom_field, resource: custom_form, key: 'page', input_type: 'page', enabled: true)
+ create(:custom_field_page, resource: custom_form, key: 'page', enabled: true)
multiselect_field = create(:custom_field, resource: custom_form, key: 'multiselect_field', title_multiloc: { 'en' => 'Multi select field' }, input_type: 'multiselect', enabled: true)
create(:custom_field_option, custom_field: multiselect_field, key: 'this', title_multiloc: { 'en' => 'This' })
create(:custom_field_option, custom_field: multiselect_field, key: 'that', title_multiloc: { 'en' => 'That' })
- create(:custom_field, resource: custom_form, key: 'page', input_type: 'page', enabled: true)
+ create(:custom_field_page, resource: custom_form, key: 'page', enabled: true)
another_select_field = create(:custom_field, resource: custom_form, key: 'another_select_field', title_multiloc: { 'en' => 'Another select field' }, input_type: 'select', enabled: true)
create(:custom_field_option, custom_field: another_select_field, key: 'yes', title_multiloc: { 'en' => 'Yes' })
diff --git a/back/engines/commercial/custom_maps/app/models/custom_maps/extensions/custom_field.rb b/back/engines/commercial/custom_maps/app/models/custom_maps/extensions/custom_field.rb
index 8e1a5e28511c..c889c263e4b5 100644
--- a/back/engines/commercial/custom_maps/app/models/custom_maps/extensions/custom_field.rb
+++ b/back/engines/commercial/custom_maps/app/models/custom_maps/extensions/custom_field.rb
@@ -9,8 +9,10 @@ def self.included(base)
base.has_one :map_config, class_name: 'CustomMaps::MapConfig', as: :mappable, dependent: :destroy
end
+ MAP_CONFIG_INPUT_TYPES = %w[point page].freeze
+
def supports_map_config?
- input_type == 'point'
+ MAP_CONFIG_INPUT_TYPES.include? input_type
end
end
end
diff --git a/back/engines/commercial/custom_maps/app/serializers/custom_maps/extensions/web_api/v1/custom_field_serializer.rb b/back/engines/commercial/custom_maps/app/serializers/custom_maps/extensions/web_api/v1/custom_field_serializer.rb
index fd50cc35b7b1..b28f259af238 100644
--- a/back/engines/commercial/custom_maps/app/serializers/custom_maps/extensions/web_api/v1/custom_field_serializer.rb
+++ b/back/engines/commercial/custom_maps/app/serializers/custom_maps/extensions/web_api/v1/custom_field_serializer.rb
@@ -9,7 +9,7 @@ def self.included(base)
base.class_eval do
has_one :map_config, class_name: 'CustomMaps::MapConfig', as: :mappable,
serializer: ::CustomMaps::WebApi::V1::MapConfigSerializer,
- if: proc { |object| object.input_type == 'point' }
+ if: proc { |object| CustomField::MAP_CONFIG_INPUT_TYPES.include? object.input_type }
end
end
end
diff --git a/back/engines/commercial/flag_inappropriate_content/config/locales/cy-GB.yml b/back/engines/commercial/flag_inappropriate_content/config/locales/cy-GB.yml
new file mode 100644
index 000000000000..3e3d1f3e5508
--- /dev/null
+++ b/back/engines/commercial/flag_inappropriate_content/config/locales/cy-GB.yml
@@ -0,0 +1,17 @@
+cy:
+ email_campaigns:
+ campaign_type_description:
+ "inappropriate_content_flagged": Amlygwyd cynnwys amhriodol
+ admin_campaign_type_description:
+ "inappropriate_content_flagged": Amlygwyd cynnwys amhriodol - gweinyddwyr
+ inappropriate_content_flagged:
+ subject: 'Mae postiad ar eich platfform wedi''i fflagio i''w adolygu'
+ header_title: 'Mae postiad ar eich platfform wedi''i fflagio i''w adolygu'
+ comment_author: '%{authorName} sylw:'
+ idea_author: '%{authorName} cyflwyno post:'
+ initiative_author: '%{authorName} cyflwynodd gynnig:'
+ automatically_flagged: >
+ Canfuwyd yn awtomatig bod y postiad hwn yn cynnwys cynnwys amhriodol. Rydym yn anfon yr hysbysiad hwn atoch fel y gallwch adolygu'r post yn unol â'ch canllawiau safoni eich hun.
+ how_to_review: >
+ Os nad yw'r post yn cynnwys cynnwys amhriodol, gallwch gael gwared ar y rhybudd trwy'ch platfform yn y tab Gweithgaredd yn y panel gweinyddol.
+ cta_review_post: 'Post adolygu'
diff --git a/back/engines/commercial/idea_assignment/config/locales/cy-GB.yml b/back/engines/commercial/idea_assignment/config/locales/cy-GB.yml
new file mode 100644
index 000000000000..757fc7a33433
--- /dev/null
+++ b/back/engines/commercial/idea_assignment/config/locales/cy-GB.yml
@@ -0,0 +1,13 @@
+cy:
+ email_campaigns:
+ campaign_type_description:
+ "idea_assigned_to_you": Neilltuo syniad i mi
+ admin_campaign_type_description:
+ "idea_assigned_to_you": Neilltuo syniad - gweinyddwyr a rheolwyr prosiect
+ idea_assigned_to_you:
+ by_author: 'gan %{authorName}'
+ cta_reply_to: 'Rhowch adborth i %{authorName}'
+ event_description_idea: 'Mae syniad wedi''i neilltuo i chi. Rhowch adborth trwy ysgrifennu diweddariad swyddogol neu trwy newid ei statws.'
+ main_header: '%{firstName}, mae gennych aseiniad newydd'
+ subject: 'Mae gennych aseiniad ar y platfform o %{organizationName}'
+ preheader_idea: 'Mae''r syniad o %{authorName} wedi''i neilltuo i chi'
diff --git a/back/engines/commercial/idea_custom_fields/app/controllers/idea_custom_fields/web_api/v1/admin/idea_custom_fields_controller.rb b/back/engines/commercial/idea_custom_fields/app/controllers/idea_custom_fields/web_api/v1/admin/idea_custom_fields_controller.rb
index 28035b150a75..bb76cef1355d 100644
--- a/back/engines/commercial/idea_custom_fields/app/controllers/idea_custom_fields/web_api/v1/admin/idea_custom_fields_controller.rb
+++ b/back/engines/commercial/idea_custom_fields/app/controllers/idea_custom_fields/web_api/v1/admin/idea_custom_fields_controller.rb
@@ -281,6 +281,7 @@ def update_all_params
:maximum_select_count,
:minimum_select_count,
:random_option_ordering,
+ :page_layout,
:map_config_id,
{ title_multiloc: CL2_SUPPORTED_LOCALES,
description_multiloc: CL2_SUPPORTED_LOCALES,
diff --git a/back/engines/commercial/idea_custom_fields/spec/acceptance/idea_custom_fields/phase_context/update_all_native_survey_spec.rb b/back/engines/commercial/idea_custom_fields/spec/acceptance/idea_custom_fields/phase_context/update_all_native_survey_spec.rb
index 1ac947020858..23fb2fd6742c 100644
--- a/back/engines/commercial/idea_custom_fields/spec/acceptance/idea_custom_fields/phase_context/update_all_native_survey_spec.rb
+++ b/back/engines/commercial/idea_custom_fields/spec/acceptance/idea_custom_fields/phase_context/update_all_native_survey_spec.rb
@@ -37,7 +37,10 @@
create(:custom_field, resource: custom_form) # field to destroy
request = {
custom_fields: [
- { input_type: 'page' },
+ {
+ input_type: 'page',
+ page_layout: 'default'
+ },
# Inserted field first to test reordering of fields.
{
input_type: 'text',
@@ -116,7 +119,10 @@
request = {
custom_fields: [
- { input_type: 'page' },
+ {
+ input_type: 'page',
+ page_layout: 'default'
+ },
{
input_type: 'multiselect',
title_multiloc: { en: 'Inserted field' },
@@ -218,7 +224,10 @@
image2 = create(:custom_field_option_image, custom_field_option: nil)
request = {
custom_fields: [
- { input_type: 'page' },
+ {
+ input_type: 'page',
+ page_layout: 'default'
+ },
{
input_type: 'multiselect_image',
title_multiloc: { en: 'Inserted field' },
@@ -288,7 +297,10 @@
example '[error] Add a field of unsupported input_type' do
request = {
custom_fields: [
- { input_type: 'page' },
+ {
+ input_type: 'page',
+ page_layout: 'default'
+ },
{
input_type: 'topic_ids',
title_multiloc: { 'en' => 'Topics field title' },
@@ -318,7 +330,8 @@
custom_fields: [
{
id: page.id,
- input_type: 'page'
+ input_type: 'page',
+ page_layout: 'default'
},
{
id: field.id,
@@ -356,7 +369,8 @@
custom_fields: [
{
id: page.id,
- input_type: 'page'
+ input_type: 'page',
+ page_layout: 'default'
},
{
id: field.id,
@@ -401,7 +415,10 @@
request = {
custom_fields: [
- { input_type: 'page' },
+ {
+ input_type: 'page',
+ page_layout: 'default'
+ },
{
id: select_field.id,
input_type: 'multiselect',
@@ -459,7 +476,10 @@
request = {
custom_fields: [
- { input_type: 'page' },
+ {
+ input_type: 'page',
+ page_layout: 'default'
+ },
{
id: select_field.id,
input_type: select_field.input_type,
@@ -519,7 +539,10 @@
request = {
custom_fields: [
- { input_type: 'page' },
+ {
+ input_type: 'page',
+ page_layout: 'default'
+ },
{
id: field.id,
title_multiloc: { 'en' => 'Updated field' },
@@ -603,7 +626,10 @@
request = {
custom_fields: [
- { input_type: 'page' },
+ {
+ input_type: 'page',
+ page_layout: 'default'
+ },
{
id: field_to_update.id,
options: []
@@ -622,7 +648,10 @@
field_to_update = create(:custom_field, resource: custom_form, title_multiloc: { 'en' => 'Some field' })
request = {
custom_fields: [
- { input_type: 'page' },
+ {
+ input_type: 'page',
+ page_layout: 'default'
+ },
{
# input_type is not given
title_multiloc: { 'en' => 'Inserted field' },
@@ -690,7 +719,10 @@
field_to_update = create(:custom_field_select, :with_options, resource: custom_form)
request = {
custom_fields: [
- { input_type: 'page' },
+ {
+ input_type: 'page',
+ page_layout: 'default'
+ },
{
id: field_to_update.id,
title_multiloc: { 'en' => 'New title' },
@@ -739,6 +771,7 @@
{
id: page1.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page1.title_multiloc,
description_multiloc: page1.description_multiloc,
required: false,
@@ -754,6 +787,7 @@
{
id: page2.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page2.title_multiloc,
description_multiloc: page2.description_multiloc,
required: false,
@@ -791,6 +825,7 @@
{
id: page1.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page1.title_multiloc,
description_multiloc: page1.description_multiloc,
required: false,
@@ -812,6 +847,7 @@
{
id: page2.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page2.title_multiloc,
description_multiloc: page2.description_multiloc,
required: false,
@@ -820,6 +856,7 @@
{
id: page3.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page3.title_multiloc,
description_multiloc: page3.description_multiloc,
required: false,
@@ -841,6 +878,7 @@
input_type: 'page',
key: page1.key,
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: page1.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -850,7 +888,7 @@
},
id: page1.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][1]).to match({
attributes: {
@@ -886,6 +924,7 @@
input_type: 'page',
key: page2.key,
ordering: 2,
+ page_layout: 'default',
required: false,
title_multiloc: page2.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -895,7 +934,7 @@
},
id: page2.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][3]).to match({
attributes: {
@@ -906,6 +945,7 @@
input_type: 'page',
key: page3.key,
ordering: 3,
+ page_layout: 'default',
required: false,
title_multiloc: page3.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -915,7 +955,7 @@
},
id: page3.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
end
@@ -930,6 +970,7 @@
{
id: page_to_update.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page_to_update.title_multiloc,
description_multiloc: page_to_update.description_multiloc,
required: false,
@@ -939,6 +980,7 @@
{
id: page2.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page2.title_multiloc,
description_multiloc: page2.description_multiloc,
required: false,
@@ -947,6 +989,7 @@
{
id: page3.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page3.title_multiloc,
description_multiloc: page3.description_multiloc,
required: false,
@@ -955,6 +998,7 @@
{
id: page4.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page4.title_multiloc,
description_multiloc: page4.description_multiloc,
required: false,
@@ -974,6 +1018,7 @@
description_multiloc: page_to_update.description_multiloc.symbolize_keys,
enabled: true,
input_type: 'page',
+ page_layout: 'default',
key: page_to_update.key,
ordering: 0,
required: false,
@@ -985,7 +1030,7 @@
},
id: page_to_update.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][1]).to match({
attributes: {
@@ -996,6 +1041,7 @@
input_type: 'page',
key: page2.key,
ordering: 1,
+ page_layout: 'default',
required: false,
title_multiloc: page2.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1005,7 +1051,7 @@
},
id: page2.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][2]).to match({
attributes: {
@@ -1016,6 +1062,7 @@
input_type: 'page',
key: page3.key,
ordering: 2,
+ page_layout: 'default',
required: false,
title_multiloc: page3.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1025,7 +1072,7 @@
},
id: page3.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][3]).to match({
attributes: {
@@ -1036,6 +1083,7 @@
input_type: 'page',
key: page4.key,
ordering: 3,
+ page_layout: 'default',
required: false,
title_multiloc: page4.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1045,7 +1093,7 @@
},
id: page4.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
end
@@ -1059,6 +1107,7 @@
{
id: page_to_update.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page_to_update.title_multiloc,
description_multiloc: page_to_update.description_multiloc,
required: false,
@@ -1070,6 +1119,7 @@
{
id: page2.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page2.title_multiloc,
description_multiloc: page2.description_multiloc,
required: false,
@@ -1078,6 +1128,7 @@
{
id: page3.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page3.title_multiloc,
description_multiloc: page3.description_multiloc,
required: false,
@@ -1086,6 +1137,7 @@
{
temp_id: 'TEMP-ID-1',
input_type: 'page',
+ page_layout: 'default',
title_multiloc: { 'en' => 'Page 4' },
description_multiloc: { 'en' => 'Page 4 description' },
required: false,
@@ -1107,6 +1159,7 @@
input_type: 'page',
key: page_to_update.key,
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: page_to_update.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1116,7 +1169,7 @@
},
id: page_to_update.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][1]).to match({
attributes: {
@@ -1127,6 +1180,7 @@
input_type: 'page',
key: page2.key,
ordering: 1,
+ page_layout: 'default',
required: false,
title_multiloc: page2.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1136,7 +1190,7 @@
},
id: page2.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][2]).to match({
attributes: {
@@ -1147,6 +1201,7 @@
input_type: 'page',
key: page3.key,
ordering: 2,
+ page_layout: 'default',
required: false,
title_multiloc: page3.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1156,7 +1211,7 @@
},
id: page3.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][3]).to match({
attributes: {
@@ -1167,6 +1222,7 @@
input_type: 'page',
key: nil,
ordering: 3,
+ page_layout: 'default',
required: false,
title_multiloc: { en: 'Page 4' },
updated_at: an_instance_of(String),
@@ -1176,7 +1232,7 @@
},
id: an_instance_of(String),
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
end
@@ -1187,6 +1243,7 @@
{
temp_id: 'TEMP-ID-1',
input_type: 'page',
+ page_layout: 'default',
title_multiloc: { 'en' => 'New page with logic' },
description_multiloc: { 'en' => 'New page with logic description' },
required: false,
@@ -1196,6 +1253,7 @@
{
id: existing_page.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: existing_page.title_multiloc,
description_multiloc: existing_page.description_multiloc,
required: false,
@@ -1204,6 +1262,7 @@
{
temp_id: 'TEMP-ID-2',
input_type: 'page',
+ page_layout: 'default',
title_multiloc: { 'en' => 'Target page' },
description_multiloc: { 'en' => 'Target page description' },
required: false,
@@ -1225,6 +1284,7 @@
input_type: 'page',
key: nil,
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: { en: 'New page with logic' },
updated_at: an_instance_of(String),
@@ -1234,7 +1294,7 @@
},
id: an_instance_of(String),
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][1]).to match({
attributes: {
@@ -1245,6 +1305,7 @@
input_type: 'page',
key: existing_page.key,
ordering: 1,
+ page_layout: 'default',
required: false,
title_multiloc: existing_page.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1254,7 +1315,7 @@
},
id: existing_page.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][2]).to match({
attributes: {
@@ -1265,6 +1326,7 @@
input_type: 'page',
key: nil,
ordering: 2,
+ page_layout: 'default',
required: false,
title_multiloc: { en: 'Target page' },
updated_at: an_instance_of(String),
@@ -1274,7 +1336,7 @@
},
id: an_instance_of(String),
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
end
@@ -1288,6 +1350,7 @@
{
id: page_to_update.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page_to_update.title_multiloc,
description_multiloc: page_to_update.description_multiloc,
required: false,
@@ -1297,6 +1360,7 @@
{
id: page2.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page2.title_multiloc,
description_multiloc: page2.description_multiloc,
required: false,
@@ -1305,6 +1369,7 @@
{
id: page3.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page3.title_multiloc,
description_multiloc: page3.description_multiloc,
required: false,
@@ -1326,6 +1391,7 @@
input_type: 'page',
key: page_to_update.key,
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: page_to_update.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1335,7 +1401,7 @@
},
id: page_to_update.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][1]).to match({
attributes: {
@@ -1346,6 +1412,7 @@
input_type: 'page',
key: page2.key,
ordering: 1,
+ page_layout: 'default',
required: false,
title_multiloc: page2.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1355,7 +1422,7 @@
},
id: page2.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][2]).to match({
attributes: {
@@ -1366,6 +1433,7 @@
input_type: 'page',
key: page3.key,
ordering: 2,
+ page_layout: 'default',
required: false,
title_multiloc: page3.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1375,7 +1443,7 @@
},
id: page3.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
end
@@ -1389,6 +1457,7 @@
{
id: page_to_update.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page_to_update.title_multiloc,
description_multiloc: page_to_update.description_multiloc,
required: false,
@@ -1398,6 +1467,7 @@
{
id: page2.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page2.title_multiloc,
description_multiloc: page2.description_multiloc,
required: false,
@@ -1419,6 +1489,7 @@
input_type: 'page',
key: page_to_update.key,
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: page_to_update.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1428,7 +1499,7 @@
},
id: page_to_update.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][1]).to match({
attributes: {
@@ -1439,6 +1510,7 @@
input_type: 'page',
key: page2.key,
ordering: 1,
+ page_layout: 'default',
required: false,
title_multiloc: page2.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1448,7 +1520,7 @@
},
id: page2.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
end
@@ -1470,6 +1542,7 @@
{
id: page1.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page1.title_multiloc,
description_multiloc: page1.description_multiloc,
required: false,
@@ -1491,6 +1564,7 @@
{
id: page2.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page2.title_multiloc,
description_multiloc: page2.description_multiloc,
required: false,
@@ -1499,6 +1573,7 @@
{
temp_id: 'TEMP-ID-1',
input_type: 'page',
+ page_layout: 'default',
title_multiloc: { 'en' => 'Page 3' },
description_multiloc: { 'en' => 'Page 3 description' },
required: false,
@@ -1520,6 +1595,7 @@
input_type: 'page',
key: page1.key,
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: page1.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1529,7 +1605,7 @@
},
id: page1.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][1]).to match({
attributes: {
@@ -1565,6 +1641,7 @@
input_type: 'page',
key: page2.key,
ordering: 2,
+ page_layout: 'default',
required: false,
title_multiloc: page2.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1574,7 +1651,7 @@
},
id: page2.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][3]).to match({
attributes: {
@@ -1585,6 +1662,7 @@
input_type: 'page',
key: nil,
ordering: 3,
+ page_layout: 'default',
required: false,
title_multiloc: { en: 'Page 3' },
updated_at: an_instance_of(String),
@@ -1594,7 +1672,7 @@
},
id: an_instance_of(String),
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
end
@@ -1618,6 +1696,7 @@
{
id: page1.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page1.title_multiloc,
description_multiloc: page1.description_multiloc,
required: false,
@@ -1639,6 +1718,7 @@
{
id: page3.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page3.title_multiloc,
description_multiloc: page3.description_multiloc,
required: false,
@@ -1647,6 +1727,7 @@
{
id: page2.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page2.title_multiloc,
description_multiloc: page2.description_multiloc,
required: false,
@@ -1667,6 +1748,7 @@
input_type: 'page',
key: page1.key,
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: page1.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1676,7 +1758,7 @@
},
id: page1.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][1]).to match({
attributes: {
@@ -1712,6 +1794,7 @@
input_type: 'page',
key: page3.key,
ordering: 2,
+ page_layout: 'default',
required: false,
title_multiloc: page3.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1721,7 +1804,7 @@
},
id: page3.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][3]).to match({
attributes: {
@@ -1732,6 +1815,7 @@
input_type: 'page',
key: page2.key,
ordering: 3,
+ page_layout: 'default',
required: false,
title_multiloc: page2.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1741,7 +1825,7 @@
},
id: page2.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
end
@@ -1763,6 +1847,7 @@
{
id: page1.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page1.title_multiloc,
description_multiloc: page1.description_multiloc,
required: false,
@@ -1782,6 +1867,7 @@
{
id: page2.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page2.title_multiloc,
description_multiloc: page2.description_multiloc,
required: false,
@@ -1803,6 +1889,7 @@
input_type: 'page',
key: page1.key,
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: page1.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1812,7 +1899,7 @@
},
id: page1.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][1]).to match({
attributes: {
@@ -1846,6 +1933,7 @@
input_type: 'page',
key: page2.key,
ordering: 2,
+ page_layout: 'default',
required: false,
title_multiloc: page2.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1855,7 +1943,7 @@
},
id: page2.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
end
@@ -1878,6 +1966,7 @@
{
id: page1.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page1.title_multiloc,
description_multiloc: page1.description_multiloc,
required: false,
@@ -1910,6 +1999,7 @@
input_type: 'page',
key: page1.key,
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: page1.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1919,7 +2009,7 @@
},
id: page1.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][1]).to match({
attributes: {
@@ -1965,6 +2055,7 @@
{
id: page1.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page1.title_multiloc,
description_multiloc: page1.description_multiloc,
required: false,
@@ -1986,6 +2077,7 @@
input_type: 'page',
key: page1.key,
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: page1.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -1995,7 +2087,7 @@
},
id: page1.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
end
@@ -2023,6 +2115,7 @@
{
id: page1.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page1.title_multiloc,
description_multiloc: page1.description_multiloc,
required: false,
@@ -2044,6 +2137,7 @@
{
id: page2.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page2.title_multiloc,
description_multiloc: page2.description_multiloc,
required: false,
@@ -2052,6 +2146,7 @@
{
id: page3.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page3.title_multiloc,
description_multiloc: page3.description_multiloc,
required: false,
@@ -2073,6 +2168,7 @@
input_type: 'page',
key: page1.key,
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: page1.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -2082,7 +2178,7 @@
},
id: page1.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][1]).to match({
attributes: {
@@ -2118,6 +2214,7 @@
input_type: 'page',
key: page2.key,
ordering: 2,
+ page_layout: 'default',
required: false,
title_multiloc: page2.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -2127,7 +2224,7 @@
},
id: page2.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][3]).to match({
attributes: {
@@ -2138,6 +2235,7 @@
input_type: 'page',
key: page3.key,
ordering: 3,
+ page_layout: 'default',
required: false,
title_multiloc: page3.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -2147,7 +2245,7 @@
},
id: page3.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
end
@@ -2165,6 +2263,7 @@
{
id: page1.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page1.title_multiloc,
description_multiloc: page1.description_multiloc,
required: false,
@@ -2186,6 +2285,7 @@
{
temp_id: 'TEMP-ID-1',
input_type: 'page',
+ page_layout: 'default',
title_multiloc: { 'en' => 'Page 2' },
description_multiloc: { 'en' => 'Page 2 description' },
required: false,
@@ -2207,6 +2307,7 @@
input_type: 'page',
key: page1.key,
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: page1.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -2216,7 +2317,7 @@
},
id: page1.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][1]).to match({
attributes: {
@@ -2252,6 +2353,7 @@
input_type: 'page',
key: nil,
ordering: 2,
+ page_layout: 'default',
required: false,
title_multiloc: { en: 'Page 2' },
updated_at: an_instance_of(String),
@@ -2261,7 +2363,7 @@
},
id: an_instance_of(String),
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
end
@@ -2285,6 +2387,7 @@
{
id: page1.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page1.title_multiloc,
description_multiloc: page1.description_multiloc,
required: false,
@@ -2328,6 +2431,7 @@
{
temp_id: 'TEMP-ID-1',
input_type: 'page',
+ page_layout: 'default',
title_multiloc: { 'en' => 'Page 2' },
description_multiloc: { 'en' => 'Page 2 description' },
required: false,
@@ -2336,6 +2440,7 @@
{
temp_id: 'TEMP-ID-3',
input_type: 'page',
+ page_layout: 'default',
title_multiloc: { 'en' => 'Page 3' },
description_multiloc: { 'en' => 'Page 3 description' },
required: false,
@@ -2360,6 +2465,7 @@
input_type: 'page',
key: page1.key,
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: page1.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -2369,7 +2475,7 @@
},
id: page1.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][1]).to match({
attributes: {
@@ -2438,6 +2544,7 @@
input_type: 'page',
key: nil,
ordering: 3,
+ page_layout: 'default',
required: false,
title_multiloc: { en: 'Page 2' },
updated_at: an_instance_of(String),
@@ -2447,7 +2554,7 @@
},
id: an_instance_of(String),
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][4]).to match({
attributes: {
@@ -2458,6 +2565,7 @@
input_type: 'page',
key: nil,
ordering: 4,
+ page_layout: 'default',
required: false,
title_multiloc: { en: 'Page 3' },
updated_at: an_instance_of(String),
@@ -2467,7 +2575,7 @@
},
id: an_instance_of(String),
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
end
@@ -2479,6 +2587,7 @@
{
id: page1.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page1.title_multiloc,
description_multiloc: page1.description_multiloc,
required: false,
@@ -2500,6 +2609,7 @@
{
temp_id: 'TEMP-ID-1',
input_type: 'page',
+ page_layout: 'default',
title_multiloc: { 'en' => 'Page 2' },
description_multiloc: { 'en' => 'Page 2 description' },
required: false,
@@ -2522,6 +2632,7 @@
input_type: 'page',
key: page1.key,
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: page1.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -2531,7 +2642,7 @@
},
id: page1.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][1]).to match({
attributes: {
@@ -2567,6 +2678,7 @@
input_type: 'page',
key: nil,
ordering: 2,
+ page_layout: 'default',
required: false,
title_multiloc: { en: 'Page 2' },
updated_at: an_instance_of(String),
@@ -2576,7 +2688,7 @@
},
id: an_instance_of(String),
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
end
@@ -2601,6 +2713,7 @@
{
id: page1.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page1.title_multiloc,
description_multiloc: page1.description_multiloc,
required: false,
@@ -2625,6 +2738,7 @@
{
id: page2.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page2.title_multiloc,
description_multiloc: page2.description_multiloc,
required: false,
@@ -2633,6 +2747,7 @@
{
id: page3.id,
input_type: 'page',
+ page_layout: 'default',
title_multiloc: page3.title_multiloc,
description_multiloc: page3.description_multiloc,
required: false,
@@ -2654,6 +2769,7 @@
input_type: 'page',
key: page1.key,
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: page1.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -2663,7 +2779,7 @@
},
id: page1.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][1]).to match({
attributes: {
@@ -2702,6 +2818,7 @@
input_type: 'page',
key: page2.key,
ordering: 2,
+ page_layout: 'default',
required: false,
title_multiloc: page2.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -2711,7 +2828,7 @@
},
id: page2.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
expect(json_response[:data][3]).to match({
attributes: {
@@ -2722,6 +2839,7 @@
input_type: 'page',
key: page3.key,
ordering: 3,
+ page_layout: 'default',
required: false,
title_multiloc: page3.title_multiloc.symbolize_keys,
updated_at: an_instance_of(String),
@@ -2731,7 +2849,7 @@
},
id: page3.id,
type: 'custom_field',
- relationships: { options: { data: [] } }
+ relationships: { map_config: { data: nil }, options: { data: [] } }
})
end
@@ -2742,7 +2860,10 @@
request = {
custom_fields: [
- { input_type: 'page' },
+ {
+ input_type: 'page',
+ page_layout: 'default'
+ },
{
id: change_field.id,
input_type: 'select',
@@ -2858,7 +2979,10 @@
field_to_update = create(:custom_field, resource: custom_form, title_multiloc: { 'en' => 'Some field' })
request = {
custom_fields: [
- { input_type: 'page' },
+ {
+ input_type: 'page',
+ page_layout: 'default'
+ },
{
title_multiloc: { 'en' => 'Inserted field' },
description_multiloc: { 'en' => ' ' },
@@ -2888,7 +3012,10 @@
field_to_update = create(:custom_field_point, resource: custom_form, title_multiloc: { 'en' => 'Point field' })
request = {
custom_fields: [
- { input_type: 'page' },
+ {
+ input_type: 'page',
+ page_layout: 'default'
+ },
{
title_multiloc: { 'en' => 'Inserted point custom field' },
description_multiloc: { 'en' => 'Inserted point custom field description' },
@@ -2921,6 +3048,45 @@
expect(new_custom_field.input_type).to eq('point')
end
+ example "Relating map_config(s) with 'page' custom field(s)" do
+ field_to_update = create(:custom_field_page, resource: custom_form, title_multiloc: { 'en' => 'Page field' })
+ request = {
+ custom_fields: [
+ {
+ input_type: 'page',
+ page_layout: 'default',
+ title_multiloc: { 'en' => 'Inserted page custom field' },
+ description_multiloc: { 'en' => 'Inserted page custom field description' },
+ required: false,
+ enabled: true,
+ map_config_id: map_config1.id
+ },
+ {
+ id: field_to_update.id,
+ input_type: 'page',
+ page_layout: 'default',
+ title_multiloc: { 'en' => 'Updated page custom field' },
+ description_multiloc: { 'en' => 'Updated page custom field description' },
+ required: false,
+ enabled: true,
+ map_config_id: map_config2.id
+ }
+ ]
+ }
+
+ do_request request
+ assert_status 200
+
+ new_custom_field = map_config1.reload.mappable
+ expect(new_custom_field.title_multiloc).to eq({ 'en' => 'Inserted page custom field' })
+ expect(new_custom_field.input_type).to eq('page')
+
+ updated_custom_field = CustomField.find(field_to_update.id)
+ expect(updated_custom_field.map_config).to eq(map_config2)
+ expect(updated_custom_field.title_multiloc).to eq({ 'en' => 'Updated page custom field' })
+ expect(new_custom_field.input_type).to eq('page')
+ end
+
example '[errors] Responds with multiple numbered errors when such errors present', document: false do
custom_field_point_with_map_config = create(:custom_field_point, resource: custom_form)
create(:map_config, mappable_id: custom_field_point_with_map_config.id, mappable_type: 'CustomField')
@@ -2935,7 +3101,10 @@
# }
request = {
custom_fields: [
- { input_type: 'page' },
+ {
+ input_type: 'page',
+ page_layout: 'default'
+ },
{
title_multiloc: { 'en' => 'Inserted text custom field' },
description_multiloc: { 'en' => 'Inserted text custom field description' },
@@ -2979,40 +3148,35 @@
# by sending a separate request to delete the map_config, using DELETE ...map_configs/:id.
# i.e. map_config_id: nil, map_config_id: '', or ommitting map_config_id param will not remove the relation.
example 'Absence of map_config_id does not remove existing relation', document: false do
- custom_field1 = create(:custom_field_point, resource: custom_form)
+ custom_field1 = create(:custom_field_page, resource: custom_form)
map_config1 = create(:map_config, mappable_id: custom_field1.id, mappable_type: 'CustomField')
custom_field2 = create(:custom_field_point, resource: custom_form)
map_config2 = create(:map_config, mappable_id: custom_field2.id, mappable_type: 'CustomField')
custom_field3 = create(:custom_field_point, resource: custom_form)
map_config3 = create(:map_config, mappable_id: custom_field3.id, mappable_type: 'CustomField')
+ custom_field4 = create(:custom_field_point, resource: custom_form)
+ map_config4 = create(:map_config, mappable_id: custom_field4.id, mappable_type: 'CustomField')
request = {
custom_fields: [
- { input_type: 'page' },
{
id: custom_field1.id,
- title_multiloc: { 'en' => 'Updated point custom field 1' },
- description_multiloc: { 'en' => 'Updated point custom field 1 description' },
- input_type: 'point',
- required: false,
- enabled: false
+ input_type: 'page',
+ page_layout: 'default',
+ map_config_id: nil
},
{
id: custom_field2.id,
- title_multiloc: { 'en' => 'Updated point custom field 2' },
- description_multiloc: { 'en' => 'Updated point custom field 2 description' },
+ input_type: 'point'
+ },
+ {
+ id: custom_field3.id,
input_type: 'point',
- required: false,
- enabled: false,
map_config_id: nil
},
{
- id: custom_field3.id,
- title_multiloc: { 'en' => 'Updated point custom field 3' },
- description_multiloc: { 'en' => 'Updated point custom field 3 description' },
+ id: custom_field4.id,
input_type: 'point',
- required: false,
- enabled: false,
map_config_id: ''
}
]
@@ -3024,6 +3188,7 @@
expect(custom_field1.reload.map_config).to eq(map_config1)
expect(custom_field2.reload.map_config).to eq(map_config2)
expect(custom_field3.reload.map_config).to eq(map_config3)
+ expect(custom_field4.reload.map_config).to eq(map_config4)
end
end
end
diff --git a/back/engines/commercial/multi_tenancy/app/services/multi_tenancy/templates/serializers/custom_field.rb b/back/engines/commercial/multi_tenancy/app/services/multi_tenancy/templates/serializers/custom_field.rb
index e431fb60a7c0..44f3b2872942 100644
--- a/back/engines/commercial/multi_tenancy/app/services/multi_tenancy/templates/serializers/custom_field.rb
+++ b/back/engines/commercial/multi_tenancy/app/services/multi_tenancy/templates/serializers/custom_field.rb
@@ -22,6 +22,7 @@ class CustomField < Base
ordering
title_multiloc
random_option_ordering
+ page_layout
]
# Enigmatic comment from the previous implementation:
diff --git a/back/engines/commercial/multi_tenancy/config/locales/cy-GB.yml b/back/engines/commercial/multi_tenancy/config/locales/cy-GB.yml
new file mode 100644
index 000000000000..a7a5a9307d78
--- /dev/null
+++ b/back/engines/commercial/multi_tenancy/config/locales/cy-GB.yml
@@ -0,0 +1,11 @@
+#Translations for continuous to timeline migration
+cy:
+ phase_title_default:
+ ideation: Casglu mewnbwn
+ voting: Pleidleisio
+ poll: Pleidlais
+ native_survey: Arolwg
+ survey: Arolwg
+ document_annotation: Dogfen adborth
+ volunteering: Dod o hyd i wirfoddolwyr
+ information: Gwybodaeth
diff --git a/back/engines/commercial/multi_tenancy/spec/services/multi_tenancy/templates/tenant_serializer_spec.rb b/back/engines/commercial/multi_tenancy/spec/services/multi_tenancy/templates/tenant_serializer_spec.rb
index 904c7cd13777..4903b85d9d55 100644
--- a/back/engines/commercial/multi_tenancy/spec/services/multi_tenancy/templates/tenant_serializer_spec.rb
+++ b/back/engines/commercial/multi_tenancy/spec/services/multi_tenancy/templates/tenant_serializer_spec.rb
@@ -175,7 +175,7 @@
description_multiloc = {
'en' => ' '
}
- field = create(:custom_field, :for_custom_form, description_multiloc: description_multiloc)
+ field = create(:custom_field_page, :for_custom_form, description_multiloc: description_multiloc)
field.update! description_multiloc: TextImageService.new.swap_data_images_multiloc(field.description_multiloc, field: :description_multiloc, imageable: field)
template = tenant_serializer.run(deserializer_format: true)
@@ -186,7 +186,8 @@
'input_type' => field.input_type,
'title_multiloc' => field.title_multiloc,
'random_option_ordering' => field.random_option_ordering,
- 'description_multiloc' => field.description_multiloc
+ 'description_multiloc' => field.description_multiloc,
+ 'page_layout' => field.page_layout
)
end
diff --git a/back/engines/free/email_campaigns/config/locales/cy-GB.yml b/back/engines/free/email_campaigns/config/locales/cy-GB.yml
new file mode 100644
index 000000000000..8daa483325df
--- /dev/null
+++ b/back/engines/free/email_campaigns/config/locales/cy-GB.yml
@@ -0,0 +1,655 @@
+cy:
+ email_campaigns:
+ campaign_type_description:
+ "manual": Negeseuon swyddogol
+ "manual_project_participants": Negeseuon swyddogol i gyfranogwyr y prosiect
+ "admin_rights_received": Hawliau gweinyddol a dderbyniwyd
+ "comment_deleted_by_admin": Dileu fy sylw
+ "comment_marked_as_spam": Sylw adroddiad sbam
+ "comment_on_your_comment": Ateb ar fy sylw
+ "comment_on_idea_you_follow": Sylw ar syniad rydych chi'n ei ddilyn
+ "comment_on_initiative_you_follow": Sylw ar gynnig yr ydych yn ei ddilyn
+ "cosponsor_of_your_initiative": Mae defnyddiwr yn derbyn fy ngwahoddiad i gyd-noddi fy nghynnig
+ "event_registration_confirmation": Cadarnhad cofrestru digwyddiad
+ "first_idea_published": Cyhoeddi fy syniad cyntaf
+ "idea_marked_as_spam": Adroddiad sbam syniad
+ "idea_published": Cyhoeddi fy syniad
+ "initiative_assigned_to_you": Neilltuo cynnig i mi
+ "initiative_marked_as_spam": Adroddiad sbam cynnig
+ "initiative_published": Cyhoeddi fy nghynnig
+ "invitation_to_cosponsor_initiative": Gwahoddiad i gyd-noddi cynnig
+ "initiative_resubmitted_for_review": Ailgyflwynwyd y cynnig i'w adolygu
+ "invite_received": Gwahoddiad
+ "invite_reminder": Nodyn atgoffa gwahoddiad
+ "internal_comment_on_idea_assigned_to_you": Sylw mewnol ar y mewnbwn a roddwyd i mi
+ "internal_comment_on_idea_you_commented_internally_on": Sylw mewnol ar fewnbwn y gwnes i sylwadau mewnol arno
+ "internal_comment_on_idea_you_moderate": Sylw mewnol ar fewnbwn yn y prosiect neu'r ffolder rwy'n ei reoli
+ "internal_comment_on_initiative_assigned_to_you": Sylw mewnol ar y cynnig a roddwyd i mi
+ "internal_comment_on_initiative_you_commented_internally_on": Sylw mewnol ar y cynnig y gwnes i sylwadau mewnol arno
+ "internal_comment_on_unassigned_initiative": Sylw mewnol ar gynnig heb ei aseinio
+ "internal_comment_on_unassigned_unmoderated_idea": Sylw mewnol ar fewnbwn heb ei neilltuo mewn prosiect heb ei reoli
+ "internal_comment_on_your_internal_comment": Sylw mewnol ar fy sylw mewnol
+ "mention_in_official_feedback": Soniwch mewn diweddariad
+ "mention_in_internal_comment": Crybwyll mewn sylw mewnol
+ "new_comment_for_admin": Sylw newydd mewn prosiect dwi'n ei gymedroli
+ "new_idea_for_admin": Syniad newydd mewn prosiect dwi'n ei gymedroli
+ "new_initiative_for_admin": Cynnig newydd
+ "official_feedback_on_idea_you_follow": Diweddariad ar syniad rydych chi'n ei ddilyn
+ "official_feedback_on_initiative_you_follow": Diweddariad ar gynnig yr ydych yn ei ddilyn
+ "password_reset": Ailosod cyfrinair
+ "project_moderation_rights_received": Hawliau cymedroli prosiect wedi'u derbyn
+ "project_folder_moderation_rights_received": Hawliau rheolwr ffolder wedi'u derbyn
+ "project_phase_started": Cyfnod prosiect newydd
+ "project_phase_upcoming": Cyfnod prosiect newydd sydd ar ddod
+ "project_published": Cyhoeddi'r prosiect
+ "status_change_on_idea_you_follow": Newid statws syniad rydych chi'n ei ddilyn
+ "status_change_on_initiative_you_follow": Newid statws cynnig yr ydych yn ei ddilyn
+ "threshold_reached_for_admin": Cyrhaeddodd y cynnig y trothwy pleidleisio
+ "welcome": Ar ôl cofrestru
+ "admin_digest": Trosolwg wythnosol ar gyfer gweinyddwyr
+ "moderator_digest": Trosolwg wythnosol ar gyfer rheolwyr prosiect
+ "assignee_digest": Trosolwg wythnosol o'r syniadau a neilltuwyd
+ "user_digest": Trosolwg wythnosol
+ "voting_basket_submitted": Cadarnhad o bleidleisio
+ "native_survey_not_submitted": Arolwg heb ei gyflwyno
+ "voting_basket_not_submitted": Pleidleisiau heb eu cyflwyno
+ "voting_last_chance": Cyfle olaf i bleidleisio
+ "voting_phase_started": Cyfnod prosiect newydd gyda phleidleisio
+ "voting_results": Canlyniadau pleidleisio
+ "your_proposed_initiatives_digest": Trosolwg wythnosol o'ch cynigion
+ general:
+ by_author: 'gan %{authorName}'
+ author_wrote: 'Ysgrifennodd %{authorName} :'
+ cta_goto_idea: 'Ewch i''r syniad hwn'
+ cta_goto_proposal: 'Ewch i''r cynnig hwn'
+ cta_goto_project: 'Ewch i''r prosiect hwn'
+ schedules:
+ weekly:
+ "0": "Yn wythnosol, ar ddydd Sul am %{hourOfDay}"
+ "1": "Yn wythnosol, ar ddydd Llun am %{hourOfDay}"
+ "2": "Yn wythnosol, ar ddydd Mawrth am %{hourOfDay}"
+ "3": "Yn wythnosol, ar ddydd Mercher am %{hourOfDay}"
+ "4": "Yn wythnosol, ar ddydd Iau am %{hourOfDay}"
+ "5": "Yn wythnosol, ar ddydd Gwener am %{hourOfDay}"
+ "6": "Yn wythnosol, ar ddydd Sadwrn am %{hourOfDay}"
+ footer:
+ "link_privacy_policy": "Polisi Preifatrwydd"
+ "link_terms_conditions": "Telerau ac Amodau"
+ "link_unsubscribe": "Dad-danysgrifio"
+ "powered_by": "Wedi ei bweru gan"
+ "statement": "Anfonwyd yr e-bost hwn atoch gan Go Vocal ar ran %{organizationName}, oherwydd eich bod yn ddefnyddiwr cofrestredig %{organizationLink}. Gallwch %{unsubscribeLink} os nad ydych am dderbyn yr e-byst hyn yn y dyfodol."
+ "unsubscribe_text": "dad-danysgrifio"
+ follow:
+ "unfollow_here": "Rydych chi wedi derbyn yr hysbysiad hwn oherwydd eitem rydych chi'n ei dilyn. Gallwch chi ei ddad-ddilyn yma. "
+ comment_deleted_by_admin:
+ reason: 'Y rheswm pam y cafodd eich sylw ei ddileu:'
+ cta_view: 'Gweld y syniad hwn'
+ event_description: '%{organizationName} dileu''r sylw a ysgrifennoch ar syniad.'
+ main_header: '%{organizationName} dileu eich sylw'
+ other_reason: '%{otherReason}'
+ inappropriate_reason: 'Ystyriwyd bod eich sylw yn amhriodol'
+ irrelevant_reason: 'Ystyriwyd bod eich sylw yn amherthnasol ar gyfer y cyd-destun hwnnw'
+ no_reason: 'Ni nodwyd unrhyw reswm'
+ subject: 'Mae eich sylw wedi''i ddileu o''r platfform o %{organizationName}'
+ preheader: 'Mae eich sylw wedi''i ddileu'
+ admin_digest:
+ subject: 'Eich adroddiad gweinyddol wythnosol o %{time}'
+ preheader: 'Crynhoad gweinyddol o %{organizationName}'
+ title_your_weekly_report: '%{firstName}, eich adroddiad wythnosol'
+ text_introduction: 'Rydym wedi curadu ar eich cyfer y mewnbwn sydd wedi cynhyrchu''r mwyaf o weithgarwch dros yr wythnos ddiwethaf. Darganfyddwch beth sy''n digwydd ar eich platfform!'
+ cta_visit_the_platform: 'Ymwelwch â''ch platfform'
+ new_users: 'Defnyddwyr newydd'
+ new_ideas: 'Syniadau newydd'
+ new_comments: 'Sylwadau newydd'
+ title_activity_past_week: 'Gweithgaredd yr wythnos ddiwethaf'
+ title_no_activity_past_week: 'Nid oedd unrhyw weithgaredd yn ystod yr wythnos ddiwethaf'
+ title_initiatives_past_week: 'Cynigion newydd yr wythnos ddiwethaf'
+ title_successful_initiatives_past_week: 'Cynigion a gyrhaeddodd y trothwy yn ystod yr wythnos ddiwethaf'
+ yesterday_by_author: 'Ddoe erbyn %{author}'
+ today_by_author: 'Heddiw erbyn %{author}'
+ x_days_ago_by_author: '%{x} diwrnod yn ôl erbyn %{author}'
+ admin_rights_received:
+ cta_manage_platform: 'Rheoli eich platfform'
+ message_you_became_administrator: 'Rydych wedi cael hawliau gweinyddwr ar gyfer y llwyfan cyfranogiad o %{organizationName}.'
+ preheader: 'Rhoddwyd hawliau gweinyddwr i chi ar gyfer platfform cyfranogiad %{organizationName}'
+ subject: 'Daethoch yn weinyddwr ar y platfform o %{organizationName}'
+ text_create_participatory_process: 'Fel gweinyddwr, gallwch greu a ffurfweddu prosiectau cyfranogiad newydd. Gallwch ychwanegu cyfnodau newydd gan ddefnyddio''r llinell amser. Gall pob un o''r cyfnodau hyn gael ei ymddygiad ei hun o ran postio syniadau, rhoi sylwadau a phleidleisio.'
+ text_moderate_analyse_input: 'Unwaith y bydd prosiectau wedi''u lansio, bydd y syniadau cyntaf yn dod i mewn. Byddwch yn derbyn adroddiadau wythnosol gyda''r holl weithgareddau allweddol fel eich bod yn cadw ar ben y cyfan. Bydd y trosolwg syniadau yn eich helpu i gymedroli''r mewnbwn a chydweithio i''w brosesu.'
+ text_platform_setup: 'Fel gweinyddwr gallwch chi sefydlu''ch platfform cyfranogiad. Dewiswch logo, delweddau a lliwiau, ysgrifennwch neges bersonol ar eich tudalen gartref, anfonwch wahoddiadau, diffiniwch yr hyn yr hoffech ei wybod am eich defnyddwyr, ...'
+ title_create_participatory_process: 'Dylunio''r broses gyfranogol'
+ title_moderate_analyse_input: 'Cymedroli a dadansoddi''r mewnbwn'
+ title_platform_setup: 'Gosodwch eich platfform'
+ title_what_can_you_do_administrator: 'Beth allwch chi ei wneud fel gweinyddwr?'
+ title_you_became_administrator: 'Daethoch yn weinyddwr'
+ comment_marked_as_spam:
+ by_author: 'gan %{authorName}'
+ commented: '%{authorName} sylw:'
+ cta_review_comment: 'Sylw adolygu'
+ days_ago: '%{numberOfDays} diwrnod yn ôl'
+ event_description: 'Adroddwyd am y sylw canlynol a bostiwyd ar ''%{post}'' :'
+ inappropriate_content: 'Mae''r sylw yn amhriodol neu''n sarhaus.'
+ preheader: 'Gweithredu ar y sylw hwn a adroddwyd fel sbam'
+ reported_this_because: 'Adroddodd %{reporterFirstName} hyn oherwydd:'
+ subject: '%{organizationName}: %{firstName} %{lastName} adroddodd y sylw hwn fel sbam'
+ title_comment_spam_report: '%{firstName} %{lastName} adroddodd y sylw hwn fel sbam'
+ today: Heddiw
+ wrong_content: 'Nid yw''r sylw yn berthnasol.'
+ yesterday: Ddoe
+ cosponsor_of_your_initiative:
+ cta_reply_to: 'Gweld eich cynnig'
+ event_description_initiative: 'Llongyfarchiadau! %{cosponsorName} wedi derbyn eich gwahoddiad i gyd-noddi eich cynnig.'
+ main_header: '%{cosponsorName} wedi derbyn eich gwahoddiad i gyd-noddi eich cynnig'
+ subject: '%{cosponsorName} wedi derbyn eich gwahoddiad i gyd-noddi eich cynnig'
+ preheader_initiative: '%{cosponsorName} wedi derbyn eich gwahoddiad i gyd-noddi eich cynnig'
+ assignee_digest:
+ subject: 'Syniadau sy''n gofyn am eich adborth: %{numberIdeas}'
+ preheader: 'Crynhoad aseinai o %{organizationName}'
+ title_your_weekly_report: '%{firstName}, mae mewnbwn dinasyddion yn aros am eich adborth'
+ cta_manage_your_input: 'Rheoli eich mewnbwn'
+ assigned_ideas: 'Mae syniadau angen eich adborth'
+ title_assignment_past_week: 'Syniadau diweddaraf a neilltuwyd i chi'
+ title_no_assignment_past_week: 'Dim syniadau newydd wedi''u neilltuo i chi yr wythnos diwethaf'
+ yesterday_by_author: 'Ddoe erbyn %{author}'
+ today_by_author: 'Heddiw erbyn %{author}'
+ x_days_ago_by_author: '%{x} diwrnod yn ôl erbyn %{author}'
+ idea_section: Syniadau
+ initiative_section: Cynigion
+ title_initiatives_past_week: 'Cynigion newydd wedi''u neilltuo i chi'
+ title_successful_initiatives_past_week: 'Cynigion a neilltuwyd i chi a gyrhaeddodd y trothwy'
+ idea_marked_as_spam:
+ cta_review_idea: 'Syniad adolygu'
+ report_inappropriate_offensive_content: 'Mae''r cynnwys hwn yn amhriodol neu''n sarhaus yn fy marn i.'
+ report_not_an_idea: 'Nid yw''r cynnwys hwn yn syniad ac nid yw''n perthyn yma.'
+ subject: 'Mae gennych adroddiad sbam ar y platfform o %{organizationName}'
+ preheader: 'Gweithredu ar yr adroddiad sbam hwn'
+ reported_this_because: 'Adroddodd %{reporterFirstName} hyn oherwydd:'
+ title_spam_report: '%{firstName} %{lastName} sbam wedi''i adrodd'
+ initiative_marked_as_spam:
+ cta_review_initiative: 'Adolygu''r cynnig'
+ report_inappropriate_offensive_content: 'Mae''r cynnwys hwn yn amhriodol neu''n sarhaus yn fy marn i.'
+ report_not_an_initiative: 'Nid yw''r cynnwys hwn yn gynnig ac nid yw''n perthyn yma.'
+ subject: 'Mae gennych adroddiad sbam ar y platfform o %{organizationName}'
+ preheader: 'Gweithredu ar yr adroddiad sbam hwn'
+ reported_this_because: 'Adroddodd %{reporterFirstName} hyn oherwydd:'
+ title_spam_report: '%{firstName} %{lastName} wedi adrodd am sbam'
+ initiative_assigned_to_you:
+ cta_reply_to: 'Rhowch adborth i %{authorName}'
+ event_description_initiative: 'Mae cynnig wedi''i neilltuo i chi. Rhowch adborth trwy ysgrifennu diweddariad swyddogol neu trwy newid ei statws.'
+ main_header: '%{firstName}, mae gennych aseiniad newydd'
+ subject: 'Mae gennych aseiniad ar y platfform o %{organizationName}'
+ preheader_initiative: 'Mae''r cynnig o %{authorName} wedi''i aseinio i chi'
+ invitation_to_cosponsor_initiative:
+ cta_reply_to: 'Cyd-noddi''r cynnig hwn'
+ event_description_initiative: '%{authorName} wedi creu cynnig newydd a hoffem i chi ei gyd-noddi.'
+ event_description_cosponsoring: 'Mae cyd-noddi cynnig yn golygu bydd eich enw yn cael ei arddangos gydag enwau cyd-noddwyr eraill y cynnig.'
+ event_description_before_action: 'I weld y cynnig a derbyn y gwahoddiad, rhaid i chi fod wedi mewngofnodi i''ch cyfrif.'
+ event_description_action: 'Cliciwch isod i ddarllen y cynnig.'
+ main_header: 'Rydych wedi cael eich gwahodd i gyd-noddi cynnig'
+ subject: 'Rydych wedi cael eich gwahodd i gyd-noddi cynnig'
+ preheader_initiative: 'Rydych wedi cael eich gwahodd i gyd-noddi''r cynnig o %{authorName}'
+ initiative_resubmitted_for_review:
+ by_author: 'gan %{authorName}'
+ cta_reply_to: 'Rhowch adborth i %{authorName}'
+ event_description_initiative: 'Mae cynnig wedi''i ailgyflwyno i''w adolygu. Rhowch adborth trwy ysgrifennu diweddariad swyddogol neu trwy newid ei statws.'
+ main_header: '%{firstName}, mae gennych gynnig i''w adolygu'
+ subject: 'Mae gennych gynnig i adolygu ar y llwyfan o %{organizationName}'
+ preheader_initiative: 'Mae''r cynnig o %{authorName} wedi''i ailgyflwyno i''w adolygu'
+ invite_reminder:
+ cta_accept_invitation: 'Derbyniwch eich gwahoddiad'
+ invitation_header: 'Mae eich gwahoddiad yn yr arfaeth'
+ preheader: 'Anfonodd %{organizationName} wahoddiad atoch i ymuno â''u platfform cyfranogiad rai dyddiau yn ôl.'
+ invitation_expiry_message: 'Daw''r gwahoddiad hwn i ben ymhen tua %{expiryDaysRemaining} diwrnod.'
+ subject: 'Gwahoddiad ar y gweill ar gyfer y llwyfan cyfranogiad o %{organizationName}'
+ invite_received:
+ added_a_message: 'Ysgrifennodd %{organizationName} y neges ganlynol:'
+ cta_accept_invitation: 'Derbyniwch eich gwahoddiad'
+ invitation_header: 'Mae gwahoddiad i chi!'
+ invitation_header_message: '%{organizationName} eich gwahodd i''w platfform cyfranogiad.'
+ invitation_expiry_message: 'Daw''r gwahoddiad hwn i ben mewn %{expiryDays} diwrnod.'
+ preheader: 'Anfonodd %{organizationName} wahoddiad atoch i ymuno â''u platfform cyfranogiad.'
+ subject: 'Fe''ch gwahoddir i ymuno â''r platfform o %{organizationName}'
+ initiative_published:
+ action_add_image: '%{addImageLink} i gynyddu gwelededd'
+ action_published_initiative: 'Cynnig wedi''i gyhoeddi'
+ action_send_email: 'Anfonwch %{sendEmailLink}i''ch cysylltiadau'
+ action_share_fb: 'Rhowch wybod i''ch ffrindiau ar %{fbLink}'
+ action_share_link: 'Rhannwch ef trwy unrhyw sianel trwy gopïo''r %{link}'
+ action_share_twitter: 'Rhowch wybod i''ch dilynwyr ar %{twitterLink}'
+ link: cyswllt
+ main_header: 'Fe wnaethoch chi bostio cynnig! Gadewch i ni gasglu cefnogaeth ar ei gyfer.'
+ message_next_steps: '%{userFirstName}, mae eich cynnig wedi''i gyhoeddi''n llwyddiannus ar lwyfan cyfranogiad %{organizationName}. Byddwch yn cael gwybod pan fydd pobl yn rhyngweithio â''ch cynnig. Darganfyddwch isod pa gamau nesaf y gallwch eu cymryd.'
+ message_get_votes: 'Cyrraedd y trothwy pleidleisio:'
+ preheader: 'Diolch am rannu eich cynnig %{initiativeTitle} ar gyfer %{organizationName}. Y cam nesaf yw cael cefnogaeth i''ch cynnig trwy ei rannu ar draws eich rhwydwaith.'
+ send_email: ebost
+ subject: 'Cyhoeddwyd eich cynnig ar lwyfan %{organizationName}'
+ mention_in_comment:
+ cta_reply_to: 'Ymateb i %{commentAuthor}'
+ event_description: 'Mae %{commentAuthorFull} wedi sôn amdanoch chi yn ei sylw ar y syniad ''%{post}''. Cliciwch y ddolen isod i fynd i mewn i''r sgwrs gyda %{commentAuthor}'
+ main_header: 'Mae pobl yn siarad amdanoch chi'
+ subject: 'Soniodd rhywun amdanoch chi ar y platfform o %{organizationName}'
+ preheader: '%{commentAuthor} sôn amdanoch chi mewn sylw'
+ mention_in_internal_comment:
+ cta_reply_to: 'Gweld y sylw gan %{firstName}'
+ event_description: '%{authorNameFull} sôn amdanoch chi mewn sylw mewnol.'
+ subject: '%{firstName} sôn amdanoch chi mewn sylw mewnol.'
+ main_header: '%{firstName} sôn amdanoch chi mewn sylw mewnol.'
+ preheader: '%{authorNameFull} sôn amdanoch chi mewn sylw mewnol.'
+ moderator_digest:
+ subject: 'Eich adroddiad rheolwr prosiect wythnosol o %{time}'
+ preheader: 'Crynhoad rheolwr prosiect o %{organizationName}'
+ title_your_weekly_report: '%{firstName}, eich adroddiad wythnosol'
+ text_introduction: 'Rydym wedi curadu ar eich cyfer y mewnbwn sydd wedi cynhyrchu''r mwyaf o weithgarwch dros yr wythnos ddiwethaf. Darganfyddwch beth sy''n digwydd gyda''ch prosiect!'
+ cta_manage: 'Rheoli eich prosiect'
+ new_users: 'Defnyddwyr newydd'
+ new_ideas: 'Syniadau newydd'
+ new_comments: 'Sylwadau newydd'
+ title_inputs_past_week: 'Mewnbynnau newydd yn ystod yr wythnos ddiwethaf'
+ title_no_inputs_past_week: 'Dim mewnbynnau newydd yn ystod yr wythnos ddiwethaf'
+ yesterday_by_author: 'Ddoe erbyn %{author}'
+ today_by_author: 'Heddiw erbyn %{author}'
+ x_days_ago_by_author: '%{x} diwrnod yn ôl erbyn %{author}'
+ new_comment_for_admin:
+ commented: '%{authorFirstName} sylw:'
+ cta_reply_to: 'Gweld y sylw %{commentAuthor}'
+ days_ago: '%{numberOfDays} diwrnod yn ôl'
+ event_description: 'Ychwanegodd %{authorName} sylw newydd ar eich platfform.'
+ main_header: '%{firstName}, mae sylw newydd wedi''i bostio ar eich platfform'
+ subject: 'Mae sylw newydd wedi''i bostio ar y llwyfan %{organizationName}''s'
+ preheader: 'Gadawodd %{authorName} sylw'
+ today: Heddiw
+ yesterday: Ddoe
+ comment_on_idea_you_follow:
+ cta_reply_to: 'Ymateb i %{commentAuthor}'
+ event_description: 'Rhoddodd %{authorNameFull} ymateb i''r syniad ''%{ideaTitle}''. Cliciwch y botwm isod i barhau â''r sgwrs gyda %{authorName}.'
+ main_header: '%{authorName} sylw ar syniad rydych chi''n ei ddilyn'
+ subject: 'Mae sylw newydd ar syniad rydych chi''n ei ddilyn'
+ preheader: 'Gadawodd %{authorName} sylw ar syniad ar gyfer %{organizationName}'
+ comment_on_initiative_you_follow:
+ cta_reply_to: 'Ymateb i %{commentAuthor}'
+ event_description: 'Rhoddodd %{authorNameFull} ymateb i''r cynnig ''%{initiativeTitle}''. Cliciwch y botwm isod i barhau â''r sgwrs gyda %{authorName}.'
+ main_header: '%{commentAuthor} sylw ar gynnig yr ydych yn ei ddilyn'
+ subject: 'Mae sylw newydd ar y cynnig rydych chi''n ei ddilyn'
+ preheader: 'Gadawodd %{authorName} sylw ar gynnig ar gyfer %{organizationName}'
+ new_initiative_for_admin:
+ cta_reply_to: 'Rhowch adborth i %{authorName}'
+ event_description: 'Mae %{authorName} wedi cyhoeddi cynnig newydd ar eich platfform. Darganfyddwch ef nawr, rhowch ychydig o adborth neu newidiwch ei statws!'
+ main_header: '%{firstName}, mae cynnig newydd wedi''i gyhoeddi ar eich platfform'
+ subject: 'Cyhoeddodd rhywun gynnig newydd ar y llwyfan o %{organizationName}'
+ preheader: 'Cyhoeddodd %{authorName} gynnig newydd ar eich platfform'
+ new_idea_for_admin:
+ commented: '%{authorFirstName} sylw:'
+ cta_reply_to: 'Rhowch adborth i %{authorName}'
+ days_ago: '%{numberOfDays} diwrnod yn ôl'
+ event_description: 'Mae %{authorName} wedi cyhoeddi syniad newydd ar eich platfform. Darganfyddwch ef nawr, rhowch ychydig o adborth neu newidiwch ei statws!'
+ main_header: '%{firstName}, mae syniad newydd wedi''i gyhoeddi ar eich platfform'
+ subject: 'Mae post newydd wedi''i gyhoeddi ar lwyfan %{organizationName}''s'
+ preheader: 'Cyhoeddodd %{authorName} syniad newydd ar eich platfform'
+ today: Heddiw
+ yesterday: Ddoe
+ comment_on_your_comment:
+ cta_reply_to: 'Ymateb i %{firstName}'
+ event_description: 'Ysgrifennodd %{authorNameFull} ateb i''ch sylw ar ''%{post}'' ar y llwyfan cyfranogiad. Cliciwch y botwm isod i barhau â''r sgwrs gyda %{authorName}.'
+ subject: 'Rydych chi wedi derbyn ateb ar eich sylw ar y platfform o %{organizationName}'
+ main_header: '%{authorName} atebodd eich sylw'
+ preheader: 'Atebodd %{authorName} eich sylw ar blatfform %{organizationName}'
+ replied: '%{authorFirstName} atebodd:'
+ internal_comment_on_your_internal_comment:
+ cta_reply_to: 'Gweld y sylw gan %{firstName}'
+ event_description: '%{authorNameFull} sylw ar eich sylw mewnol.'
+ subject: 'Rydych wedi derbyn sylw ar eich sylw mewnol ar ''%{post}'''
+ main_header: 'Rydych wedi derbyn sylw ar eich sylw mewnol ar ''%{post}'''
+ preheader: 'Ymatebodd %{authorName} i''ch sylw mewnol ar ''%{post}'''
+ internal_comment_on_idea_assigned_to_you:
+ cta_reply_to: 'Gweld y sylw gan %{firstName}'
+ event_description: '%{authorNameFull} sylwadau mewnol ar fewnbwn a neilltuwyd i chi.'
+ subject: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ main_header: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ preheader: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ internal_comment_on_idea_you_commented_internally_on:
+ cta_reply_to: 'Gweld y sylw gan %{firstName}'
+ event_description: '%{authorNameFull} sylwadau mewnol ar fewnbwn y gwnaethoch sylwadau mewnol arno.'
+ subject: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ main_header: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ preheader: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ internal_comment_on_idea_you_moderate:
+ cta_reply_to: 'Gweld y sylw gan %{firstName}'
+ event_description: '%{authorNameFull} sylwadau mewnol ar fewnbwn mewn prosiect neu ffolder yr ydych yn ei reoli.'
+ subject: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ main_header: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ preheader: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ internal_comment_on_initiative_assigned_to_you:
+ cta_reply_to: 'Gweld y sylw gan %{firstName}'
+ event_description: '%{authorNameFull} sylwadau mewnol ar gynnig a roddwyd i chi.'
+ subject: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ main_header: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ preheader: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ internal_comment_on_initiative_you_commented_internally_on:
+ cta_reply_to: 'Gweld y sylw gan %{firstName}'
+ event_description: '%{authorNameFull} sylwadau mewnol ar gynnig y gwnaethoch sylwadau mewnol arno.'
+ subject: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ main_header: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ preheader: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ internal_comment_on_unassigned_initiative:
+ cta_reply_to: 'Gweld y sylw gan %{firstName}'
+ event_description: '%{authorNameFull} sylwadau mewnol ar gynnig heb ei aseinio.'
+ subject: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ main_header: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ preheader: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ internal_comment_on_unassigned_unmoderated_idea:
+ cta_reply_to: 'Gweld y sylw gan %{firstName}'
+ event_description: '%{authorNameFull} sylwadau mewnol ar fewnbwn heb ei neilltuo mewn prosiect heb ei reoli.'
+ subject: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ main_header: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ preheader: 'Mae gan ''%{post}'' sylw mewnol newydd'
+ official_feedback_on_idea_you_follow:
+ header_message: 'Rhoddodd %{officialName} ddiweddariad ar y syniad ''%{ideaTitle}''. Cliciwch y botwm isod i fynd i mewn i''r sgwrs gyda %{officialName}.'
+ header_title: 'Mae yna ddiweddariad ar syniad rydych chi''n ei ddilyn'
+ subject: 'Mae syniad rydych chi''n ei ddilyn wedi derbyn diweddariad swyddogol ar y platfform o %{organizationName}'
+ preheader: 'Mae yna ddiweddariad ar syniad rydych chi''n ei ddilyn'
+ official_feedback_on_initiative_you_follow:
+ header_message: 'Rhoddodd %{officialName} ddiweddariad ar y cynnig ''%{initiativeTitle}''. Cliciwch y botwm isod i fynd i mewn i''r sgwrs gyda %{organizationName}.'
+ header_title: 'Mae diweddariad ar gynnig rydych chi''n ei ddilyn'
+ subject: 'Mae cynnig rydych chi''n ei ddilyn wedi derbyn diweddariad swyddogol ar y platfform o %{organizationName}'
+ preheader: 'Mae diweddariad ar gynnig rydych chi''n ei ddilyn'
+ mention_in_official_feedback:
+ cta_reply_to: 'Ymateb i %{organizationName}'
+ event_description: 'Soniodd %{organizationName} amdanoch chi yn eu hadborth ar y syniad ''%{post}''. Cliciwch y ddolen isod i fynd i mewn i''r sgwrs gyda %{organizationName}'
+ main_header: 'Yr ydych wedi cael eich crybwyll'
+ subject: '%{organizationName} sôn amdanoch chi yn eu hadborth'
+ preheader: '%{commentAuthor} sôn amdanoch chi mewn adborth'
+ project_moderation_rights_received:
+ cta_manage_project: 'Rheoli''r prosiect hwn'
+ message_you_became_moderator: 'Mae gweinyddwr y platfform cyfranogiad o %{organizationName} newydd eich gwneud yn rheolwr prosiect y prosiect canlynol:'
+ no_ideas: 'Dim syniadau eto'
+ preheader: 'Mae gweinyddwr y platfform cyfranogiad o %{organizationName} newydd eich gwneud chi''n rheolwr prosiect y prosiect canlynol'
+ subject: 'Daethoch yn rheolwr prosiect ar y platfform o %{organizationName}'
+ text_design_participatory_process: 'Fel rheolwr prosiect, gallwch chi ffurfweddu sut mae defnyddwyr yn rhyngweithio o fewn eich prosiect. Gallwch ychwanegu cyfnodau newydd gan ddefnyddio''r llinell amser. Gall pob un o''r cyfnodau hyn gael ei ymddygiad ei hun o ran postio syniadau, rhoi sylwadau a phleidleisio.'
+ text_moderate_analyse_input: 'Unwaith y bydd y prosiect wedi''i lansio, bydd y syniadau cyntaf yn dod i mewn. Byddwch yn derbyn adroddiadau wythnosol gyda''r holl weithgareddau allweddol fel eich bod yn cadw ar ben y cyfan. Bydd y trosolwg syniadau ym marn eich rheolwr prosiect yn eich helpu i ddeall pa syniadau a gafodd fwyaf o hoff a chas bethau.'
+ text_share_project_information: 'Er mwyn cynyddu ansawdd y syniadau rydych chi''n eu cael, mae''n allweddol rhannu digon o wybodaeth: ychwanegu disgrifiad o''r prosiect, atodi delweddau (gan gynnwys brasluniau a chynlluniau), a chyfathrebu''r holl ddigwyddiadau cysylltiedig sy''n digwydd. Cofiwch: mae gwybodaeth dda yn rhagflaenu cyfranogiad da!'
+ title_design_participatory_process: 'Dylunio''r broses gyfranogol'
+ title_moderate_analyse_input: 'Cymedroli a dadansoddi''r mewnbwn'
+ title_share_project_information: 'Darparu gwybodaeth am y prosiect'
+ title_what_can_you_do_moderator: 'Beth allwch chi ei wneud fel rheolwr prosiect?'
+ title_you_became_moderator: 'Daethoch yn rheolwr prosiect'
+ x_ideas: '%{numberOfIdeas} syniadau'
+ project_folder_moderation_rights_received:
+ cta_view_folder_button: 'Gweld y ffolder hon'
+ message_added_as_folderadmin: 'Rydych chi wedi cael hawliau rheolwr ffolder ar lwyfan cyfranogiad %{organizationName}ar gyfer y ffolder canlynol:'
+ no_projects: 'Dim prosiectau eto'
+ preheader: 'Mae gweinyddwr y platfform cyfranogiad o %{organizationName} newydd eich gwneud chi''n rheolwr ar y ffolder canlynol'
+ subject: 'Daethoch yn rheolwr ffolder prosiect ar lwyfan cyfranogiad %{organizationName}'
+ text_manage_folder: 'Mae ffolder yn ffordd o drefnu sawl prosiect cyfranogiad gyda''i gilydd. Fel rheolwr ffolder, gallwch olygu''r disgrifiad ffolder a ffolder a chreu prosiectau newydd (i ddileu prosiectau, cysylltwch â gweinyddwr eich platfform). Bydd gennych hefyd hawliau rheoli prosiect dros yr holl brosiectau yn y ffolder, gan ganiatáu i chi olygu''r prosiectau, rheoli''r mewnbynnau ac e-bostio cyfranogwyr.'
+ text_moderate_analyse_input: 'Unwaith y bydd y prosiectau wedi''u lansio, bydd y mewnbynnau cyntaf yn dechrau dod i mewn. Byddwch yn derbyn adroddiadau wythnosol gyda''r gweithgareddau allweddol fel y gallwch gadw ar ben yr hyn sy''n digwydd. Mae''r Rheolwr Mewnbwn yn eich panel ''Rheoli Platfform'' yn eich galluogi i weld a rheoli''r mewnbwn, gan gynnwys pennu statws ac ymateb i bostiadau a sylwadau.'
+ text_design_participatory_process: 'Gallwch reoli''r gwahanol brosiectau cyfranogiad yn eich ffolder - ffurfweddu''r dull cyfranogiad, ychwanegu disgrifiad o''r prosiect, atodi delweddau, a chyfathrebu digwyddiadau cysylltiedig. Gallwch hefyd reoli sut mae cyfranogwyr yn rhyngweithio â''ch prosiectau, gan gynnwys gosod hawliau mynediad a ffurfweddu''r gosodiadau postio, pleidleisio a rhoi sylwadau.'
+ title_design_participatory_process: 'Dylunio''r broses gyfranogol'
+ title_moderate_analyse_input: 'Cymedroli a dadansoddi''r mewnbwn'
+ title_manage_folder: 'Rheoli gosodiadau''r ffolder a chreu prosiectau newydd.'
+ title_what_can_you_do_folderadmin: 'Beth allwch chi ei wneud fel rheolwr ffolder?'
+ title_added_as_folderadmin: 'Rydych chi wedi cael eich ychwanegu fel rheolwr ffolderi'
+ x_projects: '%{numberOfProjects} prosiectau'
+ project_phase_started:
+ cta_view_phase: 'Darganfyddwch y cyfnod newydd hwn'
+ event_description: 'Dechreuodd y prosiect hwn gam newydd ar y llwyfan o %{organizationName}. Cliciwch ar y ddolen isod i ddysgu mwy!'
+ main_header: 'Cam newydd wedi dechrau ar gyfer prosiect ''%{projectName}'''
+ subtitle: 'Ynglŷn â ''%{projectName}'''
+ new_phase: 'Dechreuodd y prosiect hwn y cam ''%{phaseTitle}'''
+ subject: 'Aeth %{projectName} i mewn i gyfnod newydd'
+ preheader: 'Mae cyfnod newydd wedi cychwyn ar gyfer %{projectName}'
+ project_phase_upcoming:
+ cta_view_phase: 'Gosodwch y cam newydd hwn i fyny'
+ event_description: 'Bydd y prosiect ''%{projectName}'' yn cychwyn ar gyfnod newydd yn fuan. Sicrhewch fod popeth wedi''i drefnu ar gyfer y cam hwn: A oes disgrifiad digonol? A yw syniadau dethol yn cael eu trosglwyddo i''r cyfnod hwn? Ydych chi am roi gwybod i''ch dinasyddion am fanylion y cam hwn trwy ymgyrch e-bost wedi''i deilwra?'
+ main_header: '%{firstName}, bydd prosiect yn cychwyn ar gyfnod newydd yn fuan'
+ subtitle: 'Ynglŷn â ''%{projectName}'''
+ new_phase: 'Bydd y prosiect yn cychwyn ar y cam ''%{phaseTitle}'''
+ subject: 'Trefnwch bopeth ar gyfer y cyfnod newydd o %{projectName}'
+ preheader: 'Bydd cyfnod newydd yn cychwyn yn fuan ar gyfer %{projectName}'
+ project_published:
+ subject: 'Cyhoeddwyd prosiect newydd ar lwyfan %{organizationName}'
+ header_title: 'Cyhoeddwyd prosiect newydd'
+ header_message: 'Mae platfform cyfranogiad %{organizationName} newydd gyhoeddi''r prosiect canlynol:'
+ preheader: 'Cyhoeddwyd prosiect newydd'
+ status_change_on_idea_you_follow:
+ status_change: 'Statws newydd y syniad hwn yw ''%{ideaStatus}'''
+ header_message: 'Diweddarodd %{organizationName} statws y syniad ''%{ideaTitle}'' ar eu platfform cyfranogiad digidol.'
+ header_title: 'Mae gan syniad rydych chi''n ei ddilyn statws newydd'
+ subject: 'Mae statws syniad rydych chi''n ei ddilyn wedi''i newid'
+ preheader: 'Mae gan syniad rydych chi''n ei ddilyn statws newydd'
+ status_change_on_initiative_you_follow:
+ status_change: 'Statws newydd y cynnig hwn yw ''%{initiativeStatus}'''
+ header_message: 'Mae statws y cynnig ''%{initiativeTitle}'' wedi''i ddiweddaru ar lwyfan cyfranogiad digidol %{organizationName}.'
+ header_title: 'Mae gan gynnig a ddilynwch statws newydd'
+ subject: 'Mae statws cynnig a ddilynwch wedi newid'
+ preheader: 'Mae gan gynnig a ddilynwch statws newydd'
+ user_digest:
+ subject: "Eich gweithgaredd ar y platfform cyfranogiad o %{organizationName}"
+ commented: "%{authorFirstName} sylw:"
+ preheader: "Trosolwg wythnosol o %{organizationName}"
+ title_your_weekly_report: "Darganfyddwch beth ddigwyddodd wythnos diwethaf"
+ intro_text: "Dyma grynodeb o'r hyn a ddigwyddodd ar lwyfan cyfranogiad %{organizationName}."
+ cta_go_to_the_platform: "Ewch i'r platfform"
+ title_no_activity_past_week: "Dim gweithgaredd yn ystod yr wythnos ddiwethaf"
+ title_proposals: "Cynigion wedi dechrau"
+ proposals_started_text: "Mae cynigion yn syniadau sydd angen eu denu a’u cefnogi gan eraill (pobl fel chi!) er mwyn symud ymlaen. Isod mae rhestr o gynigion a gyflwynwyd yn ystod yr wythnos ddiwethaf. Cliciwch ar unrhyw un ohonynt i gael golwg a chynnig eich cefnogaeth ac adborth!"
+ title_successful_proposals: "Cynigion a gyrhaeddodd y trothwy"
+ successful_proposals_text: "Mae'r cynigion hyn wedi cael digon o gefnogaeth i symud i'r cam nesaf! Cliciwch ar y cynnig i ddysgu mwy am yr hyn sy'n digwydd nesaf."
+ today_by_author: "Heddiw erbyn %{author}"
+ yesterday_by_author: "Ddoe erbyn %{author}"
+ x_days_ago_by_author: "%{x} diwrnod yn ôl erbyn %{author}"
+ trending_ideas: "Syniadau tueddiadol"
+ trending_ideas_text: "Diddordeb yn yr hyn sydd wedi bod yn digwydd ar y platfform? Dyma'r tri syniad mwyaf poblogaidd a'r hyn y mae pobl yn ei ddweud amdanynt."
+ no_notifications: "Dim hysbysiadau"
+ one_notification: "1 hysbysiad"
+ multiple_notifications: "%{notifCount} hysbysiadau"
+ no_unread_notifications: "Nid oes gennych unrhyw hysbysiadau heb eu darllen. Ymwelwch â'r platfform i gyfrannu eich mewnbwn a chynhyrchu hysbysiadau newydd!"
+ unread_notifications: "Mae gennych hysbysiadau heb eu darllen. Ewch i'r platfform i ddarganfod beth sy'n digwydd!"
+ threshold_reached_for_admin:
+ cta_process_initiative: 'Ewch â''r cynnig hwn i''r camau nesaf'
+ event_description: 'Cyrhaeddodd cynnig y trothwy pleidleisio ar eich platfform. Cliciwch y botwm isod i fynd ag ef i''r camau nesaf!'
+ main_header: 'Cynnig wedi cyrraedd y trothwy pleidleisio!'
+ subject: 'Cyrhaeddodd cynnig y trothwy pleidleisio ar eich platfform'
+ preheader: 'Gwnewch yn siŵr eich bod chi''n cymryd y camau nesaf'
+ first_idea_published:
+ action_add_image: '%{addImageLink} i gynyddu gwelededd'
+ action_comment: '%{textComment} ar syniadau presennol'
+ action_published_idea: 'Syniad wedi''i gyhoeddi'
+ action_send_email: 'Anfonwch %{sendEmailLink}i''ch cysylltiadau'
+ action_share_fb: 'Rhowch wybod i''ch ffrindiau ar %{fbLink}'
+ action_share_link: 'Rhannwch ef trwy unrhyw sianel trwy gopïo''r %{link}'
+ action_share_twitter: 'Rhowch wybod i''ch dilynwyr ar %{twitterLink}'
+ add_image: 'Ychwanegu delwedd'
+ cta_view_idea: 'Ewch at eich syniad'
+ event_description: '%{firstName}, llongyfarchiadau ar eich syniad cyntaf ar y llwyfan cyfranogiad o %{organizationName}. Byddwch yn cael gwybod pan fydd pobl yn rhyngweithio â''ch syniad. Darganfyddwch isod pa gamau nesaf y gallwch eu cymryd.'
+ link: cyswllt
+ main_header: '%{firstName}, fe wnaethoch chi bostio''ch syniad cyntaf!'
+ message_get_votes: 'Cyrraedd mwy o bobl gyda''ch syniad:'
+ preheader: '%{firstName}, llongyfarchiadau ar bostio eich syniad cyntaf ar y llwyfan o %{organizationName}. Nawr casglwch gefnogaeth i''ch syniad'
+ see_you: 'Welwn ni chi ar y platfform yn fuan!'
+ send_email: ebost
+ subject: 'Eich syniad cyntaf ar y platfform o %{organizationName}'
+ welcome:
+ cta_join_platform: 'Darganfyddwch y platfform'
+ subject: 'Croeso i''r platfform o %{organizationName}'
+ main_header: Croeso!
+ message_welcome: 'Llongyfarchiadau, gwnaethoch gofrestru''n llwyddiannus ar y platfform cyfranogiad o %{organizationName}. Nawr gallwch chi ddarganfod y platfform a sicrhau bod eich llais yn cael ei glywed. Gallwch hefyd ychwanegu llun proffil a disgrifiad byr i ddweud wrth eraill pwy ydych chi.'
+ preheader: 'Dyma beth allwch chi ei wneud ar y platfform o %{organizationName}'
+ idea_published:
+ action_add_image: '%{addImageLink} i gynyddu gwelededd'
+ action_published_idea: 'Syniad wedi''i gyhoeddi'
+ action_send_email: 'Anfonwch %{sendEmailLink}i''ch cysylltiadau'
+ action_share_fb: 'Rhowch wybod i''ch ffrindiau ar %{fbLink}'
+ action_share_link: 'Rhannwch ef trwy unrhyw sianel trwy gopïo''r %{link}'
+ action_share_twitter: 'Rhowch wybod i''ch dilynwyr ar %{twitterLink}'
+ add_image: 'Ychwanegu delwedd'
+ cta_view_idea: 'Ewch at eich syniad'
+ event_description: '%{firstName}, mae eich syniad wedi''i gyhoeddi''n llwyddiannus ar lwyfan cyfranogiad %{organizationName}. Byddwch yn cael gwybod pan fydd pobl yn rhyngweithio â''ch syniad. Darganfyddwch isod pa gamau nesaf y gallwch eu cymryd.'
+ link: cyswllt
+ main_header: 'Fe wnaethoch chi bostio syniad! Gadewch i ni sicrhau ei fod yn cael ei ddarllen.'
+ message_get_votes: 'Cyrraedd mwy o bobl gyda''ch syniad:'
+ preheader: '%{firstName}, llongyfarchiadau ar bostio''ch syniad ar lwyfan %{organizationName}. Nawr casglwch gefnogaeth.'
+ see_you: 'Welwn ni chi ar y platfform yn fuan!'
+ send_email: ebost
+ subject: 'Eich syniad ar y platfform o %{organizationName}'
+ message_next_steps: ""
+ your_proposed_initiatives_digest:
+ subject: 'Diweddariad wythnosol o''ch cynigion'
+ preheader: 'Beth ddigwyddodd gyda''ch cynigion yn ystod yr wythnos ddiwethaf?'
+ title_your_weekly_report: 'Sut mae eich cynigion wedi bod yn gwneud?'
+ text_introduction: 'Dewch o hyd i''r rhifau allweddol isod ac ewch i''r platfform i weithredu a chasglu digon o gefnogaeth mewn pryd.'
+ cta_see_your_initiative: 'Ewch i''ch cynigion'
+ total_votes: 'Cyfanswm y pleidleisiau'
+ new_votes: 'Pleidleisiau newydd'
+ remaining_votes: 'Pleidleisiau yn weddill'
+ remaining_days: 'Dyddiau yn weddill'
+ voting_basket_submitted:
+ subject: '%{organizationName}: Fe wnaethoch chi bleidleisio''n llwyddiannus'
+ preheader: 'Fe wnaethoch chi bleidleisio''n llwyddiannus ar y platfform cyfranogiad o %{organizationName}'
+ title_basket_submitted: 'Fe wnaethoch chi bleidleisio''n llwyddiannus'
+ event_description: 'Diolch am gymryd rhan. Mae eich pleidleisiau wedi''u cofnodi. Ewch i''r platfform o %{organizationName} i weld a rheoli''ch pleidleisiau.'
+ cta_see_votes_submitted: 'Gweler y pleidleisiau a gyflwynwyd'
+ cta_message: 'Cliciwch ar y botwm isod i gymryd rhan'
+ native_survey_not_submitted:
+ subject: '%{organizationName}: Bron yno! Cyflwyno''ch atebion'
+ preheader: 'Ni wnaethoch gwblhau eich ymateb i''r arolwg ar y llwyfan cyfranogiad o %{organizationName}'
+ title_native_survey_not_submitted: 'Bron yna! Cyflwyno''ch atebion'
+ body_native_survey_not_submitted: 'Dechreuoch chi rannu''ch atebion ar %{phaseTitle} ond ni wnaethoch eu cyflwyno. Bydd cyflwyniadau yn cau ar %{phaseEndDate}. Cliciwch ar y botwm isod i barhau lle gwnaethoch adael.'
+ body_native_survey_not_submitted_no_date: 'Dechreuoch chi rannu''ch atebion ar %{phaseTitle} ond ni wnaethoch eu cyflwyno. Cliciwch ar y botwm isod i barhau lle gwnaethoch adael.'
+ cta_complete_your_survey_response: 'Ailddechrau eich ymateb i''r arolwg'
+ voting_basket_not_submitted:
+ subject: '%{organizationName}: Ni wnaethoch gyflwyno eich pleidleisiau'
+ preheader: 'Ni wnaethoch gyflwyno''ch pleidleisiau ar y llwyfan cyfranogiad o %{organizationName}'
+ title_basket_not_submitted: 'Ni wnaethoch gyflwyno eich pleidleisiau'
+ event_description: 'Fe wnaethoch chi ddewis ychydig o opsiynau ar gyfer %{contextTitle} ond ni wnaethoch chi gyflwyno''ch dewis.'
+ cta_view_options_and_vote: 'Gweld opsiynau a phleidleisio'
+ cta_message: 'Cliciwch ar y botwm isod i gyflwyno''r opsiynau a ddewiswyd gennych'
+ voting_last_chance:
+ subject: '%{organizationName}: Cyfle olaf i bleidleisio o blaid %{phaseTitle}'
+ preheader: 'Cyfle olaf i bleidleisio o blaid %{phaseTitle} ar lwyfan cyfranogiad %{organizationName}'
+ title_last_chance: 'Cyfle olaf i bleidleisio o blaid %{phaseTitle}'
+ body_1: 'Mae’r cyfnod pleidleisio ar gyfer y prosiect %{projectTitle} yn dod i ben yfory, am hanner nos.'
+ body_2: 'Mae amser yn mynd yn brin, a sylwon ni nad ydych chi wedi bwrw eich pleidlais eto! Gweithredwch nawr trwy glicio ar y botwm isod i gymryd rhan.'
+ body_3: 'Drwy wneud hynny, byddwch yn cael mynediad i ystod o opsiynau a chyfle i roi eich mewnbwn, sy''n hanfodol wrth benderfynu ar ddyfodol y prosiect hwn.'
+ cta_vote: 'Pleidlais'
+ voting_results:
+ subject: '%{organizationName}: %{phaseTitle} canlyniadau pleidlais wedi''u datgelu!'
+ preheader: '%{phaseTitle} canlyniadau pleidlais a ddatgelwyd ar lwyfan cyfranogiad %{organizationName}'
+ title_results: '%{phaseTitle} canlyniadau pleidlais wedi''u datgelu!'
+ body_1: 'Mae''r canlyniadau i mewn!'
+ body_2: 'Mae canlyniadau''r bleidlais %{phaseTitle} yn y platfform %{organizationName} ~ wedi''u cyhoeddi!'
+ body_3: 'Rydym yn eich annog i adolygu''r canlyniadau ac aros yn ymwybodol o ddiweddariadau pellach ar y camau nesaf.'
+ cta_see_results: 'Gweld canlyniadau yn y platfform'
+ event_registration_confirmation:
+ subject: "Rydych chi i mewn! Mae eich cofrestriad ar gyfer \"%{eventTitle}\" wedi ei gadarnhau"
+ header_message: "%{firstName}, diolch am gofrestru ar gyfer"
+ event_details:
+ labels:
+ date: 'Dyddiad'
+ location: 'Lleoliad'
+ online_link: 'Dolen ar-lein'
+ description: 'Disgrifiad'
+ project: 'Prosiect'
+ cta_go_to_event: 'Gweld y digwyddiad'
+ cta_add_to_calendar: 'Ychwanegu at eich calendr'
+ voting_phase_started:
+ subject: '%{organizationName}: Dechreuodd y cyfnod pleidleisio ar gyfer %{projectName}'
+ preheader: 'Dechreuodd y cyfnod pleidleisio ar gyfer %{projectName} ar y llwyfan cyfranogiad o %{organizationName}'
+ event_description: 'Mae''r prosiect "%{projectName}" yn gofyn i chi bleidleisio rhwng %{numIdeas} opsiynau:'
+ cta_message: 'Cliciwch ar y botwm isod i gymryd rhan'
+ cta_vote: 'Ewch i''r platfform i bleidleisio'
+ admin_labels:
+ recipient_role:
+ admins: 'I weinyddwyr'
+ admins_and_managers: 'I weinyddwyr a rheolwyr'
+ managers: 'I reolwyr'
+ project_participants: 'I gyfranogwyr y prosiect'
+ registered_users: 'I ddefnyddwyr cofrestredig'
+ recipient_segment:
+ admins: 'Gweinyddwyr'
+ admins_and_managers: 'Gweinyddwyr a rheolwyr'
+ admins_and_managers_managing_the_project: 'Gweinyddwyr a rheolwyr sy''n rheoli''r prosiect'
+ managers_managing_the_project: 'Rheolwyr sy''n rheoli''r prosiect'
+ all_users: 'Pob defnyddiwr'
+ all_users_who_uploaded_proposals: 'Pob defnyddiwr a uwchlwythodd gynigion'
+ managers: 'Rheolwyr'
+ admins_assigned_to_a_proposal: 'Gweinyddwyr wedi''u neilltuo i gynnig'
+ admins_and_managers_assigned_to_the_input: 'Gweinyddwyr a rheolwyr wedi''u neilltuo i''r mewnbwn'
+ new_attendee: 'Defnyddiwr sydd newydd gofrestru'
+ user_who_is_invited_to_cosponsor_a_proposal: 'Defnyddiwr sy''n cael ei wahodd i gyd-noddi cynnig'
+ user_who_is_receiving_admin_rights: 'Defnyddiwr sy''n derbyn hawliau gweinyddol'
+ user_who_is_receiving_folder_moderator_rights: 'Defnyddiwr sy''n derbyn hawliau safonwr ffolder'
+ user_who_is_receiving_project_moderator_rights: 'Defnyddiwr sy''n derbyn hawliau safonwr prosiect'
+ user_who_commented: 'Defnyddiwr a wnaeth sylw'
+ user_who_is_mentioned: 'Defnyddiwr sy''n cael ei grybwyll'
+ user_who_published_the_proposal: 'Defnyddiwr a gyhoeddodd y cynnig'
+ user_who_published_the_input: 'Defnyddiwr a gyhoeddodd y mewnbwn'
+ user_who_registers: 'Defnyddiwr sy''n cofrestru'
+ user_who_was_invited: 'Defnyddiwr a wahoddwyd'
+ users_who_engaged_with_the_project: 'Defnyddwyr a ymgysylltodd â''r prosiect'
+ users_who_follow_the_proposal: 'Defnyddwyr sy''n dilyn y cynnig'
+ users_who_follow_the_input: 'Defnyddwyr sy''n dilyn y mewnbwn'
+ users_who_follow_the_project: 'Defnyddwyr sy''n dilyn y prosiect'
+ user_who_voted: 'Defnyddiwr a bleidleisiodd'
+ user_with_unsubmitted_votes: 'Defnyddiwr nad yw wedi cyflwyno ei bleidleisiau'
+ users_who_engaged_but_not_voted: 'Defnyddwyr a ymgysylltodd â''r prosiect ond nad ydynt wedi pleidleisio'
+ user_with_unsubmitted_survey: 'Defnyddiwr sydd wedi dechrau ond heb gyflwyno ei arolwg'
+ content_type:
+ comments: 'Sylwadau'
+ content_moderation: 'Cymedroli cynnwys'
+ events: 'Digwyddiadau'
+ general: 'Cyffredinol'
+ inputs: 'Mewnbynnau'
+ internal_comments: 'Sylwadau mewnol'
+ permissions: 'Caniatadau'
+ projects: 'Prosiectau'
+ proposals: 'Cynigion'
+ reactions: 'Adweithiau'
+ voting: 'Pleidleisio'
+ surveys: 'Arolygon'
+ trigger:
+ comment_is_deleted: 'Sylw yn cael ei ddileu'
+ comment_is_flagged_as_spam: 'Sylw yn cael ei fflagio fel sbam'
+ content_gets_flagged_as_innapropiate: 'Mae cynnwys yn cael ei nodi fel innapropiate'
+ input_is_assigned: 'Rhoddir mewnbwn'
+ input_is_flagged_as_spam: 'Mae mewnbwn yn cael ei nodi fel sbam'
+ input_is_updated: 'Mae mewnbwn yn derbyn adborth swyddogol'
+ input_status_changes: 'Newidiadau statws mewnbwn'
+ initiative_resubmitted_for_review: 'Ailgyflwynwyd y cynnig i''w adolygu'
+ internal_comment_is_posted_on_idea_assigned_to_user: 'Sylw mewnol yn cael ei bostio ar fewnbwn a neilltuwyd i''r defnyddiwr'
+ internal_comment_is_posted_on_initiative_assigned_to_user: 'Sylw mewnol yn cael ei bostio ar gynnig a neilltuwyd i''r defnyddiwr'
+ internal_comment_is_posted_on_idea_in_project_or_folder_user_manages: 'Mae sylwadau mewnol yn cael eu postio ar fewnbwn yn rheolwyr prosiect neu ffolderi'
+ internal_comment_is_posted_on_idea_user_has_commented_internally_on: 'Sylw mewnol yn cael ei bostio ar fewnbwn defnyddiwr y sylwadau mewnol arno'
+ internal_comment_is_posted_on_idea_user_moderates: 'Sylw mewnol yn cael ei bostio ar fewnbwn defnyddiwr cymedroli'
+ internal_comment_is_posted_on_initiative_user_has_commented_internally_on: 'Mae sylwadau mewnol yn cael eu postio ar y cynnig y gwnaeth y defnyddiwr sylwadau mewnol arno'
+ internal_comment_is_posted_on_unassigned_initiative: 'Sylw mewnol yn cael ei bostio ar gynnig heb ei neilltuo'
+ internal_comment_is_posted_on_unassigned_unmoderated_idea: 'Mae sylwadau mewnol yn cael eu postio ar fewnbwn heb ei aseinio mewn prosiect heb ei reoli'
+ user_accepts_invitation_to_cosponsor_a_proposal: 'Defnyddiwr yn derbyn gwahoddiad i gyd-noddi cynnig'
+ user_is_invited_to_cosponsor_a_proposal: 'Gwahoddir defnyddiwr i gyd-noddi cynnig'
+ user_is_mentioned_in_internal_comment: 'Sonnir am y defnyddiwr yn y sylw mewnol'
+ new_input_is_published: 'Mewnbwn newydd yn cael ei gyhoeddi'
+ new_proposal_is_posted: 'Cynnig newydd yn cael ei bostio'
+ project_phase_changes: 'Newidiadau cyfnod y prosiect'
+ project_published: 'Cyhoeddi''r prosiect'
+ proposal_gets_reported_as_spam: 'Mae''r cynnig yn cael ei adrodd fel sbam'
+ proposal_is_assigned_to_admin: 'Cynnig yn cael ei neilltuo i weinyddol'
+ proposal_is_updated: 'Cynnig yn derbyn adborth swyddogol'
+ proposal_is_upvoted_above_threshold: 'Mae''r cynnig yn uwch na''r trothwy'
+ proposal_status_changes: 'Newidiadau i statws cynigion'
+ user_comments: 'Sylwadau defnyddwyr'
+ user_comments_on_input: 'Sylwadau defnyddwyr ar fewnbwn'
+ user_comments_on_proposal: 'Sylwadau defnyddwyr ar y cynnig'
+ user_is_given_admin_rights: 'Rhoddir hawliau gweinyddol i''r defnyddiwr'
+ user_is_given_folder_moderator_rights: 'Rhoddir hawliau cymedrolwr ffolder i''r defnyddiwr'
+ user_is_given_project_moderator_rights: 'Rhoddir hawliau cymedrolwr prosiect i''r defnyddiwr'
+ user_is_mentioned: 'Sonnir am y defnyddiwr'
+ input_is_published: 'Mewnbwn yn cael ei gyhoeddi'
+ proposal_is_published: 'Cynnig yn cael ei gyhoeddi'
+ user_registers_for_the_first_time: 'Defnyddwyr yn cofrestru am y tro cyntaf'
+ user_replies_to_comment: 'Ymateb defnyddiwr i sylw'
+ user_replies_to_internal_comment: 'Ymateb defnyddiwr i sylwadau mewnol'
+ voting_2_days_before_phase_closes: '2 ddiwrnod cyn i''r cyfnod pleidleisio gau'
+ voting_1_day_after_last_votes: '1 diwrnod ar ôl i''r defnyddiwr bleidleisio ddiwethaf'
+ voting_phase_ended: 'Daeth y cyfnod pleidleisio i ben'
+ voting_basket_submitted: 'Cyflwynir pleidleisiau'
+ 7_days_after_invite_is_sent: '7 diwrnod ar ôl anfon gwahoddiad'
+ 7_days_before_the_project_changes_phase: '7 diwrnod cyn i''r prosiect newid cyfnod'
+ registration_to_event: 'Cofrestru i ddigwyddiad'
+ survey_1_day_after_draft_saved: '1 diwrnod ar ôl i''r defnyddiwr arbed yr arolwg ar ffurf drafft ddiwethaf'
diff --git a/back/lib/participation_method/native_survey.rb b/back/lib/participation_method/native_survey.rb
index 7dea4fd6d13f..17fc21ccf58c 100644
--- a/back/lib/participation_method/native_survey.rb
+++ b/back/lib/participation_method/native_survey.rb
@@ -32,7 +32,8 @@ def default_fields(custom_form)
id: SecureRandom.uuid,
key: 'page1',
resource: custom_form,
- input_type: 'page'
+ input_type: 'page',
+ page_layout: 'default'
),
CustomField.new(
id: SecureRandom.uuid,
diff --git a/back/spec/factories/custom_fields.rb b/back/spec/factories/custom_fields.rb
index e9f3e7f5c98e..def2e3dab968 100644
--- a/back/spec/factories/custom_fields.rb
+++ b/back/spec/factories/custom_fields.rb
@@ -128,6 +128,7 @@
}
end
input_type { 'page' }
+ page_layout { 'default' }
end
factory :custom_field_section do
diff --git a/back/spec/models/custom_field_spec.rb b/back/spec/models/custom_field_spec.rb
index 9322841ceb77..c635d3fe7843 100644
--- a/back/spec/models/custom_field_spec.rb
+++ b/back/spec/models/custom_field_spec.rb
@@ -187,6 +187,44 @@ def visit_file_upload(_field)
end
end
+ describe 'page_layout validation' do
+ context 'for page custom_field' do
+ let(:page_custom_field) { build(:custom_field_page) }
+
+ it 'is valid when the page_layout is a valid value' do
+ page_custom_field.page_layout = 'default'
+ expect(page_custom_field.valid?).to be true
+
+ page_custom_field.page_layout = 'map'
+ expect(page_custom_field.valid?).to be true
+ end
+
+ it 'is invalid when the page_layout is an invalid value' do
+ page_custom_field.page_layout = 'invalid_value'
+ expect(page_custom_field.valid?).to be false
+ end
+
+ it 'is invalid when the page_layout is nil' do
+ page_custom_field.page_layout = nil
+ expect(page_custom_field.valid?).to be false
+ end
+ end
+
+ context 'for non-page custom_field' do
+ let(:custom_field) { build(:custom_field) }
+
+ it 'is valid when the page_layout is nil' do
+ custom_field.page_layout = nil
+ expect(custom_field.valid?).to be true
+ end
+
+ it 'is invalid when the page_layout is not nil' do
+ custom_field.page_layout = 'default'
+ expect(custom_field.valid?).to be false
+ end
+ end
+ end
+
describe 'title_multiloc validation' do
let(:form) { create(:custom_form) }
@@ -216,6 +254,7 @@ def visit_file_upload(_field)
page_field = described_class.new(
resource: form,
input_type: 'page',
+ page_layout: 'default',
key: 'field_key',
title_multiloc: { 'en' => '' }
)
@@ -415,6 +454,7 @@ def visit_file_upload(_field)
it 'sets public by default if field is a page' do
field.input_type = 'page'
+ field.page_layout = 'default'
field.validate!
expect(field.answer_visible_to).to eq 'public'
end
diff --git a/back/spec/serializers/web_api/v1/custom_field_serializer_spec.rb b/back/spec/serializers/web_api/v1/custom_field_serializer_spec.rb
index 9289d755a009..dffc46982eec 100644
--- a/back/spec/serializers/web_api/v1/custom_field_serializer_spec.rb
+++ b/back/spec/serializers/web_api/v1/custom_field_serializer_spec.rb
@@ -112,6 +112,7 @@
input_type: 'page',
key: 'page_1',
ordering: 0,
+ page_layout: 'default',
required: false,
title_multiloc: { 'en' => 'Cycling survey' },
updated_at: an_instance_of(ActiveSupport::TimeWithZone),
diff --git a/back/spec/services/input_ui_schema_generator_service_spec.rb b/back/spec/services/input_ui_schema_generator_service_spec.rb
index 58c33491d0db..ef7adaf2f3a8 100644
--- a/back/spec/services/input_ui_schema_generator_service_spec.rb
+++ b/back/spec/services/input_ui_schema_generator_service_spec.rb
@@ -780,7 +780,8 @@
resource: custom_form,
key: 'about_your_cycling_habits',
title_multiloc: { 'en' => 'About your cycling habits' },
- description_multiloc: { 'en' => 'Please indicate how you use a bike .' }
+ description_multiloc: { 'en' => 'Please indicate how you use a bike .' },
+ page_layout: 'map'
)
end
let!(:field_in_page2) do
@@ -816,7 +817,9 @@
input_type: page1.input_type,
id: page1.id,
title: 'About you',
- description: 'Please fill in some personal details .'
+ description: 'Please fill in some personal details .',
+ page_layout: 'default',
+ map_config_id: nil
},
elements: [{
type: 'Control',
@@ -837,7 +840,9 @@
input_type: page2.input_type,
id: page2.id,
title: 'About your cycling habits',
- description: 'Please indicate how you use a bike .'
+ description: 'Please indicate how you use a bike .',
+ page_layout: 'map',
+ map_config_id: nil
},
elements: [{
type: 'Control',
@@ -858,7 +863,9 @@
input_type: page3.input_type,
id: page3.id,
title: 'This is the end of the survey',
- description: 'Thank you for participating 🚀'
+ description: 'Thank you for participating 🚀',
+ page_layout: 'default',
+ map_config_id: nil
},
elements: []
},
@@ -980,7 +987,9 @@
input_type: page1.input_type,
id: page1.id,
title: '',
- description: ''
+ description: '',
+ page_layout: 'default',
+ map_config_id: nil
},
elements: [{
type: 'Control',
@@ -1002,7 +1011,9 @@
input_type: page2.input_type,
id: page2.id,
title: '',
- description: ''
+ description: '',
+ page_layout: 'default',
+ map_config_id: nil
},
elements: [{
type: 'Control',
@@ -1046,7 +1057,9 @@
input_type: page3.input_type,
id: page3.id,
title: '',
- description: ''
+ description: '',
+ page_layout: 'default',
+ map_config_id: nil
},
elements: [],
ruleArray: [
@@ -1409,14 +1422,15 @@
let(:ui_schema) { generator.generate_for IdeaCustomFieldsService.new(custom_form).enabled_fields }
let(:field) do
create(
- :custom_field,
- input_type: 'page',
+ :custom_field_page,
key: field_key,
title_multiloc: { 'en' => 'Page field title' },
description_multiloc: { 'en' => 'Page field description' }
)
end
+ let!(:map_config) { create(:map_config, mappable: field) }
+
it 'returns the schema for the given field, with id, and without elements' do
expect(generator.visit_page(field)).to eq({
type: 'Page',
@@ -1424,7 +1438,9 @@
input_type: field.input_type,
id: field.id,
title: 'Page field title',
- description: 'Page field description'
+ description: 'Page field description',
+ page_layout: 'default',
+ map_config_id: map_config.id
},
elements: []
})
diff --git a/back/spec/services/json_forms_service_spec.rb b/back/spec/services/json_forms_service_spec.rb
index 5d5e06b5a4a4..198670eaf940 100644
--- a/back/spec/services/json_forms_service_spec.rb
+++ b/back/spec/services/json_forms_service_spec.rb
@@ -386,7 +386,7 @@
description_multiloc = {
'en' => ' '
}
- field = create(:custom_field, :for_custom_form, input_type: 'page', description_multiloc: description_multiloc)
+ field = create(:custom_field_page, :for_custom_form, description_multiloc: description_multiloc)
allow_any_instance_of(TextImageService).to(
receive(:render_data_images_multiloc).with(field.description_multiloc, field: :description_multiloc, imageable: field).and_return({ 'en' => 'Description with text images' })
)
diff --git a/back/spec/services/project_copy_service_spec.rb b/back/spec/services/project_copy_service_spec.rb
index 3f24a3df0d22..2631684fbde7 100644
--- a/back/spec/services/project_copy_service_spec.rb
+++ b/back/spec/services/project_copy_service_spec.rb
@@ -148,13 +148,15 @@
it 'successfully copies map_configs associated with phase-level form custom_fields' do
open_ended_project = create(:single_phase_native_survey_project, title_multiloc: { en: 'open ended' })
form1 = create(:custom_form, participation_context: open_ended_project.phases.first)
- field1 = create(:custom_field_point, :for_custom_form, resource: form1)
- map_config = create(:map_config, zoom_level: 17, mappable: field1)
+ page_field = create(:custom_field_page, :for_custom_form, resource: form1)
+ map_config1 = create(:map_config, zoom_level: 15, mappable: page_field)
+ point_field = create(:custom_field_point, :for_custom_form, resource: form1)
+ map_config2 = create(:map_config, zoom_level: 17, mappable: point_field)
template = service.export open_ended_project
- expect(template['models']['custom_field'].size).to eq 1
- expect(template['models']['custom_maps/map_config'].size).to eq 1
+ expect(template['models']['custom_field'].size).to eq 2
+ expect(template['models']['custom_maps/map_config'].size).to eq 2
tenant = create(:tenant)
tenant.switch do
@@ -162,8 +164,9 @@
service.import template
- expect(CustomMaps::MapConfig.count).to eq 1
- expect(CustomMaps::MapConfig.first.zoom_level).to eq map_config.zoom_level
+ expect(CustomMaps::MapConfig.count).to eq 2
+ expect(CustomMaps::MapConfig.all.pluck(:zoom_level))
+ .to match_array [map_config1.zoom_level, map_config2.zoom_level]
end
end
diff --git a/back/spec/services/side_fx_custom_field_option_service_spec.rb b/back/spec/services/side_fx_custom_field_option_service_spec.rb
index 27d6f3b29c59..d1b2bdc59daf 100644
--- a/back/spec/services/side_fx_custom_field_option_service_spec.rb
+++ b/back/spec/services/side_fx_custom_field_option_service_spec.rb
@@ -22,8 +22,8 @@
describe 'after_destroy' do
let(:custom_field1) { create(:custom_field, :for_custom_form, input_type: 'select') }
- let(:custom_field2) { create(:custom_field, :for_custom_form, input_type: 'page') }
- let(:custom_field3) { create(:custom_field, :for_custom_form, input_type: 'page') }
+ let(:custom_field2) { create(:custom_field, :for_custom_form, input_type: 'page', page_layout: 'default') }
+ let(:custom_field3) { create(:custom_field, :for_custom_form, input_type: 'page', page_layout: 'default') }
let(:option1) { create(:custom_field_option, custom_field: custom_field1, key: 'option_1') }
let(:option2) { create(:custom_field_option, custom_field: custom_field1, key: 'option_2') }
let(:logic) do
diff --git a/back/spec/services/xlsx_export/value_visitor_spec.rb b/back/spec/services/xlsx_export/value_visitor_spec.rb
index da6aad2084c2..70f859431a03 100644
--- a/back/spec/services/xlsx_export/value_visitor_spec.rb
+++ b/back/spec/services/xlsx_export/value_visitor_spec.rb
@@ -499,7 +499,7 @@
end
describe '#visit_page' do
- let(:input_type) { 'page' }
+ let(:field) { create(:custom_field_page) }
let(:model) { instance_double Idea } # The model is irrelevant for this test.
it 'returns the empty string, because the field does not capture data' do
diff --git a/front/app/api/app_configuration/types.ts b/front/app/api/app_configuration/types.ts
index a16d222b7f9e..2f130b9bb0a4 100644
--- a/front/app/api/app_configuration/types.ts
+++ b/front/app/api/app_configuration/types.ts
@@ -175,6 +175,7 @@ export interface IAppConfigurationSettings {
disable_disliking?: AppConfigurationFeature;
blocking_profanity?: AppConfigurationFeature;
anonymous_participation?: AppConfigurationFeature;
+ form_mapping?: AppConfigurationFeature;
custom_idea_statuses?: AppConfigurationFeature;
intercom?: AppConfigurationFeature;
satismeter?: AppConfigurationFeature & {
diff --git a/front/app/api/custom_fields/types.ts b/front/app/api/custom_fields/types.ts
index f6fe80e97226..be57b5d6b8f6 100644
--- a/front/app/api/custom_fields/types.ts
+++ b/front/app/api/custom_fields/types.ts
@@ -57,6 +57,7 @@ export interface IAttributes {
description_multiloc: Multiloc;
input_type: ICustomFieldInputType;
map_config_id?: string | null;
+ page_layout?: 'default' | 'map' | null;
required: boolean;
isRequiredEditable?: boolean;
isEnabledEditable?: boolean;
diff --git a/front/app/components/Form/Components/Layouts/CLSurveyPageLayout.tsx b/front/app/components/Form/Components/Layouts/CLSurveyPageLayout.tsx
index c0b1e800807e..0b4718b09c59 100644
--- a/front/app/components/Form/Components/Layouts/CLSurveyPageLayout.tsx
+++ b/front/app/components/Form/Components/Layouts/CLSurveyPageLayout.tsx
@@ -1,19 +1,40 @@
-import React, { memo, useState, useEffect, useContext, useRef } from 'react';
+import React, {
+ memo,
+ useState,
+ useEffect,
+ useContext,
+ useRef,
+ useMemo,
+} from 'react';
import {
Box,
colors,
+ Spinner,
Title,
useBreakpoint,
} from '@citizenlab/cl2-component-library';
import { LayoutProps, RankedTester, rankWith } from '@jsonforms/core';
import {
- JsonFormsDispatch,
withJsonFormsLayoutProps,
useJsonForms,
+ JsonFormsDispatch,
} from '@jsonforms/react';
+import { useParams, useSearchParams } from 'react-router-dom';
import { useTheme } from 'styled-components';
+import { IMapConfig } from 'api/map_config/types';
+import useMapConfigById from 'api/map_config/useMapConfigById';
+import useProjectMapConfig from 'api/map_config/useProjectMapConfig';
+import usePhase from 'api/phases/usePhase';
+import usePhases from 'api/phases/usePhases';
+import { getCurrentPhase } from 'api/phases/utils';
+import useProjectBySlug from 'api/projects/useProjectBySlug';
+
+import useLocalize from 'hooks/useLocalize';
+
+import EsriMap from 'components/EsriMap';
+import { parseLayers } from 'components/EsriMap/utils';
import {
getSanitizedFormData,
getPageSchema,
@@ -26,6 +47,10 @@ import {
import { FormContext } from 'components/Form/contexts';
import { customAjv } from 'components/Form/utils';
import QuillEditedContent from 'components/UI/QuillEditedContent';
+import Warning from 'components/UI/Warning';
+
+import { useIntl } from 'utils/cl-intl';
+import eventEmitter from 'utils/eventEmitter';
import {
extractElementsByOtherOptionLogic,
@@ -33,6 +58,8 @@ import {
isVisible,
} from '../Controls/visibilityUtils';
+import { SURVEY_PAGE_CHANGE_EVENT } from './events';
+import messages from './messages';
import PageControlButtons from './PageControlButtons';
// Handling survey pages in here. The more things that we have added to it,
@@ -52,6 +79,12 @@ const CLSurveyPageLayout = memo(
const { onSubmit, setShowAllErrors, setFormData } = useContext(FormContext);
const [currentStep, setCurrentStep] = useState(0);
const [isLoading, setIsLoading] = useState(false);
+ const isMobileOrSmaller = useBreakpoint('phone');
+ const [searchParams] = useSearchParams();
+ const { formatMessage } = useIntl();
+ const formState = useJsonForms();
+ const localize = useLocalize();
+ const theme = useTheme();
// We can cast types because the tester made sure we only get correct values
const pageTypeElements = (uischema as PageCategorization)
@@ -59,17 +92,50 @@ const CLSurveyPageLayout = memo(
const [uiPages, setUiPages] = useState(pageTypeElements);
const [userPagePath] = useState([]);
const [scrollToError, setScrollToError] = useState(false);
- const theme = useTheme();
- const formState = useJsonForms();
- const isSmallerThanPhone = useBreakpoint('phone');
+ const [percentageAnswered, setPercentageAnswered] = useState(1);
const showSubmit = currentStep === uiPages.length - 1;
const dataCyValue = showSubmit ? 'e2e-submit-form' : 'e2e-next-page';
const hasPreviousPage = currentStep !== 0;
+
+ const draggableDivRef = useRef(null);
+ const dragDividerRef = useRef(null);
const pagesRef = useRef(null);
- const [percentageAnswered, setPercentageAnswered] = useState(1);
- const hasAnonymousWarning = document.getElementById(
- 'anonymous-survey-warning'
+
+ // Get project and relevant phase data
+ const { slug } = useParams() as {
+ slug: string;
+ };
+ const { data: project } = useProjectBySlug(slug);
+ const { data: phases } = usePhases(project?.data.id);
+ const phaseIdFromSearchParams = searchParams.get('phase_id');
+ const phaseId =
+ phaseIdFromSearchParams || getCurrentPhase(phases?.data)?.id;
+ const { data: phase } = usePhase(phaseId);
+ const allowAnonymousPosting =
+ phase?.data?.attributes.allow_anonymous_participation;
+
+ // Map-related variables
+ const { data: projectMapConfig } = useProjectMapConfig(project?.data.id);
+ const isMapPage = uiPages[currentStep].options.page_layout === 'map';
+ const mapConfigId =
+ uiPages[currentStep].options.map_config_id || projectMapConfig?.data?.id;
+ const { data: fetchedMapConfig, isFetching: isFetchingMapConfig } =
+ useMapConfigById(mapConfigId);
+ const [mapConfig, setMapConfig] = useState(
+ null
);
+ const mapLayers = useMemo(() => {
+ return parseLayers(mapConfig, localize);
+ }, [localize, mapConfig]);
+
+ useEffect(() => {
+ setMapConfig(mapConfigId ? fetchedMapConfig : null);
+ }, [fetchedMapConfig, mapConfigId]);
+
+ // Emit event when page changes and map is fetched
+ useEffect(() => {
+ eventEmitter.emit(SURVEY_PAGE_CHANGE_EVENT);
+ }, [currentStep, isFetchingMapConfig]);
useEffect(() => {
// We can cast types because the tester made sure we only get correct values
@@ -199,79 +265,165 @@ const CLSurveyPageLayout = memo(
scrollToTop();
};
+ const onDragDivider = (event) => {
+ event.preventDefault();
+ // Change the height of the map container to match the drag event
+ if (draggableDivRef?.current) {
+ const clientY = event?.changedTouches?.[0]?.clientY;
+ // Don't allow the div to be dragged outside bounds of survey page
+ if (clientY > 0 && clientY < document.body.clientHeight - 180) {
+ draggableDivRef.current.style.height = `${clientY}px`;
+ }
+ }
+ };
+
+ dragDividerRef?.current?.addEventListener('touchmove', onDragDivider);
+
+ if (isFetchingMapConfig) {
+ return (
+
+
+
+
+
+ );
+ }
+
return (
<>
-
-
- {uiPages.map((page, index) => {
- const pageElements = extractElementsByOtherOptionLogic(
- page,
- data
- );
- return (
- currentStep === index && (
-
-
- {page.options.title && (
-
- {page.options.title}
-
- )}
- {page.options.description && (
-
-
-
-
+
+ {isMapPage && (
+
+
+
+ )}
+
+
+ {isMapPage && isMobileOrSmaller && (
+
+
+
+ )}
+
+
+ {uiPages.map((page, index) => {
+ const pageElements = extractElementsByOtherOptionLogic(
+ page,
+ data
+ );
+ return (
+ currentStep === index && (
+
+
+ {allowAnonymousPosting && (
+
+
+ {formatMessage(messages.anonymousSurveyMessage)}
+
+
+ )}
+ {page.options.title && (
+
+ {page.options.title}
+
+ )}
+ {page.options.description && (
+
+
+
+
+
+ )}
+ {pageElements.map((elementUiSchema, index) => {
+ const hasOtherFieldBelow = hasOtherTextFieldBelow(
+ elementUiSchema,
+ data
+ );
+
+ return (
+
+
+
+ );
+ })}
- )}
- {pageElements.map((elementUiSchema, index) => {
- const hasOtherFieldBelow = hasOtherTextFieldBelow(
- elementUiSchema,
- data
- );
-
- return (
-
-
-
- );
- })}
-
-
- )
- );
- })}
+
+ )
+ );
+ })}
+
+
+
{/*
TODO:
We should move the footer (progress bar and navigation buttons) into IdeasNewSurveyForm/index.tsx
@@ -282,10 +434,10 @@ const CLSurveyPageLayout = memo(
progress update before entering a new page, rather than after leaving it.
*/}
diff --git a/front/app/components/Form/Components/Layouts/events.ts b/front/app/components/Form/Components/Layouts/events.ts
new file mode 100644
index 000000000000..4be4107d6fc2
--- /dev/null
+++ b/front/app/components/Form/Components/Layouts/events.ts
@@ -0,0 +1 @@
+export const SURVEY_PAGE_CHANGE_EVENT = 'surveyPageChangeEvent';
diff --git a/front/app/components/Form/Components/Layouts/messages.ts b/front/app/components/Form/Components/Layouts/messages.ts
new file mode 100644
index 000000000000..cc6ee24dc4cd
--- /dev/null
+++ b/front/app/components/Form/Components/Layouts/messages.ts
@@ -0,0 +1,8 @@
+import { defineMessages } from 'react-intl';
+
+export default defineMessages({
+ anonymousSurveyMessage: {
+ id: 'app.components.form.anonymousSurveyMessage2',
+ defaultMessage: 'All responses to this survey are anonymized.',
+ },
+});
diff --git a/front/app/components/Form/Components/Layouts/utils.ts b/front/app/components/Form/Components/Layouts/utils.ts
index 427075edd445..b936e9fd9013 100644
--- a/front/app/components/Form/Components/Layouts/utils.ts
+++ b/front/app/components/Form/Components/Layouts/utils.ts
@@ -23,6 +23,8 @@ export interface PageType extends Layout {
id?: string;
title?: string;
description?: string;
+ map_config_id?: string;
+ page_layout?: 'map' | 'default' | null;
};
label?: string;
scope?: string;
diff --git a/front/app/components/FormBuilder/components/FormBuilderSettings/PageLayoutSettings/images/default_page_layout.svg b/front/app/components/FormBuilder/components/FormBuilderSettings/PageLayoutSettings/images/default_page_layout.svg
new file mode 100644
index 000000000000..82e1c355096a
--- /dev/null
+++ b/front/app/components/FormBuilder/components/FormBuilderSettings/PageLayoutSettings/images/default_page_layout.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/front/app/components/FormBuilder/components/FormBuilderSettings/PageLayoutSettings/images/map_page_layout.svg b/front/app/components/FormBuilder/components/FormBuilderSettings/PageLayoutSettings/images/map_page_layout.svg
new file mode 100644
index 000000000000..cd15c5fed75a
--- /dev/null
+++ b/front/app/components/FormBuilder/components/FormBuilderSettings/PageLayoutSettings/images/map_page_layout.svg
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/front/app/components/FormBuilder/components/FormBuilderSettings/PageLayoutSettings/index.tsx b/front/app/components/FormBuilder/components/FormBuilderSettings/PageLayoutSettings/index.tsx
new file mode 100644
index 000000000000..43b553682c0a
--- /dev/null
+++ b/front/app/components/FormBuilder/components/FormBuilderSettings/PageLayoutSettings/index.tsx
@@ -0,0 +1,118 @@
+import React from 'react';
+
+import {
+ Box,
+ Image,
+ Label,
+ Radio,
+ Text,
+} from '@citizenlab/cl2-component-library';
+import { Controller, useFormContext } from 'react-hook-form';
+
+import { IFlatCustomFieldWithIndex } from 'api/custom_fields/types';
+
+import useFeatureFlag from 'hooks/useFeatureFlag';
+
+import RadioGroup from 'components/HookForm/RadioGroup';
+
+import { useIntl } from 'utils/cl-intl';
+
+import defaultPageSvg from './images/default_page_layout.svg';
+import mapPageSvg from './images/map_page_layout.svg';
+import messages from './messages';
+
+type Props = {
+ field: IFlatCustomFieldWithIndex;
+ pageLayoutName: string;
+};
+
+const PageLayoutSettings = ({ pageLayoutName }: Props) => {
+ const isPageLayoutSettingsEnabled = useFeatureFlag({ name: 'form_mapping' });
+ const { formatMessage } = useIntl();
+ const { control, setValue } = useFormContext();
+
+ if (!isPageLayoutSettingsEnabled) {
+ return null;
+ }
+
+ return (
+ <>
+ {
+ return (
+ <>
+
+ {formatMessage(messages.pageType)}
+
+
+
+
+
+
+
+ {formatMessage(messages.normalPage)}
+
+ }
+ onChange={() => {
+ setValue(pageLayoutName, 'default', {
+ shouldDirty: true,
+ });
+ }}
+ />
+
+
+
+
+
+
+
+
+ {formatMessage(messages.mapBasedPage)}
+
+
+ {formatMessage(messages.mapOptionDescription)}
+
+
+ }
+ onChange={() => {
+ setValue(pageLayoutName, 'map', {
+ shouldDirty: true,
+ });
+ }}
+ />
+
+
+
+
+ >
+ );
+ }}
+ />
+ >
+ );
+};
+
+export default PageLayoutSettings;
diff --git a/front/app/components/FormBuilder/components/FormBuilderSettings/PageLayoutSettings/messages.ts b/front/app/components/FormBuilder/components/FormBuilderSettings/PageLayoutSettings/messages.ts
new file mode 100644
index 000000000000..7596e73c7485
--- /dev/null
+++ b/front/app/components/FormBuilder/components/FormBuilderSettings/PageLayoutSettings/messages.ts
@@ -0,0 +1,21 @@
+import { defineMessages } from 'react-intl';
+
+export default defineMessages({
+ mapOptionDescription: {
+ id: 'app.components.formBuilder.formBuilderSettings.pageLayoutSettings.mapOptionDescription',
+ defaultMessage:
+ 'Embed map as context or ask location based questions to participants.',
+ },
+ mapBasedPage: {
+ id: 'app.components.formBuilder.formBuilderSettings.pageLayoutSettings.mapBasedPage',
+ defaultMessage: 'Map-based page',
+ },
+ normalPage: {
+ id: 'app.components.formBuilder.formBuilderSettings.pageLayoutSettings.normalPage',
+ defaultMessage: 'Normal page',
+ },
+ pageType: {
+ id: 'app.components.formBuilder.formBuilderSettings.pageLayoutSettings.pageType',
+ defaultMessage: 'Page type',
+ },
+});
diff --git a/front/app/components/FormBuilder/components/FormBuilderSettings/PointSettings/index.tsx b/front/app/components/FormBuilder/components/FormBuilderSettings/PointSettings/index.tsx
index 4be762ef70c8..5e4594055476 100644
--- a/front/app/components/FormBuilder/components/FormBuilderSettings/PointSettings/index.tsx
+++ b/front/app/components/FormBuilder/components/FormBuilderSettings/PointSettings/index.tsx
@@ -38,9 +38,10 @@ const StyledLabel = styled(Label)`
type Props = {
mapConfigIdName: string;
field: IFlatCustomFieldWithIndex;
+ pageLayoutName?: string;
};
-const PointSettings = ({ mapConfigIdName, field }: Props) => {
+const PointSettings = ({ mapConfigIdName, pageLayoutName, field }: Props) => {
const { projectId, phaseId } = useParams() as {
projectId: string;
phaseId?: string;
@@ -58,6 +59,11 @@ const PointSettings = ({ mapConfigIdName, field }: Props) => {
const { mutateAsync: duplicateMapConfig } = useDuplicateMapConfig();
const [mapView, setMapView] = useState(null);
+ // Determine whether to show the map configuration option
+ const showMapConfigurationOption = pageLayoutName
+ ? watch(pageLayoutName) === 'map'
+ : true;
+
// Default project map settings if not present
const { data: appConfig } = useAppConfiguration();
@@ -74,8 +80,12 @@ const PointSettings = ({ mapConfigIdName, field }: Props) => {
// Load map state from mapConfig
const mapLayers = useMemo(() => {
+ if (!showMapConfigurationOption) {
+ // Reset the map view if we're hiding the map
+ mapView?.destroy();
+ }
return parseLayers(mapConfig, localize);
- }, [localize, mapConfig]);
+ }, [localize, mapConfig, mapView, showMapConfigurationOption]);
const onConfigureMapClick = useCallback(() => {
if (!mapConfigId) {
@@ -159,6 +169,10 @@ const PointSettings = ({ mapConfigIdName, field }: Props) => {
setMapView(mapView);
}, []);
+ if (!showMapConfigurationOption) {
+ return null;
+ }
+
if ((isLoadingFieldConfig && mapConfigId) || isLoadingRawFields) {
return (
diff --git a/front/app/components/FormBuilder/edit/index.tsx b/front/app/components/FormBuilder/edit/index.tsx
index 605dbaa0574b..7ab4fd7e9c40 100644
--- a/front/app/components/FormBuilder/edit/index.tsx
+++ b/front/app/components/FormBuilder/edit/index.tsx
@@ -193,6 +193,9 @@ const FormEdit = ({
title_multiloc: field.title_multiloc || {},
key: field.key,
code: field.code,
+ ...(field.page_layout || field.input_type === 'page'
+ ? { page_layout: field.page_layout || 'default' }
+ : {}),
...(field.map_config_id && {
map_config_id: field.map_config_id,
}),
diff --git a/front/app/components/FormBuilder/utils.tsx b/front/app/components/FormBuilder/utils.tsx
index 32c41d6da369..d93c7c683f77 100644
--- a/front/app/components/FormBuilder/utils.tsx
+++ b/front/app/components/FormBuilder/utils.tsx
@@ -18,6 +18,7 @@ import ConfigSelectWithLocaleSwitcher from './components/FormBuilderSettings/Con
import FieldGroupSettings from './components/FormBuilderSettings/FieldGroupSettings';
import LinearScaleSettings from './components/FormBuilderSettings/LinearScaleSettings';
import MultiselectSettings from './components/FormBuilderSettings/MultiselectSettings';
+import PageLayoutSettings from './components/FormBuilderSettings/PageLayoutSettings';
import PointSettings from './components/FormBuilderSettings/PointSettings';
import SelectSettings from './components/FormBuilderSettings/SelectSettings';
import messages from './components/messages';
@@ -135,6 +136,20 @@ export function getAdditionalSettings(
>
);
case 'page':
+ return (
+ <>
+
+
+
+ >
+ );
case 'section':
return ;
case 'linear_scale':
diff --git a/front/app/components/HookForm/RadioGroup/index.tsx b/front/app/components/HookForm/RadioGroup/index.tsx
index a0ae70728554..18ae97974264 100644
--- a/front/app/components/HookForm/RadioGroup/index.tsx
+++ b/front/app/components/HookForm/RadioGroup/index.tsx
@@ -1,6 +1,6 @@
import React from 'react';
-import { Box } from '@citizenlab/cl2-component-library';
+import { Box, BoxProps } from '@citizenlab/cl2-component-library';
import { get } from 'lodash-es';
import { useFormContext } from 'react-hook-form';
import { CLError, RHFErrors } from 'typings';
@@ -12,7 +12,7 @@ interface Props {
children?: React.ReactNode;
}
-const RadioGroup = ({ name, children }: Props) => {
+const RadioGroup = ({ name, children, ...props }: Props & BoxProps) => {
const {
formState: { errors: formContextErrors },
} = useFormContext();
@@ -24,7 +24,7 @@ const RadioGroup = ({ name, children }: Props) => {
const apiError = errors?.error && ([errors] as CLError[]);
return (
-
+
{children}
{validationError && (
{
campaign?.data.attributes.context_id
);
- const { data: sender } = useUserById(
- campaign?.data.relationships.author.data.id
- );
+ const authorId = campaign?.data.relationships.author.data?.id;
+ const { data: sender } = useUserById(authorId);
const {
mutate: sendCampaign,
diff --git a/front/app/containers/Admin/settings/routes.tsx b/front/app/containers/Admin/settings/routes.tsx
index 3d4061a1d44e..30148c532691 100644
--- a/front/app/containers/Admin/settings/routes.tsx
+++ b/front/app/containers/Admin/settings/routes.tsx
@@ -31,6 +31,15 @@ const AdminTopicsIndexComponent = lazy(() => import('./topics/all'));
const AdminTopicsNewComponent = lazy(() => import('./topics/New'));
const AdminTopicsEditComponent = lazy(() => import('./topics/Edit'));
+// statuses
+const StatusesComponent = React.lazy(() => import('./statuses/containers/'));
+const NewStatusComponent = React.lazy(
+ () => import('./statuses/containers/new')
+);
+const StatusShowComponent = React.lazy(
+ () => import('./statuses/containers/edit')
+);
+
export enum settingsRoutes {
settings = 'settings',
settingsDefault = '',
@@ -43,6 +52,8 @@ export enum settingsRoutes {
topics = 'topics',
edit = 'edit',
topicEdit = ':topicId/edit',
+ statuses = 'statuses',
+ statusId = ':statusId',
}
export type settingRouteTypes =
@@ -56,6 +67,9 @@ export type settingRouteTypes =
| AdminRoute<`${settingsRoutes.settings}/${settingsRoutes.topics}`>
| AdminRoute<`${settingsRoutes.settings}/${settingsRoutes.topics}/${settingsRoutes.new}`>
| AdminRoute<`${settingsRoutes.settings}/${settingsRoutes.topics}/${string}/${settingsRoutes.edit}`>
+ | AdminRoute<`${settingsRoutes.settings}/${settingsRoutes.statuses}`>
+ | AdminRoute<`${settingsRoutes.settings}/${settingsRoutes.statuses}/${settingsRoutes.new}`>
+ | AdminRoute<`${settingsRoutes.settings}/${settingsRoutes.statuses}/${string}`>
| registrationRouteTypes;
export default () => ({
@@ -153,6 +167,37 @@ export default () => ({
},
],
},
+ {
+ path: settingsRoutes.statuses,
+
+ children: [
+ {
+ index: true,
+ element: (
+
+
+
+ ),
+ },
+ {
+ path: settingsRoutes.new,
+ element: (
+
+
+
+ ),
+ },
+ {
+ path: settingsRoutes.statusId,
+ element: (
+
+
+
+ ),
+ },
+ ],
+ },
+
...moduleConfiguration.routes['admin.settings'],
],
});
diff --git a/front/app/modules/commercial/custom_idea_statuses/admin/components/DeleteStatusButton.tsx b/front/app/containers/Admin/settings/statuses/components/DeleteStatusButton.tsx
similarity index 100%
rename from front/app/modules/commercial/custom_idea_statuses/admin/components/DeleteStatusButton.tsx
rename to front/app/containers/Admin/settings/statuses/components/DeleteStatusButton.tsx
diff --git a/front/app/modules/commercial/custom_idea_statuses/admin/components/EditStatusButton.tsx b/front/app/containers/Admin/settings/statuses/components/EditStatusButton.tsx
similarity index 100%
rename from front/app/modules/commercial/custom_idea_statuses/admin/components/EditStatusButton.tsx
rename to front/app/containers/Admin/settings/statuses/components/EditStatusButton.tsx
diff --git a/front/app/modules/commercial/custom_idea_statuses/admin/components/IdeaStatusForm.tsx b/front/app/containers/Admin/settings/statuses/components/IdeaStatusForm.tsx
similarity index 100%
rename from front/app/modules/commercial/custom_idea_statuses/admin/components/IdeaStatusForm.tsx
rename to front/app/containers/Admin/settings/statuses/components/IdeaStatusForm.tsx
diff --git a/front/app/modules/commercial/custom_idea_statuses/admin/components/messages.ts b/front/app/containers/Admin/settings/statuses/components/messages.ts
similarity index 100%
rename from front/app/modules/commercial/custom_idea_statuses/admin/components/messages.ts
rename to front/app/containers/Admin/settings/statuses/components/messages.ts
diff --git a/front/app/modules/commercial/custom_idea_statuses/admin/containers/edit.tsx b/front/app/containers/Admin/settings/statuses/containers/edit.tsx
similarity index 97%
rename from front/app/modules/commercial/custom_idea_statuses/admin/containers/edit.tsx
rename to front/app/containers/Admin/settings/statuses/containers/edit.tsx
index 0fa3874b7743..1ae9652e08a4 100644
--- a/front/app/modules/commercial/custom_idea_statuses/admin/containers/edit.tsx
+++ b/front/app/containers/Admin/settings/statuses/containers/edit.tsx
@@ -28,7 +28,7 @@ const StyledSectionTitle = styled(SectionTitle)`
`;
const Edit = () => {
- const { id: statusId } = useParams() as { id: string };
+ const { statusId } = useParams() as { statusId: string };
const { data: ideaStatus } = useIdeaStatus(statusId);
const { mutate: updateIdeaStatus } = useUpdateIdeaStatus();
const tenantLocales = useAppConfigurationLocales();
diff --git a/front/app/modules/commercial/custom_idea_statuses/admin/containers/index.tsx b/front/app/containers/Admin/settings/statuses/containers/index.tsx
similarity index 100%
rename from front/app/modules/commercial/custom_idea_statuses/admin/containers/index.tsx
rename to front/app/containers/Admin/settings/statuses/containers/index.tsx
diff --git a/front/app/modules/commercial/custom_idea_statuses/admin/containers/messages.ts b/front/app/containers/Admin/settings/statuses/containers/messages.ts
similarity index 100%
rename from front/app/modules/commercial/custom_idea_statuses/admin/containers/messages.ts
rename to front/app/containers/Admin/settings/statuses/containers/messages.ts
diff --git a/front/app/modules/commercial/custom_idea_statuses/admin/containers/new.tsx b/front/app/containers/Admin/settings/statuses/containers/new.tsx
similarity index 100%
rename from front/app/modules/commercial/custom_idea_statuses/admin/containers/new.tsx
rename to front/app/containers/Admin/settings/statuses/containers/new.tsx
diff --git a/front/app/containers/IdeasNewSurveyPage/IdeasNewSurveyForm/index.tsx b/front/app/containers/IdeasNewSurveyPage/IdeasNewSurveyForm/index.tsx
index 3f1962e9a5d7..e692c6c65632 100644
--- a/front/app/containers/IdeasNewSurveyPage/IdeasNewSurveyForm/index.tsx
+++ b/front/app/containers/IdeasNewSurveyPage/IdeasNewSurveyForm/index.tsx
@@ -28,19 +28,18 @@ import useLocalize from 'hooks/useLocalize';
import ideaFormMessages from 'containers/IdeasNewPage/messages';
import Form from 'components/Form';
+import { SURVEY_PAGE_CHANGE_EVENT } from 'components/Form/Components/Layouts/events';
import { AjvErrorGetter, ApiErrorGetter } from 'components/Form/typings';
import FullPageSpinner from 'components/UI/FullPageSpinner';
-import Warning from 'components/UI/Warning';
-import { useIntl } from 'utils/cl-intl';
import { queryClient } from 'utils/cl-react-query/queryClient';
import { getMethodConfig } from 'utils/configs/participationMethodConfig';
+import eventEmitter from 'utils/eventEmitter';
import { getElementType, getFieldNameFromPath } from 'utils/JSONFormUtils';
import { canModerateProject } from 'utils/permissions/rules/projectPermissions';
import { getFormValues } from '../../IdeasEditPage/utils';
import IdeasNewSurveyMeta from '../IdeasNewSurveyMeta';
-import messages from '../messages';
import SurveyHeading from './SurveyHeading';
@@ -72,7 +71,6 @@ interface Props {
}
const IdeasNewSurveyForm = ({ project, phaseId }: Props) => {
- const { formatMessage } = useIntl();
const localize = useLocalize();
const isSmallerThanPhone = useBreakpoint('phone');
const { mutateAsync: addIdea } = useAddIdea();
@@ -89,6 +87,7 @@ const IdeasNewSurveyForm = ({ project, phaseId }: Props) => {
projectId: project.data.id,
phaseId,
});
+ const [usingMapView, setUsingMapView] = useState(false);
const { data: draftIdea, status: draftIdeaStatus } =
useDraftIdeaByPhaseId(phaseId);
@@ -155,6 +154,19 @@ const IdeasNewSurveyForm = ({ project, phaseId }: Props) => {
}
}, [draftIdeaStatus, draftIdea, schema, ideaId]);
+ // Listen for survey page change event
+ useEffect(() => {
+ const subscription = eventEmitter
+ .observeEvent(SURVEY_PAGE_CHANGE_EVENT)
+ .subscribe(() => {
+ setUsingMapView(!!document.getElementById('survey_page_map'));
+ });
+
+ return () => {
+ subscription.unsubscribe();
+ };
+ }, []);
+
if (isLoadingInputSchema || loadingDraftIdea) return ;
if (
// inputSchemaError should display an error page instead
@@ -278,7 +290,7 @@ const IdeasNewSurveyForm = ({ project, phaseId }: Props) => {
mx="auto"
position="relative"
top={isSmallerThanPhone ? '0' : '40px'}
- maxWidth="700px"
+ maxWidth={usingMapView ? '1100px' : '700px'}
>
{
>
- {allowAnonymousPosting && (
-
-
- {formatMessage(messages.anonymousSurveyMessage)}
-
-
- )}