mirror of
https://github.com/grassrootseconomics/farmstar-survey-ui.git
synced 2025-10-16 19:12:08 +02:00
init: nuxt3 vue forms
This commit is contained in:
commit
3aff25bd6a
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Nuxt dev/build outputs
|
||||||
|
.output
|
||||||
|
.data
|
||||||
|
.nuxt
|
||||||
|
.nitro
|
||||||
|
.cache
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Node dependencies
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.DS_Store
|
||||||
|
.fleet
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Local env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
75
README.md
Normal file
75
README.md
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# Nuxt 3 Minimal Starter
|
||||||
|
|
||||||
|
Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Make sure to install the dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn install
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development Server
|
||||||
|
|
||||||
|
Start the development server on `http://localhost:3000`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm run dev
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn dev
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production
|
||||||
|
|
||||||
|
Build the application for production:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm run build
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn build
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
|
||||||
|
Locally preview production build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run preview
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm run preview
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn preview
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run preview
|
||||||
|
```
|
||||||
|
|
||||||
|
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
22
app.vue
Normal file
22
app.vue
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<template>
|
||||||
|
<AppNavbar />
|
||||||
|
<div class="bg-gray-100">
|
||||||
|
<div class="max-w-screen-xl mx-auto">
|
||||||
|
<NuxtPage />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
useHead({
|
||||||
|
title: "FarmStar Survey",
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* You can keep or remove the body style depending on your preference */
|
||||||
|
body {
|
||||||
|
background-color: #f3f4f6; /* You can use the color code for light grey */
|
||||||
|
margin: 0; /* Remove default body margin */
|
||||||
|
}
|
||||||
|
</style>
|
3
assets/css/input.css
Normal file
3
assets/css/input.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
72
components/App/AppNavbar.vue
Normal file
72
components/App/AppNavbar.vue
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<template>
|
||||||
|
<nav class="border-gray-200 bg-gray-900">
|
||||||
|
<div
|
||||||
|
class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4"
|
||||||
|
>
|
||||||
|
<NuxtLink to="/" class="flex items-center space-x-3 rtl:space-x-reverse">
|
||||||
|
<span
|
||||||
|
class="self-center text-2xl font-semibold whitespace-nowrap text-white"
|
||||||
|
>Farmstar Survey</span
|
||||||
|
></NuxtLink
|
||||||
|
>
|
||||||
|
|
||||||
|
<button
|
||||||
|
@click="toggleMenu"
|
||||||
|
data-collapse-toggle="navbar-default"
|
||||||
|
type="button"
|
||||||
|
class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm rounded-lg md:hidden focus:outline-none focus:ring-2 text-gray-400 hover:bg-gray-700 focus:ring-gray-600"
|
||||||
|
aria-controls="navbar-default"
|
||||||
|
aria-expanded="false"
|
||||||
|
>
|
||||||
|
<span class="sr-only">Open main menu</span>
|
||||||
|
<svg
|
||||||
|
class="w-5 h-5"
|
||||||
|
aria-hidden="true"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 17 14"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M1 1h15M1 7h15M1 13h15"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
:class="{ hidden: !isMenuOpen, 'lg:flex': isMenuOpen }"
|
||||||
|
class="w-full md:block md:w-auto"
|
||||||
|
id="navbar-default"
|
||||||
|
>
|
||||||
|
<ul
|
||||||
|
class="font-medium flex flex-col p-4 md:p-0 mt-4 border rounded-lg md:flex-row md:space-x-8 rtl:space-x-reverse md:mt-0 md:border-0 bg-gray-900 border-gray-700"
|
||||||
|
>
|
||||||
|
<li>
|
||||||
|
<NuxtLink
|
||||||
|
to="/about"
|
||||||
|
class="block py-2 px-3 rounded md:border-0 md:p-0 text-white md:hover:text-blue-500 hover:bg-gray-700 hover:text-white md:hover:bg-transparent"
|
||||||
|
>About</NuxtLink
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<NuxtLink
|
||||||
|
to="/help"
|
||||||
|
class="block py-2 px-3 rounded md:border-0 md:p-0 text-white md:hover:text-blue-500 hover:bg-gray-700 hover:text-white md:hover:bg-transparent"
|
||||||
|
>Help</NuxtLink
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const isMenuOpen = ref(false);
|
||||||
|
|
||||||
|
const toggleMenu = () => {
|
||||||
|
isMenuOpen.value = !isMenuOpen.value;
|
||||||
|
};
|
||||||
|
</script>
|
15
components/Card.vue
Normal file
15
components/Card.vue
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="bg-white mx-2 p-4 rounded border border-gray-300 mb-4 md:min-w-[250px] md:w-full md:mx-0 lg:mx-4"
|
||||||
|
>
|
||||||
|
<h2 class="text-xl font-bold mb-2">{{ title }}</h2>
|
||||||
|
<p class="text-gray-600 mb-4">{{ subtitle }}</p>
|
||||||
|
<NuxtLink :to="link">
|
||||||
|
<button class="bg-blue-500 text-white px-4 py-2 rounded">Enter</button>
|
||||||
|
</NuxtLink>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps(["title", "subtitle", "link"]);
|
||||||
|
</script>
|
5
components/FormSheet.vue
Normal file
5
components/FormSheet.vue
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<template>
|
||||||
|
<div class="bg-white rounded border border-gray-300 p-3">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
28
components/Notice.vue
Normal file
28
components/Notice.vue
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
id="alert-additional-content-1"
|
||||||
|
class="p-4 mb-4 text-blue-800 border border-blue-300 rounded-lg bg-blue-50 dark:bg-gray-800 dark:text-blue-400 dark:border-blue-800"
|
||||||
|
role="alert"
|
||||||
|
>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 me-2"
|
||||||
|
aria-hidden="true"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span class="sr-only">Info</span>
|
||||||
|
<h3 class="text-lg font-medium">Info</h3>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2 text-sm">{{ subtitle }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps(["subtitle"]);
|
||||||
|
</script>
|
51
components/SuccessAlert.vue
Normal file
51
components/SuccessAlert.vue
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
id="alert-additional-content-3"
|
||||||
|
class="p-4 mb-4 text-green-800 border border-green-300 rounded-lg bg-green-50 dark:bg-gray-800 dark:text-green-400 dark:border-green-800"
|
||||||
|
role="alert"
|
||||||
|
>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 me-2"
|
||||||
|
aria-hidden="true"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span class="sr-only">Info</span>
|
||||||
|
<h3 class="text-lg font-medium">{{ title }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2 mb-4 text-sm">
|
||||||
|
{{ subtitle }}
|
||||||
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
<NuxtLink :to="link">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="text-white bg-green-800 hover:bg-green-900 focus:ring-4 focus:outline-none focus:ring-green-300 font-medium rounded-lg text-xs px-3 py-1.5 me-2 text-center inline-flex items-center dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="me-2 h-3 w-3"
|
||||||
|
aria-hidden="true"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 14"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M10 0C4.612 0 0 5.336 0 7c0 1.742 3.546 7 10 7 6.454 0 10-5.258 10-7 0-1.664-4.612-7-10-7Zm0 10a3 3 0 1 1 0-6 3 3 0 0 1 0 6Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{{ action }}
|
||||||
|
</button>
|
||||||
|
</NuxtLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps(["title", "subtitle", "link", "action"]);
|
||||||
|
</script>
|
5
nuxt.config.ts
Normal file
5
nuxt.config.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
|
export default defineNuxtConfig({
|
||||||
|
devtools: { enabled: false },
|
||||||
|
modules: [ '@nuxtjs/tailwindcss', '@vueform/nuxt'],
|
||||||
|
})
|
12736
package-lock.json
generated
Normal file
12736
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
package.json
Normal file
21
package.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "nuxt-app",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"build": "nuxt build",
|
||||||
|
"dev": "nuxt dev",
|
||||||
|
"generate": "nuxt generate",
|
||||||
|
"preview": "nuxt preview",
|
||||||
|
"postinstall": "nuxt prepare"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@nuxt/devtools": "latest",
|
||||||
|
"@nuxtjs/tailwindcss": "^6.10.0",
|
||||||
|
"@vueform/nuxt": "^1.4.0",
|
||||||
|
"flowbite": "^2.2.0",
|
||||||
|
"nuxt": "^3.8.2",
|
||||||
|
"vue": "^3.3.8",
|
||||||
|
"vue-router": "^4.2.5"
|
||||||
|
}
|
||||||
|
}
|
1
pages/about.vue
Normal file
1
pages/about.vue
Normal file
@ -0,0 +1 @@
|
|||||||
|
<template></template>
|
407
pages/farmer.vue
Normal file
407
pages/farmer.vue
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
<template>
|
||||||
|
<div class="lg:flex items-start justify-center mt-4">
|
||||||
|
<FormSheet class="mx-2 mb-4 lg:w-3/4">
|
||||||
|
<ClientOnly>
|
||||||
|
<Vueform
|
||||||
|
v-if="!formSubmitted"
|
||||||
|
ref="form$"
|
||||||
|
validate-on="step"
|
||||||
|
:form-data="(form$) => form$.requestData"
|
||||||
|
@response="handleResponse"
|
||||||
|
endpoint="registration"
|
||||||
|
>
|
||||||
|
<div class="text-xl mb-1 col-span-12">
|
||||||
|
<div class="border-b border-gray-300 pb-2">Farmer's Survey</div>
|
||||||
|
</div>
|
||||||
|
<div class="text mb-1 mt-1 col-span-12">
|
||||||
|
<div class="border-b border-gray-300 pb-2">Farm Details</div>
|
||||||
|
</div>
|
||||||
|
<GroupElement name="farm_details">
|
||||||
|
<SelectElement
|
||||||
|
name="county"
|
||||||
|
label="What county are you located in?"
|
||||||
|
:native="false"
|
||||||
|
:items="{
|
||||||
|
kirinyaga: 'Kirinyaga',
|
||||||
|
muranga: 'Muranga',
|
||||||
|
nakuru: 'Nakuru',
|
||||||
|
}"
|
||||||
|
rules="required"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
name="sub_county"
|
||||||
|
label="What sub-county are you located in?"
|
||||||
|
rules="required|max:50"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
name="farming_area_acres"
|
||||||
|
input-type="number"
|
||||||
|
label="How many acres of land are you currently farming?"
|
||||||
|
rules="required"
|
||||||
|
/>
|
||||||
|
<TagsElement
|
||||||
|
name="planned_crops"
|
||||||
|
label="Which crops do you plan to grow in the coming season?"
|
||||||
|
:items="{
|
||||||
|
rice: 'Rice',
|
||||||
|
coffee: 'Coffee',
|
||||||
|
tea: 'Tea',
|
||||||
|
sugarcane: 'Sugarcane',
|
||||||
|
miraa: 'Miraa',
|
||||||
|
avocados: 'Avocados',
|
||||||
|
maize: 'Maize',
|
||||||
|
potatoes: 'Potatoes',
|
||||||
|
sorghum: 'Sorghum',
|
||||||
|
other_fruits: 'Other fruits',
|
||||||
|
other_vegetables: 'Other vegetables',
|
||||||
|
other_grains: 'Other grains',
|
||||||
|
}"
|
||||||
|
rules="required"
|
||||||
|
description="Select all options that apply."
|
||||||
|
/>
|
||||||
|
</GroupElement>
|
||||||
|
<div class="text mt-4 col-span-12">
|
||||||
|
<div class="border-b border-gray-300 pb-2">
|
||||||
|
Past Harvest Details
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-12">
|
||||||
|
<Notice
|
||||||
|
subtitle="Select all the crops that you have planted in the last 3 years, the average harvest you have gotten (in kg/acre) and how much you have earned (in ksh/kg) on selling each crop."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ListElement
|
||||||
|
name="past_harvest_details"
|
||||||
|
label="Harvest details for the last 3 years"
|
||||||
|
:min="1"
|
||||||
|
>
|
||||||
|
<template #default="{ index }">
|
||||||
|
<p>Crop {{ index + 1 }}</p>
|
||||||
|
<ObjectElement :name="index">
|
||||||
|
<SelectElement
|
||||||
|
name="crop_type"
|
||||||
|
rules="required"
|
||||||
|
:search="true"
|
||||||
|
:items="{
|
||||||
|
rice: 'Rice',
|
||||||
|
coffee: 'Coffee',
|
||||||
|
tea: 'Tea',
|
||||||
|
sugarcane: 'Sugarcane',
|
||||||
|
miraa: 'Miraa',
|
||||||
|
avocados: 'Avocados',
|
||||||
|
maize: 'Maize',
|
||||||
|
potatoes: 'Potatoes',
|
||||||
|
sorghum: 'Sorghum',
|
||||||
|
other_fruits: 'Other fruits',
|
||||||
|
other_vegetables: 'Other vegetables',
|
||||||
|
other_grains: 'Other grains',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
name="average_harvest"
|
||||||
|
label="Average harvest"
|
||||||
|
description="Average yield/output in kg/acre."
|
||||||
|
rules="required|max:100"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
name="average_earning"
|
||||||
|
label="Average earning"
|
||||||
|
description="Average yield/output in ksh/kg."
|
||||||
|
rules="required|max:100"
|
||||||
|
/>
|
||||||
|
<div class="col-span-12">
|
||||||
|
<div class="border-t border-gray-300 mt-1"></div>
|
||||||
|
</div>
|
||||||
|
</ObjectElement>
|
||||||
|
</template>
|
||||||
|
</ListElement>
|
||||||
|
<div class="text mt-4 col-span-12">
|
||||||
|
<div class="border-b border-gray-300 pb-2">
|
||||||
|
Budget and Expenditure Details
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<TextElement
|
||||||
|
name="total_expenditure"
|
||||||
|
input-type="number"
|
||||||
|
label="On average, how much do you spend on seeds, fertilizers, and crop protection (herbicides, pesticides, etc.) for a year?"
|
||||||
|
description="Average in ksh."
|
||||||
|
rules="required"
|
||||||
|
/>
|
||||||
|
<GroupElement name="expenditure_details">
|
||||||
|
<StaticElement
|
||||||
|
name="static"
|
||||||
|
description="Total percentage should add upto 100%"
|
||||||
|
>How would you say your budget is split between seeds,
|
||||||
|
fertilizers, and crop protection?</StaticElement
|
||||||
|
>
|
||||||
|
<TextElement
|
||||||
|
columns="4"
|
||||||
|
name="seeds_expenditure_percentage"
|
||||||
|
input-type="number"
|
||||||
|
label="Seeds %"
|
||||||
|
rules="required|max:100"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
columns="4"
|
||||||
|
name="fertilizer_expenditure_percentage"
|
||||||
|
input-type="number"
|
||||||
|
label="Fertilizer %"
|
||||||
|
rules="required|max:100"
|
||||||
|
F
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
columns="4"
|
||||||
|
name="crops_protection_expenditure_percentage"
|
||||||
|
input-type="number"
|
||||||
|
label="Crops Protection %"
|
||||||
|
rules="required|max:100"
|
||||||
|
/>
|
||||||
|
</GroupElement>
|
||||||
|
<GroupElement name="fertiziler_expenditure_details">
|
||||||
|
<StaticElement
|
||||||
|
name="static"
|
||||||
|
description="Total percentage should add upto 100%"
|
||||||
|
>How is your spend on fertilizers split between
|
||||||
|
synthetic/inorganic fertilizers (like DAP, NPK, etc.) and
|
||||||
|
organic/natural fertilizers (like manure, compost,
|
||||||
|
etc.)</StaticElement
|
||||||
|
>
|
||||||
|
<TextElement
|
||||||
|
columns="6"
|
||||||
|
name="synthetic_fertilizers_expenditure_percentage"
|
||||||
|
input-type="number"
|
||||||
|
label="Synthetic Fertilizers %"
|
||||||
|
rules="required|max:100"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
columns="6"
|
||||||
|
name="natural_fertizilers_percentage"
|
||||||
|
input-type="number"
|
||||||
|
label="Natural Fertilizers %"
|
||||||
|
rules="required|max:100"
|
||||||
|
/>
|
||||||
|
</GroupElement>
|
||||||
|
|
||||||
|
<StaticElement
|
||||||
|
name="static"
|
||||||
|
description="You can add upto 3 expenses."
|
||||||
|
>Select all expenses among seeds, fertilizers, or crop protection
|
||||||
|
that have increased the most in cost for you over the past 3
|
||||||
|
years?</StaticElement
|
||||||
|
>
|
||||||
|
<ListElement name="increased_expenses" :min="0">
|
||||||
|
<template #default="{ index }">
|
||||||
|
<p>Expense</p>
|
||||||
|
<ObjectElement :name="index">
|
||||||
|
<SelectElement
|
||||||
|
rules="required"
|
||||||
|
name="expense_type"
|
||||||
|
:native="false"
|
||||||
|
:items="{
|
||||||
|
fertizilers: 'Fertilizers',
|
||||||
|
seeds: 'Seeds',
|
||||||
|
crop_protection: 'Crop Protection',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<TagsElement
|
||||||
|
rules="required"
|
||||||
|
name="increased_expense_actions"
|
||||||
|
label="How have you dealt with the cost increase?"
|
||||||
|
:items="{
|
||||||
|
no_change: 'No Change',
|
||||||
|
cheap_alternative: 'Purchased and used cheaper alternative',
|
||||||
|
less_quantity: 'Purchased and used less quantity',
|
||||||
|
more_quantity: 'Purchased more',
|
||||||
|
other: 'Other',
|
||||||
|
}"
|
||||||
|
description="Select all options that apply."
|
||||||
|
/>
|
||||||
|
<TextareaElement
|
||||||
|
name="other_action"
|
||||||
|
label="Describe have you dealt with the cost increase?"
|
||||||
|
/>
|
||||||
|
<SelectElement
|
||||||
|
name="expense_action_overall_effect"
|
||||||
|
:native="false"
|
||||||
|
rules="required"
|
||||||
|
:items="{
|
||||||
|
yes: 'Yes',
|
||||||
|
no: 'No',
|
||||||
|
not_sure: 'Not Sure',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<div class="col-span-12">
|
||||||
|
<div class="border-t border-gray-300 mt-1"></div>
|
||||||
|
</div>
|
||||||
|
</ObjectElement>
|
||||||
|
</template>
|
||||||
|
</ListElement>
|
||||||
|
<div class="text mt-4 col-span-12">
|
||||||
|
<div class="border-b border-gray-300 pb-2">EverGrow</div>
|
||||||
|
</div>
|
||||||
|
<SelectElement
|
||||||
|
name="evergrow_past"
|
||||||
|
:native="false"
|
||||||
|
label="Have you used EverGrow before?"
|
||||||
|
:items="{
|
||||||
|
yes: 'Yes',
|
||||||
|
no: 'No',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
name="evergrow_first"
|
||||||
|
label="When did you first begin using EverGrow?"
|
||||||
|
:conditions="[['evergrow_past', 'yes']]"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
name="evergrow_application"
|
||||||
|
label="What is your typical application rate of EverGrow?"
|
||||||
|
description="Average in kg/acre."
|
||||||
|
:conditions="[['evergrow_past', 'yes']]"
|
||||||
|
/>
|
||||||
|
<TagsElement
|
||||||
|
name="evergrow_crops"
|
||||||
|
label="What crops have you seen the most success with using EverGrow?"
|
||||||
|
:items="{
|
||||||
|
rice: 'Rice',
|
||||||
|
coffee: 'Coffee',
|
||||||
|
tea: 'Tea',
|
||||||
|
sugarcane: 'Sugarcane',
|
||||||
|
miraa: 'Miraa',
|
||||||
|
avocados: 'Avocados',
|
||||||
|
maize: 'Maize',
|
||||||
|
potatoes: 'Potatoes',
|
||||||
|
sorghum: 'Sorghum',
|
||||||
|
other_fruits: 'Other fruits',
|
||||||
|
other_vegetables: 'Other vegetables',
|
||||||
|
other_grains: 'Other grains',
|
||||||
|
}"
|
||||||
|
:conditions="[['evergrow_past', 'yes']]"
|
||||||
|
description="Select all options that apply."
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
columns="12"
|
||||||
|
name="evergrow_yield"
|
||||||
|
input-type="number"
|
||||||
|
label="How much have your yields typically improved by when using EverGrow (vs. when not)?"
|
||||||
|
description="Enter a percentage value"
|
||||||
|
:conditions="[['evergrow_past', 'yes']]"
|
||||||
|
/>
|
||||||
|
<div class="text mt-4 col-span-12">
|
||||||
|
<div class="border-b border-gray-300 pb-2">Other Fertilizers</div>
|
||||||
|
</div>
|
||||||
|
<SelectElement
|
||||||
|
label="Do you use any other types of fertilizer on your land?"
|
||||||
|
name="other_fertilizers"
|
||||||
|
:native="false"
|
||||||
|
:items="{
|
||||||
|
yes: 'Yes',
|
||||||
|
no: 'No',
|
||||||
|
not_sure: 'Not Sure',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<StaticElement
|
||||||
|
:conditions="[['other_fertilizers', 'yes']]"
|
||||||
|
name="static"
|
||||||
|
description="You can add upto 3 other fertilizer types."
|
||||||
|
>Select all other fertilizer types that you have used in the
|
||||||
|
past?</StaticElement
|
||||||
|
>
|
||||||
|
<ListElement
|
||||||
|
name="other_fertilizers_details"
|
||||||
|
:min="0"
|
||||||
|
:conditions="[['other_fertilizers', 'yes']]"
|
||||||
|
>
|
||||||
|
<template #default="{ index }">
|
||||||
|
<p>Fertilizer</p>
|
||||||
|
<ObjectElement :name="index">
|
||||||
|
<SelectElement
|
||||||
|
rules="required"
|
||||||
|
name="other_fertilizer_type"
|
||||||
|
:native="false"
|
||||||
|
:items="{
|
||||||
|
synthetic: 'Synthetic Fertilizer',
|
||||||
|
commercial_organic: 'Commercial Organic Fertilizer',
|
||||||
|
self_made: 'Self-made fertilizer/manure',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
name="other_fertilizer_application"
|
||||||
|
label="What is your typical application rate of this type of fertilizer?"
|
||||||
|
description="Average in kg/acre."
|
||||||
|
/>
|
||||||
|
<TagsElement
|
||||||
|
name="evergrow_crops"
|
||||||
|
label="What crops have you seen the most success with using this type of fertilizer"
|
||||||
|
:items="{
|
||||||
|
rice: 'Rice',
|
||||||
|
coffee: 'Coffee',
|
||||||
|
tea: 'Tea',
|
||||||
|
sugarcane: 'Sugarcane',
|
||||||
|
miraa: 'Miraa',
|
||||||
|
avocados: 'Avocados',
|
||||||
|
maize: 'Maize',
|
||||||
|
potatoes: 'Potatoes',
|
||||||
|
sorghum: 'Sorghum',
|
||||||
|
other_fruits: 'Other fruits',
|
||||||
|
other_vegetables: 'Other vegetables',
|
||||||
|
other_grains: 'Other grains',
|
||||||
|
}"
|
||||||
|
description="Select all options that apply."
|
||||||
|
/>
|
||||||
|
<div class="col-span-12">
|
||||||
|
<div class="border-t border-gray-300 mt-1"></div>
|
||||||
|
</div>
|
||||||
|
</ObjectElement>
|
||||||
|
</template>
|
||||||
|
</ListElement>
|
||||||
|
<div class="text mt-4 col-span-12">
|
||||||
|
<div class="border-b border-gray-300 pb-2">
|
||||||
|
Fertilizer Purchase Details
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-12">
|
||||||
|
<Notice
|
||||||
|
subtitle="This applies for all types of fertilizers you purchase including Evergrow. "
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<TagsElement
|
||||||
|
name="purchase_channels"
|
||||||
|
label="Where do you typically purchase your fertilizer from?"
|
||||||
|
:items="{
|
||||||
|
manufacturers: 'Direct from manufacturers',
|
||||||
|
distributors: 'Distributors',
|
||||||
|
resellers: 'Resellers',
|
||||||
|
farmers: 'Fellow farmers',
|
||||||
|
other: 'Other',
|
||||||
|
}"
|
||||||
|
description="Select all options that apply."
|
||||||
|
/>
|
||||||
|
<ButtonElement name="submit" add-class="mt-2" submits>
|
||||||
|
Submit
|
||||||
|
</ButtonElement>
|
||||||
|
</Vueform>
|
||||||
|
<SuccessAlert
|
||||||
|
v-else
|
||||||
|
title="Submission Successful"
|
||||||
|
subtitle="Thank you for submitting the form."
|
||||||
|
link="/"
|
||||||
|
action="Home"
|
||||||
|
/>
|
||||||
|
</ClientOnly>
|
||||||
|
</FormSheet>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const form$ = ref(null);
|
||||||
|
const formSubmitted = ref(false);
|
||||||
|
|
||||||
|
const handleResponse = async (response, form$) => {
|
||||||
|
if (response.status <= 201) {
|
||||||
|
formSubmitted.value = true;
|
||||||
|
} else {
|
||||||
|
form$.messageBag.append("Error");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
1
pages/help.vue
Normal file
1
pages/help.vue
Normal file
@ -0,0 +1 @@
|
|||||||
|
<template></template>
|
19
pages/index.vue
Normal file
19
pages/index.vue
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mt-4 flex flex-col md:flex-row md:space-x-4">
|
||||||
|
<Card
|
||||||
|
title="Registration"
|
||||||
|
subtitle="For all participants."
|
||||||
|
link="/registration"
|
||||||
|
/>
|
||||||
|
<Card
|
||||||
|
title="Farmers Survey"
|
||||||
|
subtitle="For farmers using Evergrow."
|
||||||
|
link="/farmer"
|
||||||
|
/>
|
||||||
|
<Card
|
||||||
|
title="Transaction Record"
|
||||||
|
subtitle="For all EverGrow purchases."
|
||||||
|
link="/transaction"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
88
pages/registration.vue
Normal file
88
pages/registration.vue
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<template>
|
||||||
|
<div class="lg:flex items-start justify-center mt-4">
|
||||||
|
<FormSheet class="mx-2 lg:w-3/4">
|
||||||
|
<ClientOnly>
|
||||||
|
<Vueform
|
||||||
|
v-if="!formSubmitted"
|
||||||
|
ref="form$"
|
||||||
|
validate-on="step"
|
||||||
|
:form-data="(form$) => form$.requestData"
|
||||||
|
@response="handleResponse"
|
||||||
|
endpoint="registration"
|
||||||
|
>
|
||||||
|
<div class="text-xl mb-4 col-span-12">
|
||||||
|
<div class="border-b border-gray-300 pb-2">Registration Form</div>
|
||||||
|
</div>
|
||||||
|
<GroupElement name="personal_information">
|
||||||
|
<TextElement
|
||||||
|
name="name"
|
||||||
|
label="What is your full name?"
|
||||||
|
rules="required|max:150"
|
||||||
|
/>
|
||||||
|
<SelectElement
|
||||||
|
name="age_group"
|
||||||
|
:native="false"
|
||||||
|
label="How old are you?"
|
||||||
|
description="Select the age group you fall into."
|
||||||
|
:items="['20-29', '30-39', '40-49', '50-59', '60-69', '70+']"
|
||||||
|
rules="required"
|
||||||
|
/>
|
||||||
|
<SelectElement
|
||||||
|
name="gender"
|
||||||
|
label="What is your gender?"
|
||||||
|
:native="false"
|
||||||
|
:items="{
|
||||||
|
female: 'Female',
|
||||||
|
male: 'Male',
|
||||||
|
transgender: 'Transgender',
|
||||||
|
other: 'Other',
|
||||||
|
no_response: 'Prefer not to response',
|
||||||
|
}"
|
||||||
|
rules="required"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
name="phone"
|
||||||
|
label="What is your primary phone number?"
|
||||||
|
description="Enter a valid Kenyan phone number starting with 07 or 01."
|
||||||
|
rules="required|phone"
|
||||||
|
/>
|
||||||
|
<SelectElement
|
||||||
|
name="participant_type"
|
||||||
|
label="Are you a farmer, reseller or distributor?"
|
||||||
|
:native="false"
|
||||||
|
:items="{
|
||||||
|
farmer: 'Farmer',
|
||||||
|
reseller: 'Reseller',
|
||||||
|
distributor: 'Distributor',
|
||||||
|
}"
|
||||||
|
rules="required"
|
||||||
|
/>
|
||||||
|
</GroupElement>
|
||||||
|
<ButtonElement name="submit" add-class="mt-2" submits>
|
||||||
|
Register
|
||||||
|
</ButtonElement>
|
||||||
|
</Vueform>
|
||||||
|
<SuccessAlert
|
||||||
|
v-else
|
||||||
|
title="Submission Successful"
|
||||||
|
subtitle="Thank you for submitting the form."
|
||||||
|
link="/"
|
||||||
|
action="Home"
|
||||||
|
/>
|
||||||
|
</ClientOnly>
|
||||||
|
</FormSheet>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const form$ = ref(null);
|
||||||
|
const formSubmitted = ref(false);
|
||||||
|
|
||||||
|
const handleResponse = async (response, form$) => {
|
||||||
|
if (response.status <= 201) {
|
||||||
|
formSubmitted.value = true;
|
||||||
|
} else {
|
||||||
|
form$.messageBag.append("Error");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
61
pages/transaction.vue
Normal file
61
pages/transaction.vue
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<div class="lg:flex items-start justify-center mt-4">
|
||||||
|
<FormSheet class="mx-2 lg:w-3/4">
|
||||||
|
<ClientOnly>
|
||||||
|
<Vueform>
|
||||||
|
<div class="text-xl mb-4 col-span-12">
|
||||||
|
<div class="border-b border-gray-300 pb-2">
|
||||||
|
Record EverGrow Transaction
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<TextElement
|
||||||
|
name="phone"
|
||||||
|
label="What is your phone number?"
|
||||||
|
rules="required"
|
||||||
|
/>
|
||||||
|
<SelectElement
|
||||||
|
name="tx"
|
||||||
|
:native="false"
|
||||||
|
label="Did you buy or sell a FarmStar product?"
|
||||||
|
:items="{
|
||||||
|
buy: 'Buy',
|
||||||
|
sell: 'Sell',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
name="buy"
|
||||||
|
label="Enter the phone number of the person you purchased a FarmStar product from."
|
||||||
|
rules="required"
|
||||||
|
:conditions="[['tx', 'buy']]"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
name="sell"
|
||||||
|
label="Enter the phone number of the person you sold a FarmStar product to."
|
||||||
|
rules="required"
|
||||||
|
:conditions="[['tx', 'sell']]"
|
||||||
|
/>
|
||||||
|
<DateElement
|
||||||
|
name="buy_date"
|
||||||
|
label="When did you make this purchase?"
|
||||||
|
rules="required"
|
||||||
|
:conditions="[['tx', 'buy']]"
|
||||||
|
/>
|
||||||
|
<DateElement
|
||||||
|
name="sell_date"
|
||||||
|
label="When did you make this sale?"
|
||||||
|
rules="required"
|
||||||
|
:conditions="[['tx', 'sell']]"
|
||||||
|
/>
|
||||||
|
<TextareaElement
|
||||||
|
name="textarea"
|
||||||
|
:conditions="[['tx', ['sell', 'buy']]]"
|
||||||
|
label="Do you have any comments or feedback for FarmStar?"
|
||||||
|
/>
|
||||||
|
<ButtonElement name="submit" add-class="mt-2" submits>
|
||||||
|
Submit
|
||||||
|
</ButtonElement>
|
||||||
|
</Vueform>
|
||||||
|
</ClientOnly>
|
||||||
|
</FormSheet>
|
||||||
|
</div>
|
||||||
|
</template>
|
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
3
server/tsconfig.json
Normal file
3
server/tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"extends": "../.nuxt/tsconfig.server.json"
|
||||||
|
}
|
22
tailwind.config.js
Normal file
22
tailwind.config.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
export default {
|
||||||
|
content: [
|
||||||
|
"./components/**/*.{js,vue,ts}",
|
||||||
|
"./layouts/**/*.vue",
|
||||||
|
"./pages/**/*.vue",
|
||||||
|
"./plugins/**/*.{js,ts}",
|
||||||
|
"./nuxt.config.{js,ts}",
|
||||||
|
'./vueform.config.{js,ts}',
|
||||||
|
'./node_modules/@vueform/vueform/themes/tailwind/**/*.vue',
|
||||||
|
'./node_modules/@vueform/vueform/themes/tailwind/**/*.js',
|
||||||
|
'./node_modules/flowbite/**/*.{js,ts}'
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
require('flowbite/plugin'),
|
||||||
|
require('@vueform/vueform/tailwind')
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
4
tsconfig.json
Normal file
4
tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
// https://nuxt.com/docs/guide/concepts/typescript
|
||||||
|
"extends": "./.nuxt/tsconfig.json"
|
||||||
|
}
|
30
vueform.config.js
Normal file
30
vueform.config.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import en from '@vueform/vueform/locales/en'
|
||||||
|
import tailwind from '@vueform/vueform/themes/tailwind'
|
||||||
|
|
||||||
|
import { Validator } from '@vueform/vueform'
|
||||||
|
|
||||||
|
const phoneRule = class extends Validator {
|
||||||
|
get message() {
|
||||||
|
return 'The What is your primary phone number? filed requires a valid phone number'
|
||||||
|
}
|
||||||
|
|
||||||
|
check(value) {
|
||||||
|
return /^(07|01)(\d){8}$/.test(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
theme: tailwind,
|
||||||
|
locales: { en },
|
||||||
|
locale: 'en',
|
||||||
|
floatPlaceholders: false,
|
||||||
|
rules: {
|
||||||
|
phone: phoneRule,
|
||||||
|
},
|
||||||
|
endpoints: {
|
||||||
|
registration: {
|
||||||
|
url: 'https://webhook.site/af68d53b-063e-4588-a1ae-e49bc8cf5167',
|
||||||
|
method: 'post'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user