0

I'm attempting to write some code that runs over an array of lessons within the object below and return the percentage of completed lessons (ones marked as completed: true).

When I console.log the outcome it just shows as [Function completion], rather than a number as expected. Where am I going wrong?

For reference I'm using JS with React Native, but this should only concern JS if I'm correct?

WorkoutCategoryData.js

export default [
  {
    title: "Title 1",
    subtitle: "Subtitle 1",
    lessonCount: 4,
    lessons: [
      {
        title: "Lesson Name 1",
        completed: true
      },
      {
        title: "Lesson Name 2",
        completed: true
      },
      {
        title: "Lesson Name 3",
        completed: false
      },
      {
        title: "Lesson Name 4",
        completed: false
      },
    ],
    completion: function() {
      this.findCompletion();
    }
  },
  {
    title: "Title 2",
    subtitle: "Subtitle 2",
    lessonCount: 3,
    lessons: [
      {
        title: "Lesson Name 5",
        completed: true
      },
      {
        title: "Lesson Name 6",
        completed: true
      },
      {
        title: "Lesson Name 7",
        completed: true
      }
    ],
    completion: function() {
      this.findCompletion();
    }
  }
];

function findCompletion(lessons) {
  let lessonCompletion = 1;
  let completedLessons = lessons.filter(lesson => lesson.completed === true)
    .length;
  let totalLessons = lessons.length;
  lessonCompletion = (completedLessons / totalLessons) * 100;
  return lessonCompletion;
}

Workouts.js

import WorkoutCategoryData from "./data/WorkoutCategoryData";


 {WorkoutCategoryData.map(cat => {
            let currentCompletion = cat.completion;
            console.log(currentCompletion);
            return (
              <View style={styles.workoutContainer} key={cat.title}>
                <View style={styles.workoutProgress}>
                  <AnimatedCircularProgress
                    size={50}
                    width={5}
                    rotation={0}
                    fill={cat.completion}
                    tintColor={Colors.primary}
                    backgroundColor="#dddddd"
                  />
                </View>
                <View style={styles.workoutText}>
                  <Text style={styles.workoutTitle}>{cat.title}</Text>
                  {cat.subtitle ? (
                    <Text style={styles.workoutSubtitle}>{cat.subtitle}</Text>
                  ) : null}
                </View>
              </View>
            );
          })}

I'm hoping to get an Integer number I can then pass in as a prop in a component for a progress indicator. Any help would be very much appreciated, thanks in advance!

2
  • Where’s the console.log? And the call to the completions? Commented Oct 7, 2019 at 13:56
  • added that to the code now, thanks! Commented Oct 7, 2019 at 14:02

3 Answers 3

1

Repeating completion like that is a bad sign – mixing data and common implementation and so on. Consider giving your objects a type (name it what it actually represents, like Course, not Thing):

class Thing {
  constructor(data) {
    this.title = data.title;
    this.subtitle = data.subtitle;
    this.lessonCount = data.lessonCount;
    this.lessons = data.lessons;
  }

  getCompletion() {
    let completedLessons = this.lessons.filter(lesson => lesson.completed).length;
    let totalLessons = this.lessons.length;
    return (completedLessons / totalLessons) * 100;
  }
}

export default [
  {
    title: "Title 1",
    subtitle: "Subtitle 1",
    lessonCount: 4,
    lessons: [
      {
        title: "Lesson Name 1",
        completed: true
      },
      {
        title: "Lesson Name 2",
        completed: true
      },
      {
        title: "Lesson Name 3",
        completed: false
      },
      {
        title: "Lesson Name 4",
        completed: false
      },
    ],
  },
  {
    title: "Title 2",
    subtitle: "Subtitle 2",
    lessonCount: 3,
    lessons: [
      {
        title: "Lesson Name 5",
        completed: true
      },
      {
        title: "Lesson Name 6",
        completed: true
      },
      {
        title: "Lesson Name 7",
        completed: true
      },
    ],
  },
].map(data => new Thing(data));

Then you use it with fill={cat.getCompletion()}. Since it’s a function, it needs to be called.

(Also, do you really need lessonCount, considering it appears to be lessons.length?)

Another option that makes sense is not requiring this function to be a method:

let getCompletion = ({lessons}) => {
  let completedLessons = lessons.filter(lesson => lesson.completed).length;
  let totalLessons = lessons.length;
  return (completedLessons / totalLessons) * 100;
};
<AnimatedCircularProgress
  size={50}
  width={5}
  rotation={0}
  fill={getCompletion(cat)}
  tintColor={Colors.primary}
  backgroundColor="#dddddd"
/>
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for this, I'll give it a go. And no lessonCount is going to be replaced like this also, its just for initial implementation.
0

when you call completion, you might want to return the result.

completion: function() {
      return this.findCompletion();
    }

Comments

0

Like @David Koe said you need to return. However you are passing a reference to the function instead of invoking it - Please try let currentCompletion = cat.completion(); in Workouts.js and if the rest of your code is working as you expect it should return the result.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.