<commit_before>import React from 'react'
import { api } from '../../data'
import {
  Aside,
  FormWrapper,
  Fieldset,
  FormAndTableRow,
  Field,
  Submit,
  Form,
  TableOfContents
} from '../components/Forms'
import LeaderInviteForm from '../components/LeaderInviteForm'
import Button from '../components/Button'
import { Column, Container, Flex, Box } from 'rebass'
import { withFormik } from 'formik'

const InnerForm = props => {
  const {
    values,
    errors,
    touched,
    handleChange,
    handleBlur,
    handleSubmit,
    isSubmitting,
    id,
    authToken,
    params
  } = props
  const markSubmitted = e => {
    e.preventDefault()
    if (values.submitted_at) {
      alert(
        'Application already submitted. If you want to make further edits, just "Save Draft"'
      )
    } else {
      fetch(`${api}/v1/new_club_applications/${id}/submit`, {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${authToken}`
        }
      })
        .then(res => {
          if (res.ok) {
            return res.json()
          } else {
            throw res
          }
        })
        .then(json => {
          alert(json)
        })
        .catch(e => {
          console.error(e)
          if (e.status === 422) {
            alert(
              "Can't submit. Finish filling out the application and make sure all co-leads have filled out their profiles."
            )
          } else {
            alert('Something went terribly wrong')
          }
        })
    }
  }
  return (
    <FormWrapper>
      <Form onSubmit={handleSubmit}>
        <Fieldset section="school">
          <Field
            name="high_school_name"
            label="Name of high school"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_name}
            error={touched.high_school_name && errors.high_school_name}
            required
          />
          <Field
            name="high_school_url"
            label="Link to your high school's website, if any"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_url}
            error={touched.high_school_url && errors.high_school_url}
          />
          <Field
            name="high_school_type"
            label="Type of school"
            type="select"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_type || 'select'}
            error={touched.high_school_type && errors.high_school_type}
            required
          >
            <option disabled value="select">
              Select One
            </option>
            <option value="public_school">Public school</option>
            <option value="private_school">Private school</option>
            <option value="charter_school">Charter school</option>
          </Field>
          <Field
            name="high_school_address"
            label="High school's full address (include city, state/province, country)"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_address}
            error={touched.high_school_address && errors.high_school_address}
            type="textarea"
            required
          />
        </Fieldset>
        <Fieldset section="leaders">
          <LeaderInviteForm params={values} id={id} authToken={authToken} />
          <Field
            name="point_of_contact_id"
            label="Point of contact"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.point_of_contact_id || 'select'}
            error={touched.point_of_contact_id && errors.point_of_contact_id}
            type="select"
            required
          >
            <option disabled value="select">
              Select One
            </option>
            {values.applicant_profiles.map((profile, index) => (
              <option value={profile.applicant.id} key={index}>
                {profile.applicant.email}
              </option>
            ))}
          </Field>
          <Field
            name="leaders_video_url"
            label="Please enter the URL of a 1 minute unlisted (not private) YouTube video introducing the leaders"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.leaders_video_url}
            error={touched.leaders_video_url && errors.leaders_video_url}
            required
          />
          <Field
            name="leaders_interesting_project"
            label="Please tell us about an interesting project, preferably outside of class, that two or more of you created together. Include URLs if possible."
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.leaders_interesting_project}
            error={
              touched.leaders_interesting_project &&
              errors.leaders_interesting_project
            }
            type="textarea"
            required
          />
          <Field
            name="leaders_team_origin_story"
            label="How long have you known your other club leaders and how did you meet?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.leaders_team_origin_story}
            error={
              touched.leaders_team_origin_story &&
              errors.leaders_team_origin_story
            }
            type="textarea"
            required
          />
        </Fieldset>
        <Fieldset section="progress">
          <Field
            name="progress_general"
            label="How far along are you in starting your club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.progress_general}
            error={touched.progress_general && errors.progress_general}
            type="textarea"
            required
          />
          <Field
            name="progress_student_interest"
            label="Have you already polled for interest at your school? Are students interested? If you've already had meetings, how many people came?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.progress_student_interest}
            error={
              touched.progress_student_interest &&
              errors.progress_student_interest
            }
            type="textarea"
            required
          />
          <Field
            name="progress_meeting_yet"
            label="Have you begun meeting yet? We encourage you to not begin meeting until we accept you."
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.progress_meeting_yet}
            error={touched.progress_meeting_yet && errors.progress_meeting_yet}
            type="textarea"
            required
          />
        </Fieldset>
        <Fieldset section="idea">
          <Field
            name="idea_why"
            label="Why did you decide to start a Hack Club? Have you ran anything like a Hack Club before? Why do you think the club is going to work?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.idea_why}
            error={touched.idea_why && errors.idea_why}
            type="textarea"
            required
          />
          <Field
            name="idea_other_coding_clubs"
            label="Has your school had coding clubs before? What's going to be new about your Hack Club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.idea_other_coding_clubs}
            error={
              touched.idea_other_coding_clubs && errors.idea_other_coding_clubs
            }
            type="textarea"
            required
          />
          <Field
            name="idea_other_general_clubs"
            label="What other clubs exist at your school? Why will you be just as successful, if not more, than them?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.idea_other_general_clubs}
            error={
              touched.idea_other_general_clubs &&
              errors.idea_other_general_clubs
            }
            type="textarea"
            required
          />
        </Fieldset>
        <Fieldset section="formation">
          <Field
            name="formation_registered"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.formation_registered}
            error={touched.formation_registered && errors.formation_registered}
            label="Have you already registered your club with your school?"
            required
          />
          <Field
            name="formation_misc"
            label="Please provide any other relevant information about the structure or formation of the club."
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.formation_misc}
            error={touched.formation_misc && errors.formation_misc}
            type="textarea"
          />
        </Fieldset>
        <Fieldset section="other">
          <Field
            name="other_surprising_or_amusing_discovery"
            label="What is something surprising or amusing you discovered?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.other_surprising_or_amusing_discovery}
            error={
              touched.other_surprising_or_amusing_discovery &&
              errors.other_surprising_or_amusing_discovery
            }
            type="textarea"
            required
          />
        </Fieldset>
        <Fieldset section="curious">
          <Field
            name="curious_what_convinced"
            label="What convinced you to start a Hack Club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.curious_what_convinced}
            error={
              touched.curious_what_convinced && errors.curious_what_convinced
            }
            type="textarea"
          />
          <Field
            name="curious_how_did_hear"
            label="How did you hear about Hack Club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.curious_how_did_hear}
            error={touched.curious_how_did_hear && errors.curious_how_did_hear}
            type="textarea"
          />
        </Fieldset>
        <Submit value="Save Draft" disabled={isSubmitting} />
        <Submit
          value="Submit Application"
          disabled={isSubmitting}
          onClick={markSubmitted}
        />
      </Form>
    </FormWrapper>
  )
}

const ClubApplicationForm = withFormik({
  mapPropsToValues: props => props.params,
  enableReinitialize: true,
  handleSubmit: (data, { setSubmitting, props }) => {
    fetch(`${api}/v1/new_club_applications/${props.id}`, {
      method: 'PATCH',
      headers: {
        Authorization: `Bearer ${props.authToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(data)
    })
      .then(res => {
        if (res.ok) {
          return res.json()
        } else {
          throw res
        }
      })
      .then(json => {
        alert('Saved!')
        setSubmitting(false)
      })
      .catch(e => {
        console.error(e)
        alert(e)
        setSubmitting(false)
      })
  },
  displayName: 'ClubApplicationForm'
})(InnerForm)
export default ClubApplicationForm
<commit_msg>Rich quote on error message<commit_after>import React from 'react'
import { api } from '../../data'
import {
  Aside,
  FormWrapper,
  Fieldset,
  FormAndTableRow,
  Field,
  Submit,
  Form,
  TableOfContents
} from '../components/Forms'
import LeaderInviteForm from '../components/LeaderInviteForm'
import Button from '../components/Button'
import { Column, Container, Flex, Box } from 'rebass'
import { withFormik } from 'formik'

const InnerForm = props => {
  const {
    values,
    errors,
    touched,
    handleChange,
    handleBlur,
    handleSubmit,
    isSubmitting,
    id,
    authToken,
    params
  } = props
  const markSubmitted = e => {
    e.preventDefault()
    if (values.submitted_at) {
      alert(
        'Application already submitted. If you want to make further edits, just "Save Draft"'
      )
    } else {
      fetch(`${api}/v1/new_club_applications/${id}/submit`, {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${authToken}`
        }
      })
        .then(res => {
          if (res.ok) {
            return res.json()
          } else {
            throw res
          }
        })
        .then(json => {
          alert(json)
        })
        .catch(e => {
          console.error(e)
          if (e.status === 422) {
            alert(
              'Can’t submit. Finish filling out the application and make sure all co-leads have filled out their profiles.'
            )
          } else {
            alert('Something went terribly wrong')
          }
        })
    }
  }
  return (
    <FormWrapper>
      <Form onSubmit={handleSubmit}>
        <Fieldset section="school">
          <Field
            name="high_school_name"
            label="Name of high school"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_name}
            error={touched.high_school_name && errors.high_school_name}
            required
          />
          <Field
            name="high_school_url"
            label="Link to your high school's website, if any"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_url}
            error={touched.high_school_url && errors.high_school_url}
          />
          <Field
            name="high_school_type"
            label="Type of school"
            type="select"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_type || 'select'}
            error={touched.high_school_type && errors.high_school_type}
            required
          >
            <option disabled value="select">
              Select One
            </option>
            <option value="public_school">Public school</option>
            <option value="private_school">Private school</option>
            <option value="charter_school">Charter school</option>
          </Field>
          <Field
            name="high_school_address"
            label="High school's full address (include city, state/province, country)"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_address}
            error={touched.high_school_address && errors.high_school_address}
            type="textarea"
            required
          />
        </Fieldset>
        <Fieldset section="leaders">
          <LeaderInviteForm params={values} id={id} authToken={authToken} />
          <Field
            name="point_of_contact_id"
            label="Point of contact"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.point_of_contact_id || 'select'}
            error={touched.point_of_contact_id && errors.point_of_contact_id}
            type="select"
            required
          >
            <option disabled value="select">
              Select One
            </option>
            {values.applicant_profiles.map((profile, index) => (
              <option value={profile.applicant.id} key={index}>
                {profile.applicant.email}
              </option>
            ))}
          </Field>
          <Field
            name="leaders_video_url"
            label="Please enter the URL of a 1 minute unlisted (not private) YouTube video introducing the leaders"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.leaders_video_url}
            error={touched.leaders_video_url && errors.leaders_video_url}
            required
          />
          <Field
            name="leaders_interesting_project"
            label="Please tell us about an interesting project, preferably outside of class, that two or more of you created together. Include URLs if possible."
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.leaders_interesting_project}
            error={
              touched.leaders_interesting_project &&
              errors.leaders_interesting_project
            }
            type="textarea"
            required
          />
          <Field
            name="leaders_team_origin_story"
            label="How long have you known your other club leaders and how did you meet?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.leaders_team_origin_story}
            error={
              touched.leaders_team_origin_story &&
              errors.leaders_team_origin_story
            }
            type="textarea"
            required
          />
        </Fieldset>
        <Fieldset section="progress">
          <Field
            name="progress_general"
            label="How far along are you in starting your club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.progress_general}
            error={touched.progress_general && errors.progress_general}
            type="textarea"
            required
          />
          <Field
            name="progress_student_interest"
            label="Have you already polled for interest at your school? Are students interested? If you've already had meetings, how many people came?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.progress_student_interest}
            error={
              touched.progress_student_interest &&
              errors.progress_student_interest
            }
            type="textarea"
            required
          />
          <Field
            name="progress_meeting_yet"
            label="Have you begun meeting yet? We encourage you to not begin meeting until we accept you."
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.progress_meeting_yet}
            error={touched.progress_meeting_yet && errors.progress_meeting_yet}
            type="textarea"
            required
          />
        </Fieldset>
        <Fieldset section="idea">
          <Field
            name="idea_why"
            label="Why did you decide to start a Hack Club? Have you ran anything like a Hack Club before? Why do you think the club is going to work?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.idea_why}
            error={touched.idea_why && errors.idea_why}
            type="textarea"
            required
          />
          <Field
            name="idea_other_coding_clubs"
            label="Has your school had coding clubs before? What's going to be new about your Hack Club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.idea_other_coding_clubs}
            error={
              touched.idea_other_coding_clubs && errors.idea_other_coding_clubs
            }
            type="textarea"
            required
          />
          <Field
            name="idea_other_general_clubs"
            label="What other clubs exist at your school? Why will you be just as successful, if not more, than them?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.idea_other_general_clubs}
            error={
              touched.idea_other_general_clubs &&
              errors.idea_other_general_clubs
            }
            type="textarea"
            required
          />
        </Fieldset>
        <Fieldset section="formation">
          <Field
            name="formation_registered"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.formation_registered}
            error={touched.formation_registered && errors.formation_registered}
            label="Have you already registered your club with your school?"
            required
          />
          <Field
            name="formation_misc"
            label="Please provide any other relevant information about the structure or formation of the club."
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.formation_misc}
            error={touched.formation_misc && errors.formation_misc}
            type="textarea"
          />
        </Fieldset>
        <Fieldset section="other">
          <Field
            name="other_surprising_or_amusing_discovery"
            label="What is something surprising or amusing you discovered?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.other_surprising_or_amusing_discovery}
            error={
              touched.other_surprising_or_amusing_discovery &&
              errors.other_surprising_or_amusing_discovery
            }
            type="textarea"
            required
          />
        </Fieldset>
        <Fieldset section="curious">
          <Field
            name="curious_what_convinced"
            label="What convinced you to start a Hack Club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.curious_what_convinced}
            error={
              touched.curious_what_convinced && errors.curious_what_convinced
            }
            type="textarea"
          />
          <Field
            name="curious_how_did_hear"
            label="How did you hear about Hack Club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.curious_how_did_hear}
            error={touched.curious_how_did_hear && errors.curious_how_did_hear}
            type="textarea"
          />
        </Fieldset>
        <Submit value="Save Draft" disabled={isSubmitting} />
        <Submit
          value="Submit Application"
          disabled={isSubmitting}
          onClick={markSubmitted}
        />
      </Form>
    </FormWrapper>
  )
}

const ClubApplicationForm = withFormik({
  mapPropsToValues: props => props.params,
  enableReinitialize: true,
  handleSubmit: (data, { setSubmitting, props }) => {
    fetch(`${api}/v1/new_club_applications/${props.id}`, {
      method: 'PATCH',
      headers: {
        Authorization: `Bearer ${props.authToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(data)
    })
      .then(res => {
        if (res.ok) {
          return res.json()
        } else {
          throw res
        }
      })
      .then(json => {
        alert('Saved!')
        setSubmitting(false)
      })
      .catch(e => {
        console.error(e)
        alert(e)
        setSubmitting(false)
      })
  },
  displayName: 'ClubApplicationForm'
})(InnerForm)
export default ClubApplicationForm
<|endoftext|>


<commit_before>import {text} from 'incremental-dom'

export function item(value) {
    if(typeof value == 'function') {
        value()
    } else {
        text(value)
    }
}
<commit_msg>Fix incorrect key propagation to child view<commit_after>import {text} from 'incremental-dom'

export function item(value, key) {
    if(typeof value == 'function') {
        value(key)
    } else {
        text(value)
    }
}
<|endoftext|>


<commit_before>import React, { useEffect, useState } from "react"
import {
    Grid,
    Box,
    Slider,
    Typography
} from "@material-ui/core"
import moment from "moment"

export default function FoodTimeForm(props) {
    const [breakfastDuration, setBreakfastDuration] = useState(moment.duration(props.foodTimeRanges[0]).asMinutes());
    const [lunchDuration, setLunchDuration] = useState(moment.duration(props.foodTimeRanges[1]).asMinutes());
    const [dinnerDuration, setDinnerDuration] = useState(moment.duration(props.foodTimeRanges[2]).asMinutes());

    const handleBreakfastDurationChange = (event, mins) => {
        setBreakfastDuration(mins);
    }

    const handleLunchDurationChange = (event, mins) => {
        setLunchDuration(mins);
    }

    const handleDinnerDurationChange = (event, mins) => {
        setDinnerDuration(mins);
    }

    useEffect(() => {
        props.onChange([
            moment.duration(breakfastDuration, "minutes").asMilliseconds(),
            moment.duration(lunchDuration, "minutes").asMilliseconds(),
            moment.duration(dinnerDuration, "minutes").asMilliseconds(),
        ])
    }, [breakfastDuration, lunchDuration, dinnerDuration])

    const marks = [
        {
            value: 30,
            label: "30 min"
        },
        {
            value: 60,
            label: "60 min"
        },
        {
            value: 90,
            label: "90 min"
        },
        {
            value: 120,
            label: "120 min"
        }
    ]

    return (
        <Grid container direction="column">
            <Grid item>
                <Box mt={2}>
                    <Typography variant="subtitle2" gutterBottom>Enter a duration for each meal and we'll be sure to leave space in your schedule.</Typography>
                </Box>
            </Grid>
            <Grid item>
                <Box my={3} mr={3}>
                    <Typography id="discrete-slider-custom" gutterBottom>Breakfast Duration</Typography>
                    <Slider
                        value={breakfastDuration}
                        step={10}
                        valueLabelDisplay="auto"
                        marks={marks}
                        min={0}
                        max={120}
                        onChange={handleBreakfastDurationChange}
                    />
                </Box>
            </Grid>
            <Grid item>
                <Box my={1} mr={3}>
                    <Typography id="discrete-slider-custom" gutterBottom>Lunch Duration</Typography>
                    <Slider
                        value={lunchDuration}
                        step={10}
                        valueLabelDisplay="auto"
                        marks={marks}
                        min={0}
                        max={120}
                        onChange={handleLunchDurationChange}
                    />
                </Box>
            </Grid>
            <Grid item>
                <Box my={1} mr={3}>
                    <Typography id="discrete-slider-custom" gutterBottom>Dinner Duration</Typography>
                    <Slider
                        value={dinnerDuration}
                        step={10}
                        valueLabelDisplay="auto"
                        marks={marks}
                        min={0}
                        max={120}
                        onChange={handleDinnerDurationChange}
                    />
                </Box>
            </Grid>
        </Grid>
    )
}<commit_msg>Fix spacing<commit_after>import React, { useEffect, useState } from "react"
import {
    Grid,
    Box,
    Slider,
    Typography
} from "@material-ui/core"
import moment from "moment"

export default function FoodTimeForm(props) {
    const [breakfastDuration, setBreakfastDuration] = useState(moment.duration(props.foodTimeRanges[0]).asMinutes());
    const [lunchDuration, setLunchDuration] = useState(moment.duration(props.foodTimeRanges[1]).asMinutes());
    const [dinnerDuration, setDinnerDuration] = useState(moment.duration(props.foodTimeRanges[2]).asMinutes());

    const handleBreakfastDurationChange = (event, mins) => {
        setBreakfastDuration(mins);
    }

    const handleLunchDurationChange = (event, mins) => {
        setLunchDuration(mins);
    }

    const handleDinnerDurationChange = (event, mins) => {
        setDinnerDuration(mins);
    }

    useEffect(() => {
        props.onChange([
            moment.duration(breakfastDuration, "minutes").asMilliseconds(),
            moment.duration(lunchDuration, "minutes").asMilliseconds(),
            moment.duration(dinnerDuration, "minutes").asMilliseconds(),
        ])
    }, [breakfastDuration, lunchDuration, dinnerDuration])

    const marks = [
        {
            value: 30,
            label: "30 min"
        },
        {
            value: 60,
            label: "60 min"
        },
        {
            value: 90,
            label: "90 min"
        },
        {
            value: 120,
            label: "120 min"
        }
    ]

    return (
        <Grid container direction="column">
            <Grid item>
                <Box mt={2}>
                    <Typography variant="subtitle2" gutterBottom>Enter a duration for each meal and we'll be sure to leave space in your schedule.</Typography>
                </Box>
            </Grid>
            <Grid item>
                <Box my={3} mb={1} mr={3}>
                    <Typography id="discrete-slider-custom" gutterBottom>Breakfast Duration</Typography>
                    <Slider
                        value={breakfastDuration}
                        step={10}
                        valueLabelDisplay="auto"
                        marks={marks}
                        min={0}
                        max={120}
                        onChange={handleBreakfastDurationChange}
                    />
                </Box>
            </Grid>
            <Grid item>
                <Box my={1} mr={3}>
                    <Typography id="discrete-slider-custom" gutterBottom>Lunch Duration</Typography>
                    <Slider
                        value={lunchDuration}
                        step={10}
                        valueLabelDisplay="auto"
                        marks={marks}
                        min={0}
                        max={120}
                        onChange={handleLunchDurationChange}
                    />
                </Box>
            </Grid>
            <Grid item>
                <Box my={1} mr={3}>
                    <Typography id="discrete-slider-custom" gutterBottom>Dinner Duration</Typography>
                    <Slider
                        value={dinnerDuration}
                        step={10}
                        valueLabelDisplay="auto"
                        marks={marks}
                        min={0}
                        max={120}
                        onChange={handleDinnerDurationChange}
                    />
                </Box>
            </Grid>
        </Grid>
    )
}<|endoftext|>


<commit_before>/*
 * This program is part of the OpenLMIS logistics management information system platform software.
 * Copyright © 2017 VillageReach
 *
 * This program is free software: you can redistribute it and/or modify it under the terms
 * of the GNU Affero General Public License as published by the Free Software Foundation, either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details. You should have received a copy of
 * the GNU Affero General Public License along with this program. If not, see
 * http://www.gnu.org/licenses.  For additional information contact info@OpenLMIS.org.
 */

describe('stockCardSummariesService', function () {

  var service, httpBackend, rootScope, stockmanagementUrlFactory, messageService;

  beforeEach(function () {
    module('stock-card-summaries');

    inject(function (_stockCardSummariesService_, _$httpBackend_, _$rootScope_,
                     _stockmanagementUrlFactory_, _messageService_) {
      service = _stockCardSummariesService_;
      messageService = _messageService_;
      httpBackend = _$httpBackend_;
      rootScope = _$rootScope_;
      stockmanagementUrlFactory = _stockmanagementUrlFactory_;
    });
  });

  xit('should get stock card summaries', function () {
    var summary1 = {
      "stockOnHand": 123,
      "facility": {
        "id": "e6799d64-d10d-4011-b8c2-0e4d4a3f65ce",
        "code": "HC01",
        "name": "Comfort Health Clinic"
      },
    };
    var summary2 = {
      "stockOnHand": 456,
      "facility": {
        "id": "e6799d64-d10d-4011-b8c2-0e4d4a3f65ce",
        "code": "HC01",
        "name": "Comfort Health Clinic"
      },
      lot: {}
    };
    httpBackend.when('GET', stockmanagementUrlFactory('/api/stockCardSummaries?searchOption=ExistingStockCardsOnly'))
      .respond(200, [summary1, summary2]);

    var result = [];
    service.getStockCardSummaries().then(function (data) {
      result = data;
    });

    httpBackend.flush();

    expect(result.length).toBe(2);
    expect(angular.equals(result, [summary1, summary2])).toBeTruthy();
  });

  describe('search', function () {
    var item1, item2, item3, items;

    beforeEach(function () {
      item1 = {
        "stockOnHand": 233,
        "orderable": {
          "productCode": "C1",
          "fullProductName": "Acetylsalicylic Acid",
          "dispensable": {
            "dispensingUnit": ""
          }
        },
        "lot": {"lotCode": "LC0006", "expirationDate": "2016-06-30T08:06:08.454Z"},
        "lastUpdate": "2017-04-25T08:06:08.454Z"
      };

      item2 = {
        "stockOnHand": 23,
        "orderable": {
          "productCode": "C2",
          "fullProductName": "Streptococcus Pneumoniae Vaccine",
          "dispensable": {
            "dispensingUnit": ""
          }
        },
        "lot": {"lotCode": "LC0003", "expirationDate": "2016-06-30T08:06:08.454Z"},
        "lastUpdate": "2018-04-25T08:06:08.454Z"
      };

      item3 = {
        "stockOnHand": 30,
        "orderable": {
          "productCode": "C3",
          "fullProductName": "Levora",
          "dispensable": {
            "dispensingUnit": ""
          }
        },
        "lot": null,
        "lastUpdate": "2019-04-25T08:06:08.454Z"
      };

      items = [item1, item2, item3];
    });

    it('should search by productCode', function () {
      expect(service.search('C3', items)).toEqual([item3]);
    });

    it('should search by fullProductName', function () {
      expect(service.search('Vaccine', items)).toEqual([item2]);
    });

    it('should search by stockOnHand', function () {
      expect(service.search('23', items)).toEqual([item1, item2]);
    });

    it('should search by lotCode', function () {
      spyOn(messageService, 'get');
      messageService.get.andReturn('No lot defined');

      expect(service.search('LC', items)).toEqual([item1, item2]);
      expect(service.search('No lot defined', items)).toEqual([item3]);
    });

    it('should search by lot expirationDate', function () {
      expect(service.search('30/06/2016', items)).toEqual([item1, item2]);
    });

    it('should search by lastUpdate', function () {
      expect(service.search('25/04', items)).toEqual(items);
    });

    it('should renturn all items when keyword is empty', function () {
      expect(service.search('', items)).toEqual(items);
    });
  });
});
<commit_msg>update tests of card summaries service<commit_after>/*
 * This program is part of the OpenLMIS logistics management information system platform software.
 * Copyright © 2017 VillageReach
 *
 * This program is free software: you can redistribute it and/or modify it under the terms
 * of the GNU Affero General Public License as published by the Free Software Foundation, either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details. You should have received a copy of
 * the GNU Affero General Public License along with this program. If not, see
 * http://www.gnu.org/licenses.  For additional information contact info@OpenLMIS.org.
 */

describe('stockCardSummariesService', function () {

  var service, httpBackend, rootScope, stockmanagementUrlFactory, messageService;

  beforeEach(function () {
    module('stock-card-summaries');

    inject(function (_stockCardSummariesService_, _$httpBackend_, _$rootScope_,
                     _stockmanagementUrlFactory_, _messageService_) {
      service = _stockCardSummariesService_;
      messageService = _messageService_;
      httpBackend = _$httpBackend_;
      rootScope = _$rootScope_;
      stockmanagementUrlFactory = _stockmanagementUrlFactory_;
    });
  });

  it('should get stock card summaries', function () {
    var summary1 = {
      "stockOnHand": 123,
      "facility": {
        "id": "e6799d64-d10d-4011-b8c2-0e4d4a3f65ce",
        "code": "HC01",
        "name": "Comfort Health Clinic"
      },
    };
    var summary2 = {
      "stockOnHand": 456,
      "facility": {
        "id": "e6799d64-d10d-4011-b8c2-0e4d4a3f65ce",
        "code": "HC01",
        "name": "Comfort Health Clinic"
      },
      lot: {}
    };
    var summaries = {
      "totalPages": 1,
      "content": [summary1, summary2]
    };
    var programId = 'pId';
    var facilityId = 'fId';
    var pageSize = 100;

    var urlParams = '?facility=' + facilityId + '&program=' + programId + '&size=' + pageSize;
    httpBackend.when('GET', stockmanagementUrlFactory('/api/stockCardSummaries' + urlParams)).respond(200, summaries);

    var result = [];
    service.getStockCardSummaries(programId, facilityId).then(function (data) {
      result = data;
    });

    httpBackend.flush();

    expect(result.length).toBe(2);
    expect(angular.equals(result, [summary1, summary2])).toBeTruthy();
  });

  describe('search', function () {
    var item1, item2, item3, items;

    beforeEach(function () {
      item1 = {
        "stockOnHand": 233,
        "orderable": {
          "productCode": "C1",
          "fullProductName": "Acetylsalicylic Acid",
          "dispensable": {
            "dispensingUnit": ""
          }
        },
        "lot": {"lotCode": "LC0006", "expirationDate": "2016-06-30T08:06:08.454Z"},
        "lastUpdate": "2017-04-25T08:06:08.454Z"
      };

      item2 = {
        "stockOnHand": 23,
        "orderable": {
          "productCode": "C2",
          "fullProductName": "Streptococcus Pneumoniae Vaccine",
          "dispensable": {
            "dispensingUnit": ""
          }
        },
        "lot": {"lotCode": "LC0003", "expirationDate": "2016-06-30T08:06:08.454Z"},
        "lastUpdate": "2018-04-25T08:06:08.454Z"
      };

      item3 = {
        "stockOnHand": 30,
        "orderable": {
          "productCode": "C3",
          "fullProductName": "Levora",
          "dispensable": {
            "dispensingUnit": ""
          }
        },
        "lot": null,
        "lastUpdate": "2019-04-25T08:06:08.454Z"
      };

      items = [item1, item2, item3];
    });

    it('should search by productCode', function () {
      expect(service.search('C3', items)).toEqual([item3]);
    });

    it('should search by fullProductName', function () {
      expect(service.search('Vaccine', items)).toEqual([item2]);
    });

    it('should search by stockOnHand', function () {
      expect(service.search('23', items)).toEqual([item1, item2]);
    });

    it('should search by lotCode', function () {
      spyOn(messageService, 'get');
      messageService.get.andReturn('No lot defined');

      expect(service.search('LC', items)).toEqual([item1, item2]);
      expect(service.search('No lot defined', items)).toEqual([item3]);
    });

    it('should search by lot expirationDate', function () {
      expect(service.search('30/06/2016', items)).toEqual([item1, item2]);
    });

    it('should search by lastUpdate', function () {
      expect(service.search('25/04', items)).toEqual(items);
    });

    it('should renturn all items when keyword is empty', function () {
      expect(service.search('', items)).toEqual(items);
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

angular.module('projects').controller('ProjectEditController', ['$scope', '$stateParams', '$location', 'Authentication', 'Projects', '$http', '$mdToast', '$mdDialog', '$timeout', '$rootScope',
	function($scope, $stateParams, $location, Authentication, Projects, $http, $mdToast, $mdDialog, $timeout, $rootScope) {
		$scope.members = true;
		$scope.estimated = false;
		$scope.goTo = function(route) {
			$location.path(route);
		};

		$scope.authentication = Authentication;
		$scope.userIndex = -1;
		var project = {'projectId': $stateParams.projectId};
		$http({method:'POST', url:'/project', data: project}).success(function(data) {
			if (data.length !== 0) {
				var tmp = data[0];
				for (var u in tmp.users) {
					if (tmp.users[u] === $scope.authentication.user.username) {
						$scope.userIndex = u;
					}
				}

				if ($scope.userIndex === -1) {
					var toast = $mdToast.simple()
					.content('Not authorised to estimate')
					.action('')
					.highlightAction(false)
					.position($scope.getToastPosition());
					$mdToast.show(toast);
				}
			}
		});

		$scope.rootIsEmpty = function() {
			if ($scope.project.$resolved !== false) {
				if ($scope.project.children.length < 1) {
					return true;
				} else {
					return false;
				}
			}
		};

		$scope.owner = function() {
			if ($scope.project.$resolved !== false) {
				if ($scope.project.owner === $scope.authentication.user.username) {
					return true;
				} else {
					return false;
				}
			}
		};

		$scope.estimator = function() {
			if ($scope.userIndex === -1) {
				return false;
			} else {
				return true;
			}
		};

		$scope.submitEstimation = function() {
			$scope.saveProject();
			$scope.estimated = true;
		};

		$scope.addRootNode = function() {
			// initialise estimations array
			var estimationsArr = [];
			for (var i in $scope.project.users) {
				estimationsArr.push(null);
			}
			$scope.project.children.push({id: 'node', title:'Root Node', nodes: [], collapsed : false, estimations : estimationsArr});
		};

		$scope.update = function() {
			var project = $scope.project;

			project.$update(function() {
				$location.path('projects/' + project._id);
			}, function(errorResponse) {
				$scope.error = errorResponse.data.message;
			});
		};

		$scope.find = function() {
			$scope.projects = Projects.query();
		};

		// Find existing Project
		$scope.findOne = function() {
			$scope.project = Projects.get({
				projectId: $stateParams.projectId
			}, function() {
				if ($scope.project.children[0].estimations[$scope.userIndex] === null) {
					$scope.estimated = false;
				} else {
					$scope.estimated = true;
				}
			});
		};

		$scope.newSubItem = function(scope) {
			// console.log(scope.project.users);
			var nodeData = scope.$modelValue;
			// console.log(nodeData);
			var estimationsArr = [];
			for (var i in scope.project.users) {
				// console.log(i);
				estimationsArr.push(null);
			}
			nodeData.nodes.push({
				id: nodeData.id * 10 + nodeData.nodes.length,
				title: nodeData.title + '.' + (nodeData.nodes.length + 1),
				nodes: [],
				collapsed : false,
				estimations : estimationsArr
			});
		};

		$scope.undoToolTip = function(node, removeNode, newSubItem) {
			//debugger;
			var tree = $.extend(true, [], $scope.project.children);
			removeNode(node);
			var toast = $mdToast.simple()
				.content('Node deleted')
				.action('UNDO')
				.highlightAction(false)
				.position($scope.getToastPosition());
			$mdToast.show(toast).then(function() {
				$scope.project.children = $.extend(true, [], tree);
			});
		};

		$scope.toastPosition = {
			bottom: true,
			top: false,
			left: false,
			right: true
		};

		$scope.getToastPosition = function() {
			return Object.keys($scope.toastPosition)
			.filter(function(pos) { return $scope.toastPosition[pos]; })
			.join(' ');
		};

		$scope.saveProject = function() {
			$scope.project.$update(function(response) {
				$mdToast.show(
					$mdToast.simple()
					.content('Project saved')
					.position($scope.getToastPosition())
					.hideDelay(3000)
				);
			}, function(errorResponse) {
				$scope.error = errorResponse.data.message;
			});
		};
		$scope.querySearch = function(query) {
			//console.log(query);
			var results = query ? $scope.projects.filter(createFilterFor(query)) : $scope.projects, deferred;
			return results;
		};

		$scope.searchTextChange = function(text) {
			console.log('Text changed to ' + text);
		};

		$scope.selectedItemChange = function(item) {
			console.log(item);
			$scope.goTo('/projects/' + item._id + '/edit');
		};

		var createFilterFor = function(query) {
			var lowercaseQuery = angular.lowercase(query);
			return function filterFn(item) {
				//console.log(item);
				var name = angular.lowercase(item.name);
				return (name.indexOf(lowercaseQuery) === 0);
			};
		};

		$scope.collapseAll = function() {
			$scope.$broadcast('collapseAll');
		};

		$scope.expandAll = function() {
			$scope.$broadcast('expandAll');
		};

		function DialogController($scope, $mdDialog) {
			$scope.hide = function() {
				$mdDialog.hide();
			};
			$scope.cancel = function() {
				$mdDialog.cancel();
			};
		}

		$scope.showDescriptionDialog = function(ev, node) {
			$scope.currentNode = node;

			$scope.setCurrentNode(node, function() {
				var newScope = $scope.$new();

				$mdDialog.show({
					controller: DialogController,
					templateUrl: 'modules/projects/views/description.dialog.client.view.html',
					parent: angular.element(document.body),
					targetEvent: ev,
					scope: newScope
				});
			});
		};

		$scope.updateLocalTree = function(scope) {
			var count = $scope.userIndex;
			var currnode = $scope.project.children[0];
			var result;

			$scope.getEstimation(currnode, count, function(res) {
				result = res;
			});
		};

		$scope.getEstimation = function(node, userNum, callback) {
			if (node.nodes.length <= 0) {
				callback(node.estimations[userNum]);
			} else {
				node.estimations[userNum] = null;
				for (var i in node.nodes) {
					$scope.getEstimation(node.nodes[i], userNum, function(result) {
						if (node.estimations[userNum] === null) {
							node.estimations[userNum] = parseInt(result);
						} else {
							node.estimations[userNum] += parseInt(result);
						}
						callback(parseInt(result));
					});
				}
			}
		};

		$scope.currentNode = undefined;

		$scope.setCurrentNode = function(node, callback) {
			$scope.currentNode = node;

			if (callback !== undefined) {
				callback();
			}
		};

		$scope.$on('$locationChangeStart', function(event, newUrl, oldUrl) {
			// Appending dialog to document.body to cover sidenav in docs app
			if (!$scope.confirm) {
				event.preventDefault();
				//console.log(newUrl);
				var confirm = $mdDialog.confirm()
				.parent(angular.element(document.body))
				.title('Are you sure you want to leave this page?')
				.content('All unsaved changes will be lost.')
				.ariaLabel('Yes')
				.ok('Yes')
				.cancel('No')
				.targetEvent(event);
				$mdDialog.show(confirm).then(function() {
					newUrl = newUrl.split('#!');
					$scope.goTo(newUrl[1]);
					$scope.confirm = true;
					//$scope.saveProject();
				}, function() {});
			}
		});
	}
]);
<commit_msg>Certain options now only shown to owner<commit_after>'use strict';

angular.module('projects').controller('ProjectEditController', ['$scope', '$stateParams', '$location', 'Authentication', 'Projects', '$http', '$mdToast', '$mdDialog', '$timeout', '$rootScope',
	function($scope, $stateParams, $location, Authentication, Projects, $http, $mdToast, $mdDialog, $timeout, $rootScope) {
		$scope.members = true;
		$scope.estimated = false;
		$scope.goTo = function(route) {
			$location.path(route);
		};

		$scope.authentication = Authentication;
		$scope.userIndex = -1;
		var project = {'projectId': $stateParams.projectId};
		$http({method:'POST', url:'/project', data: project}).success(function(data) {
			if (data.length !== 0) {
				var tmp = data[0];
				for (var u in tmp.users) {
					if (tmp.users[u] === $scope.authentication.user.username) {
						$scope.userIndex = u;
					}
				}

				if ($scope.userIndex === -1) {
					var toast = $mdToast.simple()
					.content('Not authorised to estimate')
					.action('')
					.highlightAction(false)
					.position($scope.getToastPosition());
					$mdToast.show(toast);
				}
			}
		});

		$scope.rootIsEmpty = function() {
			if ($scope.project.$resolved !== false) {
				if ($scope.project.children.length < 1) {
					return true;
				} else {
					return false;
				}
			}
		};

		$scope.owner = function() {
			if ($scope.project.$resolved !== false) {
				if ($scope.project.owner === $scope.authentication.user.username) {
					return true;
				} else {
					return false;
				}
			}
		};

		$scope.estimator = function() {
			if ($scope.userIndex === -1) {
				return false;
			} else {
				return true;
			}
		};

		$scope.submitEstimation = function() {
			$scope.saveProject();
			$scope.estimated = true;
		};

		$scope.addRootNode = function() {
			// initialise estimations array
			var estimationsArr = [];
			for (var i in $scope.project.users) {
				estimationsArr.push(null);
			}
			$scope.project.children.push({id: 'node', title:'Root Node', nodes: [], collapsed : false, estimations : estimationsArr});
		};

		$scope.update = function() {
			var project = $scope.project;

			project.$update(function() {
				$location.path('projects/' + project._id);
			}, function(errorResponse) {
				$scope.error = errorResponse.data.message;
			});
		};

		$scope.find = function() {
			$scope.projects = Projects.query();
		};

		// Find existing Project
		$scope.findOne = function() {
			$scope.project = Projects.get({
				projectId: $stateParams.projectId
			}, function() {
				if ($scope.project.children[0].estimations[$scope.userIndex] === null) {
					$scope.estimated = false;
				} else {
					$scope.estimated = true;
				}
			});
		};

		$scope.newSubItem = function(scope) {
			// console.log(scope.project.users);
			var nodeData = scope.$modelValue;
			// console.log(nodeData);
			var estimationsArr = [];
			for (var i in scope.project.users) {
				// console.log(i);
				estimationsArr.push(null);
			}
			nodeData.nodes.push({
				id: nodeData.id * 10 + nodeData.nodes.length,
				title: nodeData.title + '.' + (nodeData.nodes.length + 1),
				nodes: [],
				collapsed : false,
				estimations : estimationsArr
			});
		};

		$scope.undoToolTip = function(node, removeNode, newSubItem) {
			//debugger;
			var tree = $.extend(true, [], $scope.project.children);

			removeNode(node);

			var toast = $mdToast.simple()
				.content('Node deleted')
				.action('UNDO')
				.highlightAction(false)
				.position($scope.getToastPosition());
			$mdToast.show(toast).then(function() {
				$scope.project.children = $.extend(true, [], tree);
			});
		};

		$scope.toastPosition = {
			bottom: true,
			top: false,
			left: false,
			right: true
		};

		$scope.getToastPosition = function() {
			return Object.keys($scope.toastPosition)
			.filter(function(pos) { return $scope.toastPosition[pos]; })
			.join(' ');
		};

		$scope.saveProject = function() {
			$scope.project.$update(function(response) {
				$mdToast.show(
					$mdToast.simple()
					.content('Project saved')
					.position($scope.getToastPosition())
					.hideDelay(3000)
				);
			}, function(errorResponse) {
				$scope.error = errorResponse.data.message;
			});
		};
		$scope.querySearch = function(query) {
			//console.log(query);
			var results = query ? $scope.projects.filter(createFilterFor(query)) : $scope.projects, deferred;
			return results;
		};

		$scope.searchTextChange = function(text) {
			console.log('Text changed to ' + text);
		};

		$scope.selectedItemChange = function(item) {
			console.log(item);
			$scope.goTo('/projects/' + item._id + '/edit');
		};

		var createFilterFor = function(query) {
			var lowercaseQuery = angular.lowercase(query);
			return function filterFn(item) {
				//console.log(item);
				var name = angular.lowercase(item.name);
				return (name.indexOf(lowercaseQuery) === 0);
			};
		};

		$scope.collapseAll = function() {
			$scope.$broadcast('collapseAll');
		};

		$scope.expandAll = function() {
			$scope.$broadcast('expandAll');
		};

		function DialogController($scope, $mdDialog) {
			$scope.hide = function() {
				$mdDialog.hide();
			};
			$scope.cancel = function() {
				$mdDialog.cancel();
			};
		}

		$scope.showDescriptionDialog = function(ev, node) {
			$scope.currentNode = node;

			$scope.setCurrentNode(node, function() {
				var newScope = $scope.$new();

				$mdDialog.show({
					controller: DialogController,
					templateUrl: 'modules/projects/views/description.dialog.client.view.html',
					parent: angular.element(document.body),
					targetEvent: ev,
					scope: newScope
				});
			});
		};

		$scope.updateLocalTree = function(scope) {
			var count = $scope.userIndex;
			var currnode = $scope.project.children[0];
			var result;

			$scope.getEstimation(currnode, count, function(res) {
				result = res;
			});
		};

		$scope.getEstimation = function(node, userNum, callback) {
			if (node.nodes.length <= 0) {
				callback(node.estimations[userNum]);
			} else {
				node.estimations[userNum] = null;
				for (var i in node.nodes) {
					$scope.getEstimation(node.nodes[i], userNum, function(result) {
						if (node.estimations[userNum] === null) {
							node.estimations[userNum] = parseInt(result);
						} else {
							node.estimations[userNum] += parseInt(result);
						}
						callback(parseInt(result));
					});
				}
			}
		};

		$scope.currentNode = undefined;

		$scope.setCurrentNode = function(node, callback) {
			$scope.currentNode = node;

			if (callback !== undefined) {
				callback();
			}
		};

		$scope.$on('$locationChangeStart', function(event, newUrl, oldUrl) {
			// Appending dialog to document.body to cover sidenav in docs app
			if (!$scope.confirm) {
				event.preventDefault();
				//console.log(newUrl);
				var confirm = $mdDialog.confirm()
				.parent(angular.element(document.body))
				.title('Are you sure you want to leave this page?')
				.content('All unsaved changes will be lost.')
				.ariaLabel('Yes')
				.ok('Yes')
				.cancel('No')
				.targetEvent(event);
				$mdDialog.show(confirm).then(function() {
					newUrl = newUrl.split('#!');
					$scope.goTo(newUrl[1]);
					$scope.confirm = true;
					//$scope.saveProject();
				}, function() {});
			}
		});
	}
]);
<|endoftext|>


<commit_before>$.namespace("DjangoGoogleMapWidget");

DjangoGoogleMapWidget = DjangoMapWidgetBase.extend({

    initializeMap: function(){
        var location = this.defaultLandingLocation;
        if (this.landingLocation && this.landingLocationName){
            location = this.landingLocation
        }
        this.map = new google.maps.Map(document.getElementById('mw-map'), {
            center: new google.maps.LatLng(location.lat, location.lng),
            scrollwheel: false,
            zoomControlOptions: {
                position: google.maps.ControlPosition.RIGHT
            },
            zoom: this.zoom
        });
        this.addMarkerBtn.on("click", this.handleAddMarkerBtnClick.bind(this));
    },

    addMarkerToMap: function(lat, lng){
        this.removeMarker();
        var marker_position = {lat: lat, lng: lng};
        this.marker = new google.maps.Marker({
            position: marker_position,
            map: this.map,
            draggable: true
        });
        this.marker.addListener("dragend", this.dragMarker.bind(this));
        var bounds = new google.maps.LatLngBounds();
        bounds.extend(this.marker.getPosition());
        this.map.fitBounds(bounds);
        var listener = google.maps.event.addListener(this.map, "bounds_changed", function() {
            if (this.getZoom() > 16) {
                this.setZoom(16)
            }
            google.maps.event.removeListener(listener);
        });
    },

    removeMarker: function(e){
        if (this.marker){
            this.marker.setMap(null);
        }
    },

    dragMarker: function(e){
        this.updateLocationInput(e.latLng.lat(), e.latLng.lng())
    },

    handleAddMarkerBtnClick: function(e){
        if (!this.addMarkerBtn.hasClass("active")){
            this.map.addListener("click", this.handleMapClick.bind(this));
            $(".mw-map").addClass("click");
            this.addMarkerBtn.addClass("active");
        }else{
            $(".mw-map").removeClass("click");
            this.addMarkerBtn.removeClass("active");
        }

    },

    handleMapClick: function(e){
        this.updateLocationInput(e.latLng.lat(), e.latLng.lng())
    }
});

$(document).ready(function(){
    new DjangoGoogleMapWidget({
        locationInput: $("#test"),
        landingLocationName: "Turkey",
        mapApiKey: null,
        mapCenterCoordinates: [],
        mapElement: null,
        landingLocation: null,
        defaultLandingLocation: {
            lat: 37.0625,
            lng: -95.677068
        }, // google default landing location
        googleAddressInput: null,
        coordinatesInputs: null,
        coordinatesOverlayToggleBtn: $("#mw-btn-coordinates"),
        coordinatesOverlayDoneBtn: $("#mw-btn-coordinates-done"),
        myLocationBtn: $("#mw-btn-my-location"),
        coordinatesOverlay: $("#mw-coordinates-overlay"),
        addressAutoCompleteInput: document.getElementById("mw-google-address-input"),
        resetBtn: $("#mw-btn-reset"),
        addMarkerBtn: $("#dw-add-marker"),
        loaderOverlayElem: $("#mw-loader-overlay"),
        zoom: 5,
    });
});<commit_msg>DjangoGoogleMapWidget called in django widget template<commit_after>$.namespace("DjangoGoogleMapWidget");

DjangoGoogleMapWidget = DjangoMapWidgetBase.extend({

    initializeMap: function(){
        var location = this.defaultLandingLocation;
        if (this.landingLocation && this.landingLocationName){
            location = this.landingLocation
        }
        this.map = new google.maps.Map(document.getElementById('mw-map'), {
            center: new google.maps.LatLng(location.lat, location.lng),
            scrollwheel: false,
            zoomControlOptions: {
                position: google.maps.ControlPosition.RIGHT
            },
            zoom: this.zoom
        });
        this.addMarkerBtn.on("click", this.handleAddMarkerBtnClick.bind(this));
    },

    addMarkerToMap: function(lat, lng){
        this.removeMarker();
        var marker_position = {lat: lat, lng: lng};
        this.marker = new google.maps.Marker({
            position: marker_position,
            map: this.map,
            draggable: true
        });
        this.marker.addListener("dragend", this.dragMarker.bind(this));
        var bounds = new google.maps.LatLngBounds();
        bounds.extend(this.marker.getPosition());
        this.map.fitBounds(bounds);
        var listener = google.maps.event.addListener(this.map, "bounds_changed", function() {
            if (this.getZoom() > 16) {
                this.setZoom(16)
            }
            google.maps.event.removeListener(listener);
        });
    },

    removeMarker: function(e){
        if (this.marker){
            this.marker.setMap(null);
        }
    },

    dragMarker: function(e){
        this.updateLocationInput(e.latLng.lat(), e.latLng.lng())
    },

    handleAddMarkerBtnClick: function(e){
        if (!this.addMarkerBtn.hasClass("active")){
            this.map.addListener("click", this.handleMapClick.bind(this));
            $(".mw-map").addClass("click");
            this.addMarkerBtn.addClass("active");
        }else{
            $(".mw-map").removeClass("click");
            this.addMarkerBtn.removeClass("active");
        }

    },

    handleMapClick: function(e){
        this.updateLocationInput(e.latLng.lat(), e.latLng.lng())
    }
});

<|endoftext|>


<commit_before>/**
 * @file
 * Git deployment for Aquifer.
 */

/* globals require, Aquifer, AquiferGitConfig, module */

module.exports = (Aquifer, AquiferGitConfig) => {

  'use strict';

  const AquiferGit = () => {};
  const _ = require('lodash');
  const mktemp = require('mktemp');
  const path = require('path');
  const fs = require('fs-extra');

  /**
   * Informs Aquifer of what this deployment script does.
   * @returns {object} details about this deployment script.
   */
  AquiferGit.commands = () => {
    return {
      'deploy-git': {
        description: 'Deploys the site to a remote Git repository.',
        options: {
          remote: {
            name: '-r, --remote <remote>',
            description: 'The repository to deploy to.'
          },
          branch: {
            name: '-b, --branch <branch>',
            description: 'The branch to deploy to.'
          },
          message: {
            name: '-m, --message <message>',
            default: 'Deployment from source repository.',
            description: 'The message to use with the deployment commit.'
          },
          folder: {
            name: '-f, --folder <folder_name>',
            default: false,
            description: 'Subfolder in remote repository that should hold the build.'
          },
          name: {
            name: '-n, --name <name>',
            default: false,
            description: 'Name to use for the deployment commit signature.'
          },
          email: {
            name: '-a, --email <email>',
            default: false,
            description: 'Email to use for the deployment commit signature.'
          }
        }
      }
    };
  };

  /**
   * Run when user runs commands within this extension.
   * @param {string} command string representing the name of the command defined in AquiferGit.commands that should run.
   * @param {object} commandOptions options passed from the command.
   * @param {function} callback function that is called when there is an error message to send.
   * @returns {undefined} null.
   */
  AquiferGit.run = (command, commandOptions, callback) => {
    if (command !== 'deploy-git') {
      callback('Invalid command.');
      return;
    }

    let options = {
      deploymentFiles: [],
      excludeLinks: ['sites/default/files'],
      addLinks: [],
      delPatterns: ['*', '!.git']
    };
    let requiredOptions = ['remote', 'branch', 'message'];
    let optionsMissing  = false;
    let build;
    let destPath;
    let run = new Aquifer.api.run(Aquifer);

    // Parse options and make sure they all exist.
    _.assign(options, AquiferGitConfig, commandOptions, (lastValue, nextValue, name) => {
      return nextValue ? nextValue : lastValue;
    });

    requiredOptions.forEach((name) => {
      if (!options[name]) {
        callback('"' + name + '" option is missing. Cannot deploy.');
        optionsMissing = true;
      }
    });

    if (optionsMissing) {
      return;
    }

    // Create the destination directory and initiate the promise chain.
    mktemp.createDir('aquifer-git-XXXXXXX')

    // Clone the repository.
    .then((destPath_) => {
      Aquifer.console.log('Cloning the repository into ' + destPath_ + '...', 'status');
      destPath = destPath_;
      return run.invoke('git clone ' + options.remote + ' ' + destPath);
    })

    // Prepare the repository for the build.
    .then(() => {
      return run.invoke('git -C ' + path.join(Aquifer.projectDir, destPath) + ' checkout ' + options.branch)
        .then(() => {
          Aquifer.console.log('Checking out branch: ' + options.branch + '...', 'status');
        })
        .catch(() => {
          Aquifer.console.log('Creating new branch: ' + options.branch + '...', 'status');
          return run.invoke('git -C ' + path.join(Aquifer.projectDir, destPath) + ' checkout -b ' + options.branch);
        });
    })

    // Build the site.
    .then(() => {
      Aquifer.console.log('Building the site...', 'status');

      let buildOptions = {
        symlink: false,
        delPatterns: options.delPatterns,
        excludeLinks: options.excludeLinks,
        addLinks: options.addLinks
      };

      // Calculate build path.
      let buildPath = destPath;

      // If a folder is specified, add it to the build path.
      if (options.folder) {
        buildPath = path.join(buildPath, options.folder);
      }

      // Create instance of build object.
      build = new Aquifer.api.build(Aquifer);
      return build.create(buildPath, buildOptions);
    })

    // Copy over additional deployment files.
    .then(() => {
      Aquifer.console.log('Copying deployment files...', 'status');
      options.deploymentFiles.forEach(function (link) {
        let src = path.join(Aquifer.projectDir, link.src);
        let dest = path.join(destPath, link.dest);
        fs.removeSync(dest);
        fs.copySync(src, dest, {clobber: true});
      });
    })

    // Add all files to the index.
    .then(() => {
      Aquifer.console.log('Clearing the index...', 'status');
      console.log(path.join(Aquifer.projectDir, destPath));
      fs.removeSync(path.join(Aquifer.projectDir, destPath, '.git/index'));
    })

    // Add all files to the index.
    .then(() => {
      Aquifer.console.log('Adding all files to the index...', 'status');
      return run.invoke('git -C ' + path.join(Aquifer.projectDir, destPath) + ' add -A');
    })

    // Commit changes.
    .then(() => {
      Aquifer.console.log('Committing changes...', 'status');

      // Add author info to commit if we have it in config options.
      if (options.name !== 'undefined') {
        options.email = options.email || '';
        return run.invoke('git -C ' + path.join(Aquifer.projectDir, destPath) + ' commit -m "' + options.message + '" --author "' + options.name + '<' + options.email + '>"');
      }
      else {
        return run.invoke('git -C ' + path.join(Aquifer.projectDir, destPath) + ' commit -m "' + options.message + '"');
      }
    })

    // Push to origin.
    .then(() => {
      Aquifer.console.log('Pushing branch: ' + options.branch + '...', 'status');
      return run.invoke('git -C ' + path.join(Aquifer.projectDir, destPath) + ' push origin ' + options.branch);
    })

    // Remove the destination path.
    .then(() => {
      Aquifer.console.log('Removing the ' + destPath + ' directory...', 'status');
      fs.removeSync(destPath);
    })

    // Success!
    .then(() => {
      Aquifer.console.log('The site has been successfully deployed!', 'success');
    })

    // Catch any errors.
    .catch((err) => {
      callback(err);
    });
  };

  return AquiferGit;
};
<commit_msg>Handle empty name string properly.<commit_after>/**
 * @file
 * Git deployment for Aquifer.
 */

/* globals require, Aquifer, AquiferGitConfig, module */

module.exports = (Aquifer, AquiferGitConfig) => {

  'use strict';

  const AquiferGit = () => {};
  const _ = require('lodash');
  const mktemp = require('mktemp');
  const path = require('path');
  const fs = require('fs-extra');

  /**
   * Informs Aquifer of what this deployment script does.
   * @returns {object} details about this deployment script.
   */
  AquiferGit.commands = () => {
    return {
      'deploy-git': {
        description: 'Deploys the site to a remote Git repository.',
        options: {
          remote: {
            name: '-r, --remote <remote>',
            description: 'The repository to deploy to.'
          },
          branch: {
            name: '-b, --branch <branch>',
            description: 'The branch to deploy to.'
          },
          message: {
            name: '-m, --message <message>',
            default: 'Deployment from source repository.',
            description: 'The message to use with the deployment commit.'
          },
          folder: {
            name: '-f, --folder <folder_name>',
            default: false,
            description: 'Subfolder in remote repository that should hold the build.'
          },
          name: {
            name: '-n, --name <name>',
            default: false,
            description: 'Name to use for the deployment commit signature.'
          },
          email: {
            name: '-a, --email <email>',
            default: false,
            description: 'Email to use for the deployment commit signature.'
          }
        }
      }
    };
  };

  /**
   * Run when user runs commands within this extension.
   * @param {string} command string representing the name of the command defined in AquiferGit.commands that should run.
   * @param {object} commandOptions options passed from the command.
   * @param {function} callback function that is called when there is an error message to send.
   * @returns {undefined} null.
   */
  AquiferGit.run = (command, commandOptions, callback) => {
    if (command !== 'deploy-git') {
      callback('Invalid command.');
      return;
    }

    let options = {
      deploymentFiles: [],
      excludeLinks: ['sites/default/files'],
      addLinks: [],
      delPatterns: ['*', '!.git']
    };
    let requiredOptions = ['remote', 'branch', 'message'];
    let optionsMissing  = false;
    let build;
    let destPath;
    let run = new Aquifer.api.run(Aquifer);

    // Parse options and make sure they all exist.
    _.assign(options, AquiferGitConfig, commandOptions, (lastValue, nextValue, name) => {
      return nextValue ? nextValue : lastValue;
    });

    requiredOptions.forEach((name) => {
      if (!options[name]) {
        callback('"' + name + '" option is missing. Cannot deploy.');
        optionsMissing = true;
      }
    });

    if (optionsMissing) {
      return;
    }

    // Create the destination directory and initiate the promise chain.
    mktemp.createDir('aquifer-git-XXXXXXX')

    // Clone the repository.
    .then((destPath_) => {
      Aquifer.console.log('Cloning the repository into ' + destPath_ + '...', 'status');
      destPath = destPath_;
      return run.invoke('git clone ' + options.remote + ' ' + destPath);
    })

    // Prepare the repository for the build.
    .then(() => {
      return run.invoke('git -C ' + path.join(Aquifer.projectDir, destPath) + ' checkout ' + options.branch)
        .then(() => {
          Aquifer.console.log('Checking out branch: ' + options.branch + '...', 'status');
        })
        .catch(() => {
          Aquifer.console.log('Creating new branch: ' + options.branch + '...', 'status');
          return run.invoke('git -C ' + path.join(Aquifer.projectDir, destPath) + ' checkout -b ' + options.branch);
        });
    })

    // Build the site.
    .then(() => {
      Aquifer.console.log('Building the site...', 'status');

      let buildOptions = {
        symlink: false,
        delPatterns: options.delPatterns,
        excludeLinks: options.excludeLinks,
        addLinks: options.addLinks
      };

      // Calculate build path.
      let buildPath = destPath;

      // If a folder is specified, add it to the build path.
      if (options.folder) {
        buildPath = path.join(buildPath, options.folder);
      }

      // Create instance of build object.
      build = new Aquifer.api.build(Aquifer);
      return build.create(buildPath, buildOptions);
    })

    // Copy over additional deployment files.
    .then(() => {
      Aquifer.console.log('Copying deployment files...', 'status');
      options.deploymentFiles.forEach(function (link) {
        let src = path.join(Aquifer.projectDir, link.src);
        let dest = path.join(destPath, link.dest);
        fs.removeSync(dest);
        fs.copySync(src, dest, {clobber: true});
      });
    })

    // Add all files to the index.
    .then(() => {
      Aquifer.console.log('Clearing the index...', 'status');
      console.log(path.join(Aquifer.projectDir, destPath));
      fs.removeSync(path.join(Aquifer.projectDir, destPath, '.git/index'));
    })

    // Add all files to the index.
    .then(() => {
      Aquifer.console.log('Adding all files to the index...', 'status');
      return run.invoke('git -C ' + path.join(Aquifer.projectDir, destPath) + ' add -A');
    })

    // Commit changes.
    .then(() => {
      Aquifer.console.log('Committing changes...', 'status');

      // Add author info to commit if we have it in config options.
      if (options.name) {
        options.email = options.email || '';
        return run.invoke('git -C ' + path.join(Aquifer.projectDir, destPath) + ' commit -m "' + options.message + '" --author "' + options.name + '<' + options.email + '>"');
      }
      else {
        return run.invoke('git -C ' + path.join(Aquifer.projectDir, destPath) + ' commit -m "' + options.message + '"');
      }
    })

    // Push to origin.
    .then(() => {
      Aquifer.console.log('Pushing branch: ' + options.branch + '...', 'status');
      return run.invoke('git -C ' + path.join(Aquifer.projectDir, destPath) + ' push origin ' + options.branch);
    })

    // Remove the destination path.
    .then(() => {
      Aquifer.console.log('Removing the ' + destPath + ' directory...', 'status');
      fs.removeSync(destPath);
    })

    // Success!
    .then(() => {
      Aquifer.console.log('The site has been successfully deployed!', 'success');
    })

    // Catch any errors.
    .catch((err) => {
      callback(err);
    });
  };

  return AquiferGit;
};
<|endoftext|>


<commit_before><script>
/*
===================================
| DATALAYER ARCHITECTURE: SHOPIFY |
-----------------------------------

DEFINITION:
A data layer helps you collect more accurate analytics data, that in turn allows you to better understand what potential buyers are doing on your website and where you can make improvements. It also reduces the time to implement marketing tags on a website, and reduces the need for IT involvement, leaving them to get on with implementing new features and fixing bugs.

RESOURCES:
http://www.datalayerdoctor.com/a-gentle-introduction-to-the-data-layer-for-digital-marketers/
http://www.simoahava.com/analytics/data-layer/

AUTHORS:
Mechelle Warneke = [{
Email: mechellewarneke@gmail.com,
Website: mechellewarneke.com,
BVACCEL: [{
    Email: mechelle@bvaccel.com,
    Position: XO Strategist | Technical Web Analyst
}]
}];

EXTERNAL DEPENDENCIES:
* jQuery Cookie Plugin v1.4.1 - https://github.com/carhartl/jquery-cookie

DataLayer Architecture: Shopify v1.3.1
COPYRIGHT 2016
LICENSES: MIT ( https://opensource.org/licenses/MIT )
*/

/*
========================
| DYNAMIC DEPENDENCIES |
------------------------

[ IMPORTANT ]: Review options and make any necessary changes. */

/* ------- CONSOLE DATA [ UNDER CONSTRUCTION ] ------- */
// If you want all data to be logged to the console for reference set to true.

// var consoleLog = true;

/* =======================
| PREREQUISITE LIBRARIES |
--------------------------

Load jQuery Cookie Library
--------------------------
jQuery Cookie Plugin v1.4.1
https://github.com/carhartl/jquery-cookie

Copyright 2006, 2014 Klaus Hartl
Released under the MIT license
*/

(function (factory) {
  if (typeof define === 'function' && define.amd) {
        // AMD (Register as an anonymous module)
        define(['jquery'], factory);
      } else if (typeof exports === 'object') {
        // Node/CommonJS
        module.exports = factory(require('jquery'));
      } else {
        // Browser globals
        factory(jQuery);
      }
    }(function ($) {

      var pluses = /\+/g;

      function encode(s) {
        return config.raw ? s : encodeURIComponent(s);
      }

      function decode(s) {
        return config.raw ? s : decodeURIComponent(s);
      }

      function stringifyCookieValue(value) {
        return encode(config.json ? JSON.stringify(value) : String(value));
      }

      function parseCookieValue(s) {
        if (s.indexOf('"') === 0) {
            // This is a quoted cookie as according to RFC2068, unescape...
            s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
          }

          try {
            // Replace server-side written pluses with spaces.
            // If we can't decode the cookie, ignore it, it's unusable.
            // If we can't parse the cookie, ignore it, it's unusable.
            s = decodeURIComponent(s.replace(pluses, ' '));
            return config.json ? JSON.parse(s) : s;
          } catch(e) {}
        }

        function read(s, converter) {
          var value = config.raw ? s : parseCookieValue(s);
          return $.isFunction(converter) ? converter(value) : value;
        }

        var config = $.cookie = function (key, value, options) {

        // Write

        if (arguments.length > 1 && !$.isFunction(value)) {
          options = $.extend({}, config.defaults, options);

          if (typeof options.expires === 'number') {
            var days = options.expires, t = options.expires = new Date();
            t.setMilliseconds(t.getMilliseconds() + days * 864e+5);
          }

          return (document.cookie = [
            encode(key), '=', stringifyCookieValue(value),
                options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
                options.path    ? '; path=' + options.path : '',
                options.domain  ? '; domain=' + options.domain : '',
                options.secure  ? '; secure' : ''
                ].join(''));
        }

        // Read

        var result = key ? undefined : {},
            // To prevent the for loop in the first place assign an empty array
            // in case there are no cookies at all. Also prevents odd result when
            // calling $.cookie().
            cookies = document.cookie ? document.cookie.split('; ') : [],
            i = 0,
            l = cookies.length;

            for (; i < l; i++) {
              var parts = cookies[i].split('='),
              name = decode(parts.shift()),
              cookie = parts.join('=');

              if (key === name) {
                // If second argument (value) is a function it's a converter...
                result = read(cookie, value);
                break;
              }

            // Prevent storing a cookie that we couldn't decode.
            if (!key && (cookie = read(cookie)) !== undefined) {
              result[name] = cookie;
            }
          }

          return result;
        };

        config.defaults = {};

        $.removeCookie = function (key, options) {
        // Must not alter options, thus extending a fresh object...
        $.cookie(key, '', $.extend({}, options, { expires: -1 }));
        return !$.cookie(key);
      };

    }));

console.log("----------------------\nBEGIN DATALAYER BUILD\nTHEME PAGES\n----------------------");
window.dataLayer = window.dataLayer || []
console.log('Page Template = {{template}}');
var template = '{{template}}';

/* Landing Page Cookie
-----------------------
1. Detect if user just landed on the site
2. Only fires if Page Title matches website */

$.cookie.raw = true;

if( $.cookie('landingPage') === undefined || $.cookie('landingPage').length === 0 ){

  $.cookie('landingPage', unescape);
  $.removeCookie('landingPage',{ path: '/' });
  $.cookie('landingPage', 'landed',{ path: '/' });
  var landingPage = true;
  console.log("Landing Page = True");

}else{

  $.cookie('landingPage', unescape);
  $.removeCookie('landingPage',{ path: '/' });
  $.cookie('landingPage', 'refresh',{ path: '/' });
  console.log("Landing Page = False");

}

/* Log State Cookie
------------------- */

{% if customer %}
var logState = "Logged In";
{% endif %}

if( typeof logState == "undefined" ){
  var logState = "Logged Out";
  $.cookie('logState', unescape);
  $.removeCookie('logState',{ path: '/' });
  $.cookie('logState', 'loggedOut',{ path: '/' })
  console.log("Log State = Logged Out");
}

if( logState === "Logged In"){
  if( $.cookie('logState') === "loggedOut" || $.cookie('logState') === undefined ){

    $.cookie('logState', unescape);
    $.removeCookie('logState',{ path: '/' });
    $.cookie('logState', 'firstLog',{ path: '/' });
    console.log("Log State = Logged In");

  }else if( $.cookie("logState") === "firstLog"  ){

    $.cookie('logState', unescape);
    $.removeCookie('logState',{ path: '/' });
    $.cookie('logState', 'refresh',{ path: '/' });
    console.log("Log State = Logged In");

  }else{
    console.log("Log State = Logged In");
  }
}

if( $.cookie("logState") === "firstLog"  ){
  var firstLog = "True";
}else{
  var firstLog = "False";
}
console.log("First Log = "+firstLog);

    // TIMESTAMP
    var ts = Date.now();
    console.log("Timestamp = "+ts);

/* ==========
| DATALAYERS |
----------- */

/* DATALAYER: Landing Page
--------------------------
Fires any time a user first lands on the site. */

if( $.cookie("landingPage") === "landed"  ){
  dataLayer.push({
    'pageType':'Landing Page',
    'event':'Landing Page'
  });
}

/* DATALAYER: Log State
-----------------------
1. Determine if user is logged in or not.
2. Return User specific data. */

dataLayer.push({
  {% if shop.customer_accounts_enabled %}
  {% if customer %}
  'userId': '{{customer.id}}',
  'customerEmail': '{{customer.email}}',
  'logState': "Logged In",
  {% else %}
  'logState': "Logged Out",
  {% endif %}
  {% endif %}
  'firstLog': firstLog,
  'customerEmail': '{{customer.email}}',
  'timestamp': ts
},{'event':'Log State'});

/* DATALAYER: Confirmation
-------------------------- */

dataLayer.push({
  'transactionId': '{{checkout.order_id}}',
  'transactionNumber': '{{checkout.order_number}}',
  'transactionAffiliation': '{{shop.name}}',
  'transactionTotal': '{{checkout.total_price |  money_without_currency}}',
  'transactionTax': '{{checkout.total_price |  money_without_currency}}',
  'transactionShipping': '{{checkout.shipping_price |  money_without_currency}}',

  {% for discount in checkout.discounts %}
  'promoCode':'{{discount.code}}',
  'discount': '{{discount.amount | money_without_currency}}',
  {% endfor %}

  'transactionProducts': [

  {% for line_item in checkout.line_items %}
  {
    'id': '{{line_item.product_id}}',
    'sku': '{{line_item.sku}}',
    'variantId': '{{line_item.variant_id}}',
    'name': '{{line_item.title}}',
    'category': '{{ collection.title }}',
    'price': '{{line_item.price | money_without_currency}}',
    'quantity': '{{line_item.quantity}}'
  },
  {% endfor %}

  ]},{
    'pageType':'Confirmation',
    'event':'Confirmation'
  });

/* DATALAYER: All Pages
-----------------------
Fire all pages trigger after all additional dataLayers have loaded. */

dataLayer.push({
  'event':'All Pages'
});
</script>
<commit_msg>Delete dataLayer-confirmation.js<commit_after><|endoftext|>